Commit | Line | Data |
---|---|---|
3ce72726 OW |
1 | /* |
2 | * | |
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | |
733ba91c | 4 | * Copyright (c) 2003-2012, Intel Corporation. |
3ce72726 OW |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms and conditions of the GNU General Public License, | |
8 | * version 2, as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <linux/pci.h> | |
4f3afe1d | 18 | #include <linux/mei.h> |
47a73801 TW |
19 | |
20 | #include "mei_dev.h" | |
9dc64d6a | 21 | #include "hw-me.h" |
3ce72726 | 22 | |
3a65dd4e TW |
23 | /** |
24 | * mei_reg_read - Reads 32bit data from the mei device | |
25 | * | |
26 | * @dev: the device structure | |
27 | * @offset: offset from which to read the data | |
28 | * | |
29 | * returns register value (u32) | |
30 | */ | |
31 | static inline u32 mei_reg_read(const struct mei_device *dev, | |
32 | unsigned long offset) | |
33 | { | |
34 | return ioread32(dev->mem_addr + offset); | |
35 | } | |
36 | ||
37 | ||
38 | /** | |
39 | * mei_reg_write - Writes 32bit data to the mei device | |
40 | * | |
41 | * @dev: the device structure | |
42 | * @offset: offset from which to write the data | |
43 | * @value: register value to write (u32) | |
44 | */ | |
45 | static inline void mei_reg_write(const struct mei_device *dev, | |
46 | unsigned long offset, u32 value) | |
47 | { | |
48 | iowrite32(value, dev->mem_addr + offset); | |
49 | } | |
3ce72726 | 50 | |
3a65dd4e | 51 | /** |
d025284d TW |
52 | * mei_mecbrw_read - Reads 32bit data from ME circular buffer |
53 | * read window register | |
3a65dd4e TW |
54 | * |
55 | * @dev: the device structure | |
56 | * | |
d025284d | 57 | * returns ME_CB_RW register value (u32) |
3a65dd4e | 58 | */ |
3a65dd4e TW |
59 | u32 mei_mecbrw_read(const struct mei_device *dev) |
60 | { | |
61 | return mei_reg_read(dev, ME_CB_RW); | |
62 | } | |
63 | /** | |
64 | * mei_mecsr_read - Reads 32bit data from the ME CSR | |
65 | * | |
66 | * @dev: the device structure | |
67 | * | |
68 | * returns ME_CSR_HA register value (u32) | |
69 | */ | |
70 | u32 mei_mecsr_read(const struct mei_device *dev) | |
71 | { | |
72 | return mei_reg_read(dev, ME_CSR_HA); | |
73 | } | |
3ce72726 OW |
74 | |
75 | /** | |
d025284d TW |
76 | * mei_hcsr_read - Reads 32bit data from the host CSR |
77 | * | |
78 | * @dev: the device structure | |
79 | * | |
80 | * returns H_CSR register value (u32) | |
81 | */ | |
82 | u32 mei_hcsr_read(const struct mei_device *dev) | |
83 | { | |
84 | return mei_reg_read(dev, H_CSR); | |
85 | } | |
86 | ||
87 | /** | |
88 | * mei_hcsr_set - writes H_CSR register to the mei device, | |
3ce72726 OW |
89 | * and ignores the H_IS bit for it is write-one-to-zero. |
90 | * | |
91 | * @dev: the device structure | |
92 | */ | |
88eb99f2 | 93 | static inline void mei_hcsr_set(struct mei_device *dev, u32 hcsr) |
3ce72726 | 94 | { |
88eb99f2 TW |
95 | hcsr &= ~H_IS; |
96 | mei_reg_write(dev, H_CSR, hcsr); | |
3ce72726 OW |
97 | } |
98 | ||
99 | /** | |
d025284d | 100 | * mei_clear_interrupts - clear and stop interrupts |
3a65dd4e TW |
101 | * |
102 | * @dev: the device structure | |
103 | */ | |
104 | void mei_clear_interrupts(struct mei_device *dev) | |
105 | { | |
9ea73ddd TW |
106 | u32 hcsr = mei_hcsr_read(dev); |
107 | if ((hcsr & H_IS) == H_IS) | |
108 | mei_reg_write(dev, H_CSR, hcsr); | |
3a65dd4e TW |
109 | } |
110 | ||
111 | /** | |
112 | * mei_enable_interrupts - enables mei device interrupts | |
3ce72726 OW |
113 | * |
114 | * @dev: the device structure | |
115 | */ | |
116 | void mei_enable_interrupts(struct mei_device *dev) | |
117 | { | |
9ea73ddd TW |
118 | u32 hcsr = mei_hcsr_read(dev); |
119 | hcsr |= H_IE; | |
88eb99f2 | 120 | mei_hcsr_set(dev, hcsr); |
3ce72726 OW |
121 | } |
122 | ||
123 | /** | |
3a65dd4e | 124 | * mei_disable_interrupts - disables mei device interrupts |
3ce72726 OW |
125 | * |
126 | * @dev: the device structure | |
127 | */ | |
128 | void mei_disable_interrupts(struct mei_device *dev) | |
129 | { | |
9ea73ddd TW |
130 | u32 hcsr = mei_hcsr_read(dev); |
131 | hcsr &= ~H_IE; | |
88eb99f2 | 132 | mei_hcsr_set(dev, hcsr); |
3ce72726 OW |
133 | } |
134 | ||
adfba322 TW |
135 | /** |
136 | * mei_hw_reset - resets fw via mei csr register. | |
137 | * | |
138 | * @dev: the device structure | |
139 | * @interrupts_enabled: if interrupt should be enabled after reset. | |
140 | */ | |
141 | void mei_hw_reset(struct mei_device *dev, bool intr_enable) | |
142 | { | |
143 | u32 hcsr = mei_hcsr_read(dev); | |
144 | ||
145 | dev_dbg(&dev->pdev->dev, "before reset HCSR = 0x%08x.\n", hcsr); | |
146 | ||
147 | hcsr |= (H_RST | H_IG); | |
148 | ||
149 | if (intr_enable) | |
150 | hcsr |= H_IE; | |
151 | else | |
152 | hcsr &= ~H_IE; | |
153 | ||
88eb99f2 | 154 | mei_hcsr_set(dev, hcsr); |
adfba322 | 155 | |
88eb99f2 | 156 | hcsr = mei_hcsr_read(dev) | H_IG; |
adfba322 | 157 | hcsr &= ~H_RST; |
adfba322 | 158 | |
88eb99f2 | 159 | mei_hcsr_set(dev, hcsr); |
adfba322 TW |
160 | |
161 | hcsr = mei_hcsr_read(dev); | |
162 | ||
163 | dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr); | |
164 | } | |
165 | ||
115ba28c TW |
166 | /** |
167 | * mei_host_set_ready - enable device | |
168 | * | |
169 | * @dev - mei device | |
170 | * returns bool | |
171 | */ | |
172 | ||
173 | void mei_host_set_ready(struct mei_device *dev) | |
174 | { | |
175 | dev->host_hw_state |= H_IE | H_IG | H_RDY; | |
88eb99f2 | 176 | mei_hcsr_set(dev, dev->host_hw_state); |
115ba28c TW |
177 | } |
178 | /** | |
179 | * mei_host_is_ready - check whether the host has turned ready | |
180 | * | |
181 | * @dev - mei device | |
182 | * returns bool | |
183 | */ | |
184 | bool mei_host_is_ready(struct mei_device *dev) | |
185 | { | |
186 | return (dev->host_hw_state & H_RDY) == H_RDY; | |
187 | } | |
188 | ||
189 | /** | |
190 | * mei_me_is_ready - check whether the me has turned ready | |
191 | * | |
192 | * @dev - mei device | |
193 | * returns bool | |
194 | */ | |
195 | bool mei_me_is_ready(struct mei_device *dev) | |
196 | { | |
197 | return (dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA; | |
198 | } | |
3a65dd4e TW |
199 | |
200 | /** | |
201 | * mei_interrupt_quick_handler - The ISR of the MEI device | |
202 | * | |
203 | * @irq: The irq number | |
204 | * @dev_id: pointer to the device structure | |
205 | * | |
206 | * returns irqreturn_t | |
207 | */ | |
208 | irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id) | |
209 | { | |
210 | struct mei_device *dev = (struct mei_device *) dev_id; | |
211 | u32 csr_reg = mei_hcsr_read(dev); | |
212 | ||
213 | if ((csr_reg & H_IS) != H_IS) | |
214 | return IRQ_NONE; | |
215 | ||
216 | /* clear H_IS bit in H_CSR */ | |
217 | mei_reg_write(dev, H_CSR, csr_reg); | |
218 | ||
219 | return IRQ_WAKE_THREAD; | |
220 | } | |
221 | ||
3ce72726 | 222 | /** |
726917f0 | 223 | * mei_hbuf_filled_slots - gets number of device filled buffer slots |
3ce72726 OW |
224 | * |
225 | * @device: the device structure | |
226 | * | |
227 | * returns number of filled slots | |
228 | */ | |
726917f0 | 229 | static unsigned char mei_hbuf_filled_slots(struct mei_device *dev) |
3ce72726 OW |
230 | { |
231 | char read_ptr, write_ptr; | |
232 | ||
726917f0 TW |
233 | dev->host_hw_state = mei_hcsr_read(dev); |
234 | ||
3ce72726 OW |
235 | read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8); |
236 | write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16); | |
237 | ||
238 | return (unsigned char) (write_ptr - read_ptr); | |
239 | } | |
240 | ||
241 | /** | |
726917f0 | 242 | * mei_hbuf_is_empty - checks if host buffer is empty. |
3ce72726 OW |
243 | * |
244 | * @dev: the device structure | |
245 | * | |
726917f0 | 246 | * returns true if empty, false - otherwise. |
3ce72726 | 247 | */ |
726917f0 | 248 | bool mei_hbuf_is_empty(struct mei_device *dev) |
3ce72726 | 249 | { |
726917f0 | 250 | return mei_hbuf_filled_slots(dev) == 0; |
3ce72726 OW |
251 | } |
252 | ||
253 | /** | |
726917f0 | 254 | * mei_hbuf_empty_slots - counts write empty slots. |
3ce72726 OW |
255 | * |
256 | * @dev: the device structure | |
257 | * | |
258 | * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count | |
259 | */ | |
726917f0 | 260 | int mei_hbuf_empty_slots(struct mei_device *dev) |
3ce72726 | 261 | { |
24aadc80 | 262 | unsigned char filled_slots, empty_slots; |
3ce72726 | 263 | |
726917f0 | 264 | filled_slots = mei_hbuf_filled_slots(dev); |
24aadc80 | 265 | empty_slots = dev->hbuf_depth - filled_slots; |
3ce72726 OW |
266 | |
267 | /* check for overflow */ | |
24aadc80 | 268 | if (filled_slots > dev->hbuf_depth) |
3ce72726 OW |
269 | return -EOVERFLOW; |
270 | ||
271 | return empty_slots; | |
272 | } | |
273 | ||
274 | /** | |
275 | * mei_write_message - writes a message to mei device. | |
276 | * | |
277 | * @dev: the device structure | |
438763f3 TW |
278 | * @hader: mei HECI header of message |
279 | * @buf: message payload will be written | |
3ce72726 | 280 | * |
1ccb7b62 | 281 | * This function returns -EIO if write has failed |
3ce72726 | 282 | */ |
169d1338 | 283 | int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header, |
438763f3 | 284 | unsigned char *buf) |
3ce72726 | 285 | { |
169d1338 | 286 | unsigned long rem, dw_cnt; |
438763f3 | 287 | unsigned long length = header->length; |
169d1338 | 288 | u32 *reg_buf = (u32 *)buf; |
88eb99f2 | 289 | u32 hcsr; |
169d1338 TW |
290 | int i; |
291 | int empty_slots; | |
3ce72726 | 292 | |
15d4acc5 | 293 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header)); |
3ce72726 | 294 | |
726917f0 | 295 | empty_slots = mei_hbuf_empty_slots(dev); |
169d1338 | 296 | dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots); |
3ce72726 | 297 | |
7bdf72d3 | 298 | dw_cnt = mei_data2slots(length); |
169d1338 | 299 | if (empty_slots < 0 || dw_cnt > empty_slots) |
1ccb7b62 | 300 | return -EIO; |
3ce72726 OW |
301 | |
302 | mei_reg_write(dev, H_CB_WW, *((u32 *) header)); | |
303 | ||
169d1338 TW |
304 | for (i = 0; i < length / 4; i++) |
305 | mei_reg_write(dev, H_CB_WW, reg_buf[i]); | |
3ce72726 | 306 | |
169d1338 TW |
307 | rem = length & 0x3; |
308 | if (rem > 0) { | |
309 | u32 reg = 0; | |
310 | memcpy(®, &buf[length - rem], rem); | |
311 | mei_reg_write(dev, H_CB_WW, reg); | |
3ce72726 OW |
312 | } |
313 | ||
88eb99f2 TW |
314 | hcsr = mei_hcsr_read(dev) | H_IG; |
315 | mei_hcsr_set(dev, hcsr); | |
3ce72726 | 316 | dev->me_hw_state = mei_mecsr_read(dev); |
115ba28c | 317 | if (!mei_me_is_ready(dev)) |
1ccb7b62 | 318 | return -EIO; |
3ce72726 | 319 | |
1ccb7b62 | 320 | return 0; |
3ce72726 OW |
321 | } |
322 | ||
323 | /** | |
324 | * mei_count_full_read_slots - counts read full slots. | |
325 | * | |
326 | * @dev: the device structure | |
327 | * | |
328 | * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count | |
329 | */ | |
330 | int mei_count_full_read_slots(struct mei_device *dev) | |
331 | { | |
332 | char read_ptr, write_ptr; | |
333 | unsigned char buffer_depth, filled_slots; | |
334 | ||
335 | dev->me_hw_state = mei_mecsr_read(dev); | |
336 | buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24); | |
337 | read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8); | |
338 | write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16); | |
339 | filled_slots = (unsigned char) (write_ptr - read_ptr); | |
340 | ||
341 | /* check for overflow */ | |
342 | if (filled_slots > buffer_depth) | |
343 | return -EOVERFLOW; | |
344 | ||
345 | dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots); | |
346 | return (int)filled_slots; | |
347 | } | |
348 | ||
349 | /** | |
350 | * mei_read_slots - reads a message from mei device. | |
351 | * | |
352 | * @dev: the device structure | |
353 | * @buffer: message buffer will be written | |
354 | * @buffer_length: message size will be read | |
355 | */ | |
edf1eed4 TW |
356 | void mei_read_slots(struct mei_device *dev, unsigned char *buffer, |
357 | unsigned long buffer_length) | |
3ce72726 | 358 | { |
edf1eed4 | 359 | u32 *reg_buf = (u32 *)buffer; |
88eb99f2 | 360 | u32 hcsr; |
3ce72726 | 361 | |
edf1eed4 TW |
362 | for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32)) |
363 | *reg_buf++ = mei_mecbrw_read(dev); | |
3ce72726 OW |
364 | |
365 | if (buffer_length > 0) { | |
edf1eed4 TW |
366 | u32 reg = mei_mecbrw_read(dev); |
367 | memcpy(reg_buf, ®, buffer_length); | |
3ce72726 OW |
368 | } |
369 | ||
88eb99f2 TW |
370 | hcsr = mei_hcsr_read(dev) | H_IG; |
371 | mei_hcsr_set(dev, hcsr); | |
3ce72726 OW |
372 | } |
373 |