]>
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> | |
06ecd645 TW |
18 | |
19 | #include <linux/kthread.h> | |
20 | #include <linux/interrupt.h> | |
47a73801 TW |
21 | |
22 | #include "mei_dev.h" | |
06ecd645 TW |
23 | #include "hbm.h" |
24 | ||
6e4cd27a TW |
25 | #include "hw-me.h" |
26 | #include "hw-me-regs.h" | |
06ecd645 | 27 | |
a0a927d0 TW |
28 | #include "mei-trace.h" |
29 | ||
3a65dd4e | 30 | /** |
b68301e9 | 31 | * mei_me_reg_read - Reads 32bit data from the mei device |
3a65dd4e | 32 | * |
a8605ea2 | 33 | * @hw: the me hardware structure |
3a65dd4e TW |
34 | * @offset: offset from which to read the data |
35 | * | |
a8605ea2 | 36 | * Return: register value (u32) |
3a65dd4e | 37 | */ |
b68301e9 | 38 | static inline u32 mei_me_reg_read(const struct mei_me_hw *hw, |
3a65dd4e TW |
39 | unsigned long offset) |
40 | { | |
52c34561 | 41 | return ioread32(hw->mem_addr + offset); |
3a65dd4e TW |
42 | } |
43 | ||
44 | ||
45 | /** | |
b68301e9 | 46 | * mei_me_reg_write - Writes 32bit data to the mei device |
3a65dd4e | 47 | * |
a8605ea2 | 48 | * @hw: the me hardware structure |
3a65dd4e TW |
49 | * @offset: offset from which to write the data |
50 | * @value: register value to write (u32) | |
51 | */ | |
b68301e9 | 52 | static inline void mei_me_reg_write(const struct mei_me_hw *hw, |
3a65dd4e TW |
53 | unsigned long offset, u32 value) |
54 | { | |
52c34561 | 55 | iowrite32(value, hw->mem_addr + offset); |
3a65dd4e | 56 | } |
3ce72726 | 57 | |
3a65dd4e | 58 | /** |
b68301e9 | 59 | * mei_me_mecbrw_read - Reads 32bit data from ME circular buffer |
d025284d | 60 | * read window register |
3a65dd4e TW |
61 | * |
62 | * @dev: the device structure | |
63 | * | |
a8605ea2 | 64 | * Return: ME_CB_RW register value (u32) |
3a65dd4e | 65 | */ |
381a58c7 | 66 | static inline u32 mei_me_mecbrw_read(const struct mei_device *dev) |
3a65dd4e | 67 | { |
b68301e9 | 68 | return mei_me_reg_read(to_me_hw(dev), ME_CB_RW); |
3a65dd4e | 69 | } |
381a58c7 TW |
70 | |
71 | /** | |
72 | * mei_me_hcbww_write - write 32bit data to the host circular buffer | |
73 | * | |
74 | * @dev: the device structure | |
75 | * @data: 32bit data to be written to the host circular buffer | |
76 | */ | |
77 | static inline void mei_me_hcbww_write(struct mei_device *dev, u32 data) | |
78 | { | |
79 | mei_me_reg_write(to_me_hw(dev), H_CB_WW, data); | |
80 | } | |
81 | ||
3a65dd4e | 82 | /** |
b68301e9 | 83 | * mei_me_mecsr_read - Reads 32bit data from the ME CSR |
3a65dd4e | 84 | * |
381a58c7 | 85 | * @dev: the device structure |
3a65dd4e | 86 | * |
a8605ea2 | 87 | * Return: ME_CSR_HA register value (u32) |
3a65dd4e | 88 | */ |
381a58c7 | 89 | static inline u32 mei_me_mecsr_read(const struct mei_device *dev) |
3a65dd4e | 90 | { |
a0a927d0 TW |
91 | u32 reg; |
92 | ||
93 | reg = mei_me_reg_read(to_me_hw(dev), ME_CSR_HA); | |
94 | trace_mei_reg_read(dev->dev, "ME_CSR_HA", ME_CSR_HA, reg); | |
95 | ||
96 | return reg; | |
3a65dd4e | 97 | } |
3ce72726 OW |
98 | |
99 | /** | |
d025284d TW |
100 | * mei_hcsr_read - Reads 32bit data from the host CSR |
101 | * | |
381a58c7 | 102 | * @dev: the device structure |
d025284d | 103 | * |
a8605ea2 | 104 | * Return: H_CSR register value (u32) |
d025284d | 105 | */ |
381a58c7 | 106 | static inline u32 mei_hcsr_read(const struct mei_device *dev) |
d025284d | 107 | { |
a0a927d0 TW |
108 | u32 reg; |
109 | ||
110 | reg = mei_me_reg_read(to_me_hw(dev), H_CSR); | |
111 | trace_mei_reg_read(dev->dev, "H_CSR", H_CSR, reg); | |
112 | ||
113 | return reg; | |
381a58c7 TW |
114 | } |
115 | ||
116 | /** | |
117 | * mei_hcsr_write - writes H_CSR register to the mei device | |
118 | * | |
119 | * @dev: the device structure | |
120 | * @reg: new register value | |
121 | */ | |
122 | static inline void mei_hcsr_write(struct mei_device *dev, u32 reg) | |
123 | { | |
a0a927d0 | 124 | trace_mei_reg_write(dev->dev, "H_CSR", H_CSR, reg); |
381a58c7 | 125 | mei_me_reg_write(to_me_hw(dev), H_CSR, reg); |
d025284d TW |
126 | } |
127 | ||
128 | /** | |
129 | * mei_hcsr_set - writes H_CSR register to the mei device, | |
3ce72726 OW |
130 | * and ignores the H_IS bit for it is write-one-to-zero. |
131 | * | |
381a58c7 TW |
132 | * @dev: the device structure |
133 | * @reg: new register value | |
3ce72726 | 134 | */ |
381a58c7 | 135 | static inline void mei_hcsr_set(struct mei_device *dev, u32 reg) |
3ce72726 | 136 | { |
1fa55b4e | 137 | reg &= ~H_CSR_IS_MASK; |
381a58c7 | 138 | mei_hcsr_write(dev, reg); |
3ce72726 OW |
139 | } |
140 | ||
859ef2ff AU |
141 | /** |
142 | * mei_me_d0i3c_read - Reads 32bit data from the D0I3C register | |
143 | * | |
144 | * @dev: the device structure | |
145 | * | |
146 | * Return: H_D0I3C register value (u32) | |
147 | */ | |
148 | static inline u32 mei_me_d0i3c_read(const struct mei_device *dev) | |
149 | { | |
150 | u32 reg; | |
151 | ||
152 | reg = mei_me_reg_read(to_me_hw(dev), H_D0I3C); | |
153 | trace_mei_reg_read(dev->dev, "H_D0I3C", H_CSR, reg); | |
154 | ||
155 | return reg; | |
156 | } | |
157 | ||
158 | /** | |
159 | * mei_me_d0i3c_write - writes H_D0I3C register to device | |
160 | * | |
161 | * @dev: the device structure | |
162 | * @reg: new register value | |
163 | */ | |
164 | static inline void mei_me_d0i3c_write(struct mei_device *dev, u32 reg) | |
165 | { | |
166 | trace_mei_reg_write(dev->dev, "H_D0I3C", H_CSR, reg); | |
167 | mei_me_reg_write(to_me_hw(dev), H_D0I3C, reg); | |
168 | } | |
169 | ||
1bd30b6a TW |
170 | /** |
171 | * mei_me_fw_status - read fw status register from pci config space | |
172 | * | |
173 | * @dev: mei device | |
174 | * @fw_status: fw status register values | |
ce23139c AU |
175 | * |
176 | * Return: 0 on success, error otherwise | |
1bd30b6a TW |
177 | */ |
178 | static int mei_me_fw_status(struct mei_device *dev, | |
179 | struct mei_fw_status *fw_status) | |
180 | { | |
1bd30b6a | 181 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
4ad96db6 TW |
182 | struct mei_me_hw *hw = to_me_hw(dev); |
183 | const struct mei_fw_status *fw_src = &hw->cfg->fw_status; | |
1bd30b6a TW |
184 | int ret; |
185 | int i; | |
186 | ||
187 | if (!fw_status) | |
188 | return -EINVAL; | |
189 | ||
190 | fw_status->count = fw_src->count; | |
191 | for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) { | |
192 | ret = pci_read_config_dword(pdev, | |
193 | fw_src->status[i], &fw_status->status[i]); | |
194 | if (ret) | |
195 | return ret; | |
196 | } | |
197 | ||
198 | return 0; | |
199 | } | |
e7e0c231 TW |
200 | |
201 | /** | |
393b148f | 202 | * mei_me_hw_config - configure hw dependent settings |
e7e0c231 TW |
203 | * |
204 | * @dev: mei device | |
205 | */ | |
827eef51 | 206 | static void mei_me_hw_config(struct mei_device *dev) |
e7e0c231 | 207 | { |
bb9f4d26 | 208 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
ba9cdd0e | 209 | struct mei_me_hw *hw = to_me_hw(dev); |
bb9f4d26 AU |
210 | u32 hcsr, reg; |
211 | ||
e7e0c231 | 212 | /* Doesn't change in runtime */ |
bb9f4d26 | 213 | hcsr = mei_hcsr_read(dev); |
e7e0c231 | 214 | dev->hbuf_depth = (hcsr & H_CBD) >> 24; |
ba9cdd0e | 215 | |
bb9f4d26 AU |
216 | reg = 0; |
217 | pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); | |
218 | hw->d0i3_supported = | |
219 | ((reg & PCI_CFG_HFS_1_D0I3_MSK) == PCI_CFG_HFS_1_D0I3_MSK); | |
b9a1fc99 AU |
220 | |
221 | hw->pg_state = MEI_PG_OFF; | |
222 | if (hw->d0i3_supported) { | |
223 | reg = mei_me_d0i3c_read(dev); | |
224 | if (reg & H_D0I3C_I3) | |
225 | hw->pg_state = MEI_PG_ON; | |
226 | } | |
e7e0c231 | 227 | } |
964a2331 TW |
228 | |
229 | /** | |
230 | * mei_me_pg_state - translate internal pg state | |
231 | * to the mei power gating state | |
232 | * | |
ce23139c AU |
233 | * @dev: mei device |
234 | * | |
235 | * Return: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise | |
964a2331 TW |
236 | */ |
237 | static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev) | |
238 | { | |
ba9cdd0e | 239 | struct mei_me_hw *hw = to_me_hw(dev); |
92db1555 | 240 | |
ba9cdd0e | 241 | return hw->pg_state; |
964a2331 TW |
242 | } |
243 | ||
3ce72726 | 244 | /** |
ce23139c | 245 | * mei_me_intr_clear - clear and stop interrupts |
3a65dd4e TW |
246 | * |
247 | * @dev: the device structure | |
248 | */ | |
827eef51 | 249 | static void mei_me_intr_clear(struct mei_device *dev) |
3a65dd4e | 250 | { |
381a58c7 | 251 | u32 hcsr = mei_hcsr_read(dev); |
92db1555 | 252 | |
1fa55b4e | 253 | if (hcsr & H_CSR_IS_MASK) |
381a58c7 | 254 | mei_hcsr_write(dev, hcsr); |
3a65dd4e | 255 | } |
3a65dd4e | 256 | /** |
827eef51 | 257 | * mei_me_intr_enable - enables mei device interrupts |
3ce72726 OW |
258 | * |
259 | * @dev: the device structure | |
260 | */ | |
827eef51 | 261 | static void mei_me_intr_enable(struct mei_device *dev) |
3ce72726 | 262 | { |
381a58c7 | 263 | u32 hcsr = mei_hcsr_read(dev); |
92db1555 | 264 | |
1fa55b4e | 265 | hcsr |= H_CSR_IE_MASK; |
381a58c7 | 266 | mei_hcsr_set(dev, hcsr); |
3ce72726 OW |
267 | } |
268 | ||
269 | /** | |
ce23139c | 270 | * mei_me_intr_disable - disables mei device interrupts |
3ce72726 OW |
271 | * |
272 | * @dev: the device structure | |
273 | */ | |
827eef51 | 274 | static void mei_me_intr_disable(struct mei_device *dev) |
3ce72726 | 275 | { |
381a58c7 | 276 | u32 hcsr = mei_hcsr_read(dev); |
92db1555 | 277 | |
1fa55b4e | 278 | hcsr &= ~H_CSR_IE_MASK; |
381a58c7 | 279 | mei_hcsr_set(dev, hcsr); |
3ce72726 OW |
280 | } |
281 | ||
68f8ea18 TW |
282 | /** |
283 | * mei_me_hw_reset_release - release device from the reset | |
284 | * | |
285 | * @dev: the device structure | |
286 | */ | |
287 | static void mei_me_hw_reset_release(struct mei_device *dev) | |
288 | { | |
381a58c7 | 289 | u32 hcsr = mei_hcsr_read(dev); |
68f8ea18 TW |
290 | |
291 | hcsr |= H_IG; | |
292 | hcsr &= ~H_RST; | |
381a58c7 | 293 | mei_hcsr_set(dev, hcsr); |
b04ada92 TW |
294 | |
295 | /* complete this write before we set host ready on another CPU */ | |
296 | mmiowb(); | |
68f8ea18 | 297 | } |
adfba322 | 298 | |
115ba28c | 299 | /** |
827eef51 | 300 | * mei_me_host_set_ready - enable device |
115ba28c | 301 | * |
ce23139c | 302 | * @dev: mei device |
115ba28c | 303 | */ |
827eef51 | 304 | static void mei_me_host_set_ready(struct mei_device *dev) |
115ba28c | 305 | { |
381a58c7 | 306 | u32 hcsr = mei_hcsr_read(dev); |
92db1555 | 307 | |
1fa55b4e | 308 | hcsr |= H_CSR_IE_MASK | H_IG | H_RDY; |
381a58c7 | 309 | mei_hcsr_set(dev, hcsr); |
115ba28c | 310 | } |
ce23139c | 311 | |
115ba28c | 312 | /** |
827eef51 | 313 | * mei_me_host_is_ready - check whether the host has turned ready |
115ba28c | 314 | * |
a8605ea2 AU |
315 | * @dev: mei device |
316 | * Return: bool | |
115ba28c | 317 | */ |
827eef51 | 318 | static bool mei_me_host_is_ready(struct mei_device *dev) |
115ba28c | 319 | { |
381a58c7 | 320 | u32 hcsr = mei_hcsr_read(dev); |
92db1555 | 321 | |
18caeb70 | 322 | return (hcsr & H_RDY) == H_RDY; |
115ba28c TW |
323 | } |
324 | ||
325 | /** | |
827eef51 | 326 | * mei_me_hw_is_ready - check whether the me(hw) has turned ready |
115ba28c | 327 | * |
a8605ea2 AU |
328 | * @dev: mei device |
329 | * Return: bool | |
115ba28c | 330 | */ |
827eef51 | 331 | static bool mei_me_hw_is_ready(struct mei_device *dev) |
115ba28c | 332 | { |
381a58c7 | 333 | u32 mecsr = mei_me_mecsr_read(dev); |
92db1555 | 334 | |
18caeb70 | 335 | return (mecsr & ME_RDY_HRA) == ME_RDY_HRA; |
115ba28c | 336 | } |
3a65dd4e | 337 | |
ce23139c AU |
338 | /** |
339 | * mei_me_hw_ready_wait - wait until the me(hw) has turned ready | |
340 | * or timeout is reached | |
341 | * | |
342 | * @dev: mei device | |
343 | * Return: 0 on success, error otherwise | |
344 | */ | |
aafae7ec TW |
345 | static int mei_me_hw_ready_wait(struct mei_device *dev) |
346 | { | |
aafae7ec | 347 | mutex_unlock(&dev->device_lock); |
2c2b93ec | 348 | wait_event_timeout(dev->wait_hw_ready, |
dab9bf41 | 349 | dev->recvd_hw_ready, |
7d93e58d | 350 | mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT)); |
aafae7ec | 351 | mutex_lock(&dev->device_lock); |
2c2b93ec | 352 | if (!dev->recvd_hw_ready) { |
2bf94cab | 353 | dev_err(dev->dev, "wait hw ready failed\n"); |
2c2b93ec | 354 | return -ETIME; |
aafae7ec TW |
355 | } |
356 | ||
663b7ee9 | 357 | mei_me_hw_reset_release(dev); |
aafae7ec TW |
358 | dev->recvd_hw_ready = false; |
359 | return 0; | |
360 | } | |
361 | ||
ce23139c AU |
362 | /** |
363 | * mei_me_hw_start - hw start routine | |
364 | * | |
365 | * @dev: mei device | |
366 | * Return: 0 on success, error otherwise | |
367 | */ | |
aafae7ec TW |
368 | static int mei_me_hw_start(struct mei_device *dev) |
369 | { | |
370 | int ret = mei_me_hw_ready_wait(dev); | |
92db1555 | 371 | |
aafae7ec TW |
372 | if (ret) |
373 | return ret; | |
2bf94cab | 374 | dev_dbg(dev->dev, "hw is ready\n"); |
aafae7ec TW |
375 | |
376 | mei_me_host_set_ready(dev); | |
377 | return ret; | |
378 | } | |
379 | ||
380 | ||
3ce72726 | 381 | /** |
726917f0 | 382 | * mei_hbuf_filled_slots - gets number of device filled buffer slots |
3ce72726 | 383 | * |
7353f85c | 384 | * @dev: the device structure |
3ce72726 | 385 | * |
a8605ea2 | 386 | * Return: number of filled slots |
3ce72726 | 387 | */ |
726917f0 | 388 | static unsigned char mei_hbuf_filled_slots(struct mei_device *dev) |
3ce72726 | 389 | { |
18caeb70 | 390 | u32 hcsr; |
3ce72726 OW |
391 | char read_ptr, write_ptr; |
392 | ||
381a58c7 | 393 | hcsr = mei_hcsr_read(dev); |
726917f0 | 394 | |
18caeb70 TW |
395 | read_ptr = (char) ((hcsr & H_CBRP) >> 8); |
396 | write_ptr = (char) ((hcsr & H_CBWP) >> 16); | |
3ce72726 OW |
397 | |
398 | return (unsigned char) (write_ptr - read_ptr); | |
399 | } | |
400 | ||
401 | /** | |
393b148f | 402 | * mei_me_hbuf_is_empty - checks if host buffer is empty. |
3ce72726 OW |
403 | * |
404 | * @dev: the device structure | |
405 | * | |
a8605ea2 | 406 | * Return: true if empty, false - otherwise. |
3ce72726 | 407 | */ |
827eef51 | 408 | static bool mei_me_hbuf_is_empty(struct mei_device *dev) |
3ce72726 | 409 | { |
726917f0 | 410 | return mei_hbuf_filled_slots(dev) == 0; |
3ce72726 OW |
411 | } |
412 | ||
413 | /** | |
827eef51 | 414 | * mei_me_hbuf_empty_slots - counts write empty slots. |
3ce72726 OW |
415 | * |
416 | * @dev: the device structure | |
417 | * | |
a8605ea2 | 418 | * Return: -EOVERFLOW if overflow, otherwise empty slots count |
3ce72726 | 419 | */ |
827eef51 | 420 | static int mei_me_hbuf_empty_slots(struct mei_device *dev) |
3ce72726 | 421 | { |
24aadc80 | 422 | unsigned char filled_slots, empty_slots; |
3ce72726 | 423 | |
726917f0 | 424 | filled_slots = mei_hbuf_filled_slots(dev); |
24aadc80 | 425 | empty_slots = dev->hbuf_depth - filled_slots; |
3ce72726 OW |
426 | |
427 | /* check for overflow */ | |
24aadc80 | 428 | if (filled_slots > dev->hbuf_depth) |
3ce72726 OW |
429 | return -EOVERFLOW; |
430 | ||
431 | return empty_slots; | |
432 | } | |
433 | ||
ce23139c AU |
434 | /** |
435 | * mei_me_hbuf_max_len - returns size of hw buffer. | |
436 | * | |
437 | * @dev: the device structure | |
438 | * | |
439 | * Return: size of hw buffer in bytes | |
440 | */ | |
827eef51 TW |
441 | static size_t mei_me_hbuf_max_len(const struct mei_device *dev) |
442 | { | |
443 | return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr); | |
444 | } | |
445 | ||
446 | ||
3ce72726 | 447 | /** |
7ca96aa2 | 448 | * mei_me_write_message - writes a message to mei device. |
3ce72726 OW |
449 | * |
450 | * @dev: the device structure | |
7353f85c | 451 | * @header: mei HECI header of message |
438763f3 | 452 | * @buf: message payload will be written |
3ce72726 | 453 | * |
a8605ea2 | 454 | * Return: -EIO if write has failed |
3ce72726 | 455 | */ |
827eef51 TW |
456 | static int mei_me_write_message(struct mei_device *dev, |
457 | struct mei_msg_hdr *header, | |
458 | unsigned char *buf) | |
3ce72726 | 459 | { |
c8c8d080 | 460 | unsigned long rem; |
438763f3 | 461 | unsigned long length = header->length; |
169d1338 | 462 | u32 *reg_buf = (u32 *)buf; |
88eb99f2 | 463 | u32 hcsr; |
c8c8d080 | 464 | u32 dw_cnt; |
169d1338 TW |
465 | int i; |
466 | int empty_slots; | |
3ce72726 | 467 | |
2bf94cab | 468 | dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header)); |
3ce72726 | 469 | |
726917f0 | 470 | empty_slots = mei_hbuf_empty_slots(dev); |
2bf94cab | 471 | dev_dbg(dev->dev, "empty slots = %hu.\n", empty_slots); |
3ce72726 | 472 | |
7bdf72d3 | 473 | dw_cnt = mei_data2slots(length); |
169d1338 | 474 | if (empty_slots < 0 || dw_cnt > empty_slots) |
9d098192 | 475 | return -EMSGSIZE; |
3ce72726 | 476 | |
381a58c7 | 477 | mei_me_hcbww_write(dev, *((u32 *) header)); |
3ce72726 | 478 | |
169d1338 | 479 | for (i = 0; i < length / 4; i++) |
381a58c7 | 480 | mei_me_hcbww_write(dev, reg_buf[i]); |
3ce72726 | 481 | |
169d1338 TW |
482 | rem = length & 0x3; |
483 | if (rem > 0) { | |
484 | u32 reg = 0; | |
92db1555 | 485 | |
169d1338 | 486 | memcpy(®, &buf[length - rem], rem); |
381a58c7 | 487 | mei_me_hcbww_write(dev, reg); |
3ce72726 OW |
488 | } |
489 | ||
381a58c7 TW |
490 | hcsr = mei_hcsr_read(dev) | H_IG; |
491 | mei_hcsr_set(dev, hcsr); | |
827eef51 | 492 | if (!mei_me_hw_is_ready(dev)) |
1ccb7b62 | 493 | return -EIO; |
3ce72726 | 494 | |
1ccb7b62 | 495 | return 0; |
3ce72726 OW |
496 | } |
497 | ||
498 | /** | |
827eef51 | 499 | * mei_me_count_full_read_slots - counts read full slots. |
3ce72726 OW |
500 | * |
501 | * @dev: the device structure | |
502 | * | |
a8605ea2 | 503 | * Return: -EOVERFLOW if overflow, otherwise filled slots count |
3ce72726 | 504 | */ |
827eef51 | 505 | static int mei_me_count_full_read_slots(struct mei_device *dev) |
3ce72726 | 506 | { |
18caeb70 | 507 | u32 me_csr; |
3ce72726 OW |
508 | char read_ptr, write_ptr; |
509 | unsigned char buffer_depth, filled_slots; | |
510 | ||
381a58c7 | 511 | me_csr = mei_me_mecsr_read(dev); |
18caeb70 TW |
512 | buffer_depth = (unsigned char)((me_csr & ME_CBD_HRA) >> 24); |
513 | read_ptr = (char) ((me_csr & ME_CBRP_HRA) >> 8); | |
514 | write_ptr = (char) ((me_csr & ME_CBWP_HRA) >> 16); | |
3ce72726 OW |
515 | filled_slots = (unsigned char) (write_ptr - read_ptr); |
516 | ||
517 | /* check for overflow */ | |
518 | if (filled_slots > buffer_depth) | |
519 | return -EOVERFLOW; | |
520 | ||
2bf94cab | 521 | dev_dbg(dev->dev, "filled_slots =%08x\n", filled_slots); |
3ce72726 OW |
522 | return (int)filled_slots; |
523 | } | |
524 | ||
525 | /** | |
827eef51 | 526 | * mei_me_read_slots - reads a message from mei device. |
3ce72726 OW |
527 | * |
528 | * @dev: the device structure | |
529 | * @buffer: message buffer will be written | |
530 | * @buffer_length: message size will be read | |
ce23139c AU |
531 | * |
532 | * Return: always 0 | |
3ce72726 | 533 | */ |
827eef51 | 534 | static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, |
edf1eed4 | 535 | unsigned long buffer_length) |
3ce72726 | 536 | { |
edf1eed4 | 537 | u32 *reg_buf = (u32 *)buffer; |
88eb99f2 | 538 | u32 hcsr; |
3ce72726 | 539 | |
edf1eed4 | 540 | for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32)) |
827eef51 | 541 | *reg_buf++ = mei_me_mecbrw_read(dev); |
3ce72726 OW |
542 | |
543 | if (buffer_length > 0) { | |
827eef51 | 544 | u32 reg = mei_me_mecbrw_read(dev); |
92db1555 | 545 | |
edf1eed4 | 546 | memcpy(reg_buf, ®, buffer_length); |
3ce72726 OW |
547 | } |
548 | ||
381a58c7 TW |
549 | hcsr = mei_hcsr_read(dev) | H_IG; |
550 | mei_hcsr_set(dev, hcsr); | |
827eef51 | 551 | return 0; |
3ce72726 OW |
552 | } |
553 | ||
b16c3571 | 554 | /** |
2d1995fc | 555 | * mei_me_pg_set - write pg enter register |
b16c3571 TW |
556 | * |
557 | * @dev: the device structure | |
558 | */ | |
2d1995fc | 559 | static void mei_me_pg_set(struct mei_device *dev) |
b16c3571 TW |
560 | { |
561 | struct mei_me_hw *hw = to_me_hw(dev); | |
a0a927d0 TW |
562 | u32 reg; |
563 | ||
564 | reg = mei_me_reg_read(hw, H_HPG_CSR); | |
565 | trace_mei_reg_read(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); | |
92db1555 | 566 | |
b16c3571 | 567 | reg |= H_HPG_CSR_PGI; |
a0a927d0 TW |
568 | |
569 | trace_mei_reg_write(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); | |
b16c3571 TW |
570 | mei_me_reg_write(hw, H_HPG_CSR, reg); |
571 | } | |
572 | ||
573 | /** | |
2d1995fc | 574 | * mei_me_pg_unset - write pg exit register |
b16c3571 TW |
575 | * |
576 | * @dev: the device structure | |
577 | */ | |
2d1995fc | 578 | static void mei_me_pg_unset(struct mei_device *dev) |
b16c3571 TW |
579 | { |
580 | struct mei_me_hw *hw = to_me_hw(dev); | |
a0a927d0 TW |
581 | u32 reg; |
582 | ||
583 | reg = mei_me_reg_read(hw, H_HPG_CSR); | |
584 | trace_mei_reg_read(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); | |
b16c3571 TW |
585 | |
586 | WARN(!(reg & H_HPG_CSR_PGI), "PGI is not set\n"); | |
587 | ||
588 | reg |= H_HPG_CSR_PGIHEXR; | |
a0a927d0 TW |
589 | |
590 | trace_mei_reg_write(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); | |
b16c3571 TW |
591 | mei_me_reg_write(hw, H_HPG_CSR, reg); |
592 | } | |
593 | ||
ba9cdd0e | 594 | /** |
859ef2ff | 595 | * mei_me_pg_legacy_enter_sync - perform legacy pg entry procedure |
ba9cdd0e TW |
596 | * |
597 | * @dev: the device structure | |
598 | * | |
a8605ea2 | 599 | * Return: 0 on success an error code otherwise |
ba9cdd0e | 600 | */ |
859ef2ff | 601 | static int mei_me_pg_legacy_enter_sync(struct mei_device *dev) |
ba9cdd0e TW |
602 | { |
603 | struct mei_me_hw *hw = to_me_hw(dev); | |
604 | unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); | |
605 | int ret; | |
606 | ||
607 | dev->pg_event = MEI_PG_EVENT_WAIT; | |
608 | ||
609 | ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_ENTRY_REQ_CMD); | |
610 | if (ret) | |
611 | return ret; | |
612 | ||
613 | mutex_unlock(&dev->device_lock); | |
614 | wait_event_timeout(dev->wait_pg, | |
615 | dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); | |
616 | mutex_lock(&dev->device_lock); | |
617 | ||
618 | if (dev->pg_event == MEI_PG_EVENT_RECEIVED) { | |
2d1995fc | 619 | mei_me_pg_set(dev); |
ba9cdd0e TW |
620 | ret = 0; |
621 | } else { | |
622 | ret = -ETIME; | |
623 | } | |
624 | ||
625 | dev->pg_event = MEI_PG_EVENT_IDLE; | |
626 | hw->pg_state = MEI_PG_ON; | |
627 | ||
628 | return ret; | |
629 | } | |
630 | ||
631 | /** | |
859ef2ff | 632 | * mei_me_pg_legacy_exit_sync - perform legacy pg exit procedure |
ba9cdd0e TW |
633 | * |
634 | * @dev: the device structure | |
635 | * | |
a8605ea2 | 636 | * Return: 0 on success an error code otherwise |
ba9cdd0e | 637 | */ |
859ef2ff | 638 | static int mei_me_pg_legacy_exit_sync(struct mei_device *dev) |
ba9cdd0e TW |
639 | { |
640 | struct mei_me_hw *hw = to_me_hw(dev); | |
641 | unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); | |
642 | int ret; | |
643 | ||
644 | if (dev->pg_event == MEI_PG_EVENT_RECEIVED) | |
645 | goto reply; | |
646 | ||
647 | dev->pg_event = MEI_PG_EVENT_WAIT; | |
648 | ||
2d1995fc | 649 | mei_me_pg_unset(dev); |
ba9cdd0e TW |
650 | |
651 | mutex_unlock(&dev->device_lock); | |
652 | wait_event_timeout(dev->wait_pg, | |
653 | dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); | |
654 | mutex_lock(&dev->device_lock); | |
655 | ||
656 | reply: | |
3dc196ea AU |
657 | if (dev->pg_event != MEI_PG_EVENT_RECEIVED) { |
658 | ret = -ETIME; | |
659 | goto out; | |
660 | } | |
661 | ||
662 | dev->pg_event = MEI_PG_EVENT_INTR_WAIT; | |
663 | ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_EXIT_RES_CMD); | |
664 | if (ret) | |
665 | return ret; | |
666 | ||
667 | mutex_unlock(&dev->device_lock); | |
668 | wait_event_timeout(dev->wait_pg, | |
669 | dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED, timeout); | |
670 | mutex_lock(&dev->device_lock); | |
671 | ||
672 | if (dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED) | |
673 | ret = 0; | |
ba9cdd0e TW |
674 | else |
675 | ret = -ETIME; | |
676 | ||
3dc196ea | 677 | out: |
ba9cdd0e TW |
678 | dev->pg_event = MEI_PG_EVENT_IDLE; |
679 | hw->pg_state = MEI_PG_OFF; | |
680 | ||
681 | return ret; | |
682 | } | |
683 | ||
3dc196ea AU |
684 | /** |
685 | * mei_me_pg_in_transition - is device now in pg transition | |
686 | * | |
687 | * @dev: the device structure | |
688 | * | |
689 | * Return: true if in pg transition, false otherwise | |
690 | */ | |
691 | static bool mei_me_pg_in_transition(struct mei_device *dev) | |
692 | { | |
693 | return dev->pg_event >= MEI_PG_EVENT_WAIT && | |
694 | dev->pg_event <= MEI_PG_EVENT_INTR_WAIT; | |
695 | } | |
696 | ||
ee7e5afd TW |
697 | /** |
698 | * mei_me_pg_is_enabled - detect if PG is supported by HW | |
699 | * | |
700 | * @dev: the device structure | |
701 | * | |
a8605ea2 | 702 | * Return: true is pg supported, false otherwise |
ee7e5afd TW |
703 | */ |
704 | static bool mei_me_pg_is_enabled(struct mei_device *dev) | |
705 | { | |
859ef2ff | 706 | struct mei_me_hw *hw = to_me_hw(dev); |
381a58c7 | 707 | u32 reg = mei_me_mecsr_read(dev); |
ee7e5afd | 708 | |
859ef2ff AU |
709 | if (hw->d0i3_supported) |
710 | return true; | |
711 | ||
ee7e5afd TW |
712 | if ((reg & ME_PGIC_HRA) == 0) |
713 | goto notsupported; | |
714 | ||
bae1cc7d | 715 | if (!dev->hbm_f_pg_supported) |
ee7e5afd TW |
716 | goto notsupported; |
717 | ||
718 | return true; | |
719 | ||
720 | notsupported: | |
859ef2ff AU |
721 | dev_dbg(dev->dev, "pg: not supported: d0i3 = %d HGP = %d hbm version %d.%d ?= %d.%d\n", |
722 | hw->d0i3_supported, | |
ee7e5afd TW |
723 | !!(reg & ME_PGIC_HRA), |
724 | dev->version.major_version, | |
725 | dev->version.minor_version, | |
726 | HBM_MAJOR_VERSION_PGI, | |
727 | HBM_MINOR_VERSION_PGI); | |
728 | ||
729 | return false; | |
730 | } | |
731 | ||
3dc196ea | 732 | /** |
859ef2ff | 733 | * mei_me_d0i3_set - write d0i3 register bit on mei device. |
3dc196ea AU |
734 | * |
735 | * @dev: the device structure | |
859ef2ff AU |
736 | * @intr: ask for interrupt |
737 | * | |
738 | * Return: D0I3C register value | |
3dc196ea | 739 | */ |
859ef2ff AU |
740 | static u32 mei_me_d0i3_set(struct mei_device *dev, bool intr) |
741 | { | |
742 | u32 reg = mei_me_d0i3c_read(dev); | |
743 | ||
744 | reg |= H_D0I3C_I3; | |
745 | if (intr) | |
746 | reg |= H_D0I3C_IR; | |
747 | else | |
748 | reg &= ~H_D0I3C_IR; | |
749 | mei_me_d0i3c_write(dev, reg); | |
750 | /* read it to ensure HW consistency */ | |
751 | reg = mei_me_d0i3c_read(dev); | |
752 | return reg; | |
753 | } | |
754 | ||
755 | /** | |
756 | * mei_me_d0i3_unset - clean d0i3 register bit on mei device. | |
757 | * | |
758 | * @dev: the device structure | |
759 | * | |
760 | * Return: D0I3C register value | |
761 | */ | |
762 | static u32 mei_me_d0i3_unset(struct mei_device *dev) | |
763 | { | |
764 | u32 reg = mei_me_d0i3c_read(dev); | |
765 | ||
766 | reg &= ~H_D0I3C_I3; | |
767 | reg |= H_D0I3C_IR; | |
768 | mei_me_d0i3c_write(dev, reg); | |
769 | /* read it to ensure HW consistency */ | |
770 | reg = mei_me_d0i3c_read(dev); | |
771 | return reg; | |
772 | } | |
773 | ||
774 | /** | |
775 | * mei_me_d0i3_enter_sync - perform d0i3 entry procedure | |
776 | * | |
777 | * @dev: the device structure | |
778 | * | |
779 | * Return: 0 on success an error code otherwise | |
780 | */ | |
781 | static int mei_me_d0i3_enter_sync(struct mei_device *dev) | |
782 | { | |
783 | struct mei_me_hw *hw = to_me_hw(dev); | |
784 | unsigned long d0i3_timeout = mei_secs_to_jiffies(MEI_D0I3_TIMEOUT); | |
785 | unsigned long pgi_timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); | |
786 | int ret; | |
787 | u32 reg; | |
788 | ||
789 | reg = mei_me_d0i3c_read(dev); | |
790 | if (reg & H_D0I3C_I3) { | |
791 | /* we are in d0i3, nothing to do */ | |
792 | dev_dbg(dev->dev, "d0i3 set not needed\n"); | |
793 | ret = 0; | |
794 | goto on; | |
795 | } | |
796 | ||
797 | /* PGI entry procedure */ | |
798 | dev->pg_event = MEI_PG_EVENT_WAIT; | |
799 | ||
800 | ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_ENTRY_REQ_CMD); | |
801 | if (ret) | |
802 | /* FIXME: should we reset here? */ | |
803 | goto out; | |
804 | ||
805 | mutex_unlock(&dev->device_lock); | |
806 | wait_event_timeout(dev->wait_pg, | |
807 | dev->pg_event == MEI_PG_EVENT_RECEIVED, pgi_timeout); | |
808 | mutex_lock(&dev->device_lock); | |
809 | ||
810 | if (dev->pg_event != MEI_PG_EVENT_RECEIVED) { | |
811 | ret = -ETIME; | |
812 | goto out; | |
813 | } | |
814 | /* end PGI entry procedure */ | |
815 | ||
816 | dev->pg_event = MEI_PG_EVENT_INTR_WAIT; | |
817 | ||
818 | reg = mei_me_d0i3_set(dev, true); | |
819 | if (!(reg & H_D0I3C_CIP)) { | |
820 | dev_dbg(dev->dev, "d0i3 enter wait not needed\n"); | |
821 | ret = 0; | |
822 | goto on; | |
823 | } | |
824 | ||
825 | mutex_unlock(&dev->device_lock); | |
826 | wait_event_timeout(dev->wait_pg, | |
827 | dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED, d0i3_timeout); | |
828 | mutex_lock(&dev->device_lock); | |
829 | ||
830 | if (dev->pg_event != MEI_PG_EVENT_INTR_RECEIVED) { | |
831 | reg = mei_me_d0i3c_read(dev); | |
832 | if (!(reg & H_D0I3C_I3)) { | |
833 | ret = -ETIME; | |
834 | goto out; | |
835 | } | |
836 | } | |
837 | ||
838 | ret = 0; | |
839 | on: | |
840 | hw->pg_state = MEI_PG_ON; | |
841 | out: | |
842 | dev->pg_event = MEI_PG_EVENT_IDLE; | |
843 | dev_dbg(dev->dev, "d0i3 enter ret = %d\n", ret); | |
844 | return ret; | |
845 | } | |
846 | ||
847 | /** | |
848 | * mei_me_d0i3_enter - perform d0i3 entry procedure | |
849 | * no hbm PG handshake | |
850 | * no waiting for confirmation; runs with interrupts | |
851 | * disabled | |
852 | * | |
853 | * @dev: the device structure | |
854 | * | |
855 | * Return: 0 on success an error code otherwise | |
856 | */ | |
857 | static int mei_me_d0i3_enter(struct mei_device *dev) | |
858 | { | |
859 | struct mei_me_hw *hw = to_me_hw(dev); | |
860 | u32 reg; | |
861 | ||
862 | reg = mei_me_d0i3c_read(dev); | |
863 | if (reg & H_D0I3C_I3) { | |
864 | /* we are in d0i3, nothing to do */ | |
865 | dev_dbg(dev->dev, "already d0i3 : set not needed\n"); | |
866 | goto on; | |
867 | } | |
868 | ||
869 | mei_me_d0i3_set(dev, false); | |
870 | on: | |
871 | hw->pg_state = MEI_PG_ON; | |
872 | dev->pg_event = MEI_PG_EVENT_IDLE; | |
873 | dev_dbg(dev->dev, "d0i3 enter\n"); | |
874 | return 0; | |
875 | } | |
876 | ||
877 | /** | |
878 | * mei_me_d0i3_exit_sync - perform d0i3 exit procedure | |
879 | * | |
880 | * @dev: the device structure | |
881 | * | |
882 | * Return: 0 on success an error code otherwise | |
883 | */ | |
884 | static int mei_me_d0i3_exit_sync(struct mei_device *dev) | |
885 | { | |
886 | struct mei_me_hw *hw = to_me_hw(dev); | |
887 | unsigned long timeout = mei_secs_to_jiffies(MEI_D0I3_TIMEOUT); | |
888 | int ret; | |
889 | u32 reg; | |
890 | ||
891 | dev->pg_event = MEI_PG_EVENT_INTR_WAIT; | |
892 | ||
893 | reg = mei_me_d0i3c_read(dev); | |
894 | if (!(reg & H_D0I3C_I3)) { | |
895 | /* we are not in d0i3, nothing to do */ | |
896 | dev_dbg(dev->dev, "d0i3 exit not needed\n"); | |
897 | ret = 0; | |
898 | goto off; | |
899 | } | |
900 | ||
901 | reg = mei_me_d0i3_unset(dev); | |
902 | if (!(reg & H_D0I3C_CIP)) { | |
903 | dev_dbg(dev->dev, "d0i3 exit wait not needed\n"); | |
904 | ret = 0; | |
905 | goto off; | |
906 | } | |
907 | ||
908 | mutex_unlock(&dev->device_lock); | |
909 | wait_event_timeout(dev->wait_pg, | |
910 | dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED, timeout); | |
911 | mutex_lock(&dev->device_lock); | |
912 | ||
913 | if (dev->pg_event != MEI_PG_EVENT_INTR_RECEIVED) { | |
914 | reg = mei_me_d0i3c_read(dev); | |
915 | if (reg & H_D0I3C_I3) { | |
916 | ret = -ETIME; | |
917 | goto out; | |
918 | } | |
919 | } | |
920 | ||
921 | ret = 0; | |
922 | off: | |
923 | hw->pg_state = MEI_PG_OFF; | |
924 | out: | |
925 | dev->pg_event = MEI_PG_EVENT_IDLE; | |
926 | ||
927 | dev_dbg(dev->dev, "d0i3 exit ret = %d\n", ret); | |
928 | return ret; | |
929 | } | |
930 | ||
931 | /** | |
932 | * mei_me_pg_legacy_intr - perform legacy pg processing | |
933 | * in interrupt thread handler | |
934 | * | |
935 | * @dev: the device structure | |
936 | */ | |
937 | static void mei_me_pg_legacy_intr(struct mei_device *dev) | |
3dc196ea AU |
938 | { |
939 | struct mei_me_hw *hw = to_me_hw(dev); | |
940 | ||
941 | if (dev->pg_event != MEI_PG_EVENT_INTR_WAIT) | |
942 | return; | |
943 | ||
944 | dev->pg_event = MEI_PG_EVENT_INTR_RECEIVED; | |
945 | hw->pg_state = MEI_PG_OFF; | |
946 | if (waitqueue_active(&dev->wait_pg)) | |
947 | wake_up(&dev->wait_pg); | |
948 | } | |
949 | ||
859ef2ff AU |
950 | /** |
951 | * mei_me_d0i3_intr - perform d0i3 processing in interrupt thread handler | |
952 | * | |
953 | * @dev: the device structure | |
954 | */ | |
955 | static void mei_me_d0i3_intr(struct mei_device *dev) | |
956 | { | |
957 | struct mei_me_hw *hw = to_me_hw(dev); | |
958 | ||
959 | if (dev->pg_event == MEI_PG_EVENT_INTR_WAIT && | |
960 | (hw->intr_source & H_D0I3C_IS)) { | |
961 | dev->pg_event = MEI_PG_EVENT_INTR_RECEIVED; | |
962 | if (hw->pg_state == MEI_PG_ON) { | |
963 | hw->pg_state = MEI_PG_OFF; | |
964 | if (dev->hbm_state != MEI_HBM_IDLE) { | |
965 | /* | |
966 | * force H_RDY because it could be | |
967 | * wiped off during PG | |
968 | */ | |
969 | dev_dbg(dev->dev, "d0i3 set host ready\n"); | |
970 | mei_me_host_set_ready(dev); | |
971 | } | |
972 | } else { | |
973 | hw->pg_state = MEI_PG_ON; | |
974 | } | |
975 | ||
976 | wake_up(&dev->wait_pg); | |
977 | } | |
978 | ||
979 | if (hw->pg_state == MEI_PG_ON && (hw->intr_source & H_IS)) { | |
980 | /* | |
981 | * HW sent some data and we are in D0i3, so | |
982 | * we got here because of HW initiated exit from D0i3. | |
983 | * Start runtime pm resume sequence to exit low power state. | |
984 | */ | |
985 | dev_dbg(dev->dev, "d0i3 want resume\n"); | |
986 | mei_hbm_pg_resume(dev); | |
987 | } | |
988 | } | |
989 | ||
990 | /** | |
991 | * mei_me_pg_intr - perform pg processing in interrupt thread handler | |
992 | * | |
993 | * @dev: the device structure | |
994 | */ | |
995 | static void mei_me_pg_intr(struct mei_device *dev) | |
996 | { | |
997 | struct mei_me_hw *hw = to_me_hw(dev); | |
998 | ||
999 | if (hw->d0i3_supported) | |
1000 | mei_me_d0i3_intr(dev); | |
1001 | else | |
1002 | mei_me_pg_legacy_intr(dev); | |
1003 | } | |
1004 | ||
1005 | /** | |
1006 | * mei_me_pg_enter_sync - perform runtime pm entry procedure | |
1007 | * | |
1008 | * @dev: the device structure | |
1009 | * | |
1010 | * Return: 0 on success an error code otherwise | |
1011 | */ | |
1012 | int mei_me_pg_enter_sync(struct mei_device *dev) | |
1013 | { | |
1014 | struct mei_me_hw *hw = to_me_hw(dev); | |
1015 | ||
1016 | if (hw->d0i3_supported) | |
1017 | return mei_me_d0i3_enter_sync(dev); | |
1018 | else | |
1019 | return mei_me_pg_legacy_enter_sync(dev); | |
1020 | } | |
1021 | ||
1022 | /** | |
1023 | * mei_me_pg_exit_sync - perform runtime pm exit procedure | |
1024 | * | |
1025 | * @dev: the device structure | |
1026 | * | |
1027 | * Return: 0 on success an error code otherwise | |
1028 | */ | |
1029 | int mei_me_pg_exit_sync(struct mei_device *dev) | |
1030 | { | |
1031 | struct mei_me_hw *hw = to_me_hw(dev); | |
1032 | ||
1033 | if (hw->d0i3_supported) | |
1034 | return mei_me_d0i3_exit_sync(dev); | |
1035 | else | |
1036 | return mei_me_pg_legacy_exit_sync(dev); | |
1037 | } | |
1038 | ||
ebad6b94 AU |
1039 | /** |
1040 | * mei_me_hw_reset - resets fw via mei csr register. | |
1041 | * | |
1042 | * @dev: the device structure | |
1043 | * @intr_enable: if interrupt should be enabled after reset. | |
1044 | * | |
b9a1fc99 | 1045 | * Return: 0 on success an error code otherwise |
ebad6b94 AU |
1046 | */ |
1047 | static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) | |
1048 | { | |
b9a1fc99 AU |
1049 | struct mei_me_hw *hw = to_me_hw(dev); |
1050 | int ret; | |
1051 | u32 hcsr; | |
1052 | ||
1053 | if (intr_enable) { | |
1054 | mei_me_intr_enable(dev); | |
1055 | if (hw->d0i3_supported) { | |
1056 | ret = mei_me_d0i3_exit_sync(dev); | |
1057 | if (ret) | |
1058 | return ret; | |
1059 | } | |
1060 | } | |
ebad6b94 | 1061 | |
b9a1fc99 | 1062 | hcsr = mei_hcsr_read(dev); |
ebad6b94 AU |
1063 | /* H_RST may be found lit before reset is started, |
1064 | * for example if preceding reset flow hasn't completed. | |
1065 | * In that case asserting H_RST will be ignored, therefore | |
1066 | * we need to clean H_RST bit to start a successful reset sequence. | |
1067 | */ | |
1068 | if ((hcsr & H_RST) == H_RST) { | |
1069 | dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr); | |
1070 | hcsr &= ~H_RST; | |
1071 | mei_hcsr_set(dev, hcsr); | |
1072 | hcsr = mei_hcsr_read(dev); | |
1073 | } | |
1074 | ||
1075 | hcsr |= H_RST | H_IG | H_CSR_IS_MASK; | |
1076 | ||
b9a1fc99 | 1077 | if (!intr_enable) |
ebad6b94 AU |
1078 | hcsr &= ~H_CSR_IE_MASK; |
1079 | ||
1080 | dev->recvd_hw_ready = false; | |
1081 | mei_hcsr_write(dev, hcsr); | |
1082 | ||
1083 | /* | |
1084 | * Host reads the H_CSR once to ensure that the | |
1085 | * posted write to H_CSR completes. | |
1086 | */ | |
1087 | hcsr = mei_hcsr_read(dev); | |
1088 | ||
1089 | if ((hcsr & H_RST) == 0) | |
1090 | dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr); | |
1091 | ||
1092 | if ((hcsr & H_RDY) == H_RDY) | |
1093 | dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr); | |
1094 | ||
b9a1fc99 | 1095 | if (!intr_enable) { |
ebad6b94 | 1096 | mei_me_hw_reset_release(dev); |
b9a1fc99 AU |
1097 | if (hw->d0i3_supported) { |
1098 | ret = mei_me_d0i3_enter(dev); | |
1099 | if (ret) | |
1100 | return ret; | |
1101 | } | |
1102 | } | |
ebad6b94 AU |
1103 | return 0; |
1104 | } | |
1105 | ||
06ecd645 TW |
1106 | /** |
1107 | * mei_me_irq_quick_handler - The ISR of the MEI device | |
1108 | * | |
1109 | * @irq: The irq number | |
1110 | * @dev_id: pointer to the device structure | |
1111 | * | |
a8605ea2 | 1112 | * Return: irqreturn_t |
06ecd645 | 1113 | */ |
06ecd645 TW |
1114 | irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id) |
1115 | { | |
1fa55b4e AU |
1116 | struct mei_device *dev = (struct mei_device *)dev_id; |
1117 | struct mei_me_hw *hw = to_me_hw(dev); | |
1118 | u32 hcsr; | |
06ecd645 | 1119 | |
1fa55b4e AU |
1120 | hcsr = mei_hcsr_read(dev); |
1121 | if (!(hcsr & H_CSR_IS_MASK)) | |
06ecd645 TW |
1122 | return IRQ_NONE; |
1123 | ||
1fa55b4e AU |
1124 | hw->intr_source = hcsr & H_CSR_IS_MASK; |
1125 | dev_dbg(dev->dev, "interrupt source 0x%08X.\n", hw->intr_source); | |
1126 | ||
1127 | /* clear H_IS and H_D0I3C_IS bits in H_CSR to clear the interrupts */ | |
381a58c7 | 1128 | mei_hcsr_write(dev, hcsr); |
06ecd645 TW |
1129 | |
1130 | return IRQ_WAKE_THREAD; | |
1131 | } | |
1132 | ||
1133 | /** | |
1134 | * mei_me_irq_thread_handler - function called after ISR to handle the interrupt | |
1135 | * processing. | |
1136 | * | |
1137 | * @irq: The irq number | |
1138 | * @dev_id: pointer to the device structure | |
1139 | * | |
a8605ea2 | 1140 | * Return: irqreturn_t |
06ecd645 TW |
1141 | * |
1142 | */ | |
1143 | irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |
1144 | { | |
1145 | struct mei_device *dev = (struct mei_device *) dev_id; | |
1146 | struct mei_cl_cb complete_list; | |
06ecd645 | 1147 | s32 slots; |
544f9460 | 1148 | int rets = 0; |
06ecd645 | 1149 | |
2bf94cab | 1150 | dev_dbg(dev->dev, "function called after ISR to handle the interrupt processing.\n"); |
06ecd645 TW |
1151 | /* initialize our complete list */ |
1152 | mutex_lock(&dev->device_lock); | |
1153 | mei_io_list_init(&complete_list); | |
1154 | ||
06ecd645 | 1155 | /* check if ME wants a reset */ |
33ec0826 | 1156 | if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { |
2bf94cab | 1157 | dev_warn(dev->dev, "FW not ready: resetting.\n"); |
544f9460 TW |
1158 | schedule_work(&dev->reset_work); |
1159 | goto end; | |
06ecd645 TW |
1160 | } |
1161 | ||
3dc196ea AU |
1162 | mei_me_pg_intr(dev); |
1163 | ||
06ecd645 TW |
1164 | /* check if we need to start the dev */ |
1165 | if (!mei_host_is_ready(dev)) { | |
1166 | if (mei_hw_is_ready(dev)) { | |
2bf94cab | 1167 | dev_dbg(dev->dev, "we need to start the dev.\n"); |
aafae7ec | 1168 | dev->recvd_hw_ready = true; |
2c2b93ec | 1169 | wake_up(&dev->wait_hw_ready); |
06ecd645 | 1170 | } else { |
2bf94cab | 1171 | dev_dbg(dev->dev, "Spurious Interrupt\n"); |
06ecd645 | 1172 | } |
544f9460 | 1173 | goto end; |
06ecd645 TW |
1174 | } |
1175 | /* check slots available for reading */ | |
1176 | slots = mei_count_full_read_slots(dev); | |
1177 | while (slots > 0) { | |
2bf94cab | 1178 | dev_dbg(dev->dev, "slots to read = %08x\n", slots); |
06ecd645 | 1179 | rets = mei_irq_read_handler(dev, &complete_list, &slots); |
b1b94b5d TW |
1180 | /* There is a race between ME write and interrupt delivery: |
1181 | * Not all data is always available immediately after the | |
1182 | * interrupt, so try to read again on the next interrupt. | |
1183 | */ | |
1184 | if (rets == -ENODATA) | |
1185 | break; | |
1186 | ||
33ec0826 | 1187 | if (rets && dev->dev_state != MEI_DEV_RESETTING) { |
2bf94cab | 1188 | dev_err(dev->dev, "mei_irq_read_handler ret = %d.\n", |
b1b94b5d | 1189 | rets); |
544f9460 | 1190 | schedule_work(&dev->reset_work); |
06ecd645 | 1191 | goto end; |
544f9460 | 1192 | } |
06ecd645 | 1193 | } |
544f9460 | 1194 | |
6aae48ff TW |
1195 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); |
1196 | ||
ba9cdd0e TW |
1197 | /* |
1198 | * During PG handshake only allowed write is the replay to the | |
1199 | * PG exit message, so block calling write function | |
3dc196ea | 1200 | * if the pg event is in PG handshake |
ba9cdd0e | 1201 | */ |
3dc196ea AU |
1202 | if (dev->pg_event != MEI_PG_EVENT_WAIT && |
1203 | dev->pg_event != MEI_PG_EVENT_RECEIVED) { | |
ba9cdd0e TW |
1204 | rets = mei_irq_write_handler(dev, &complete_list); |
1205 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | |
1206 | } | |
06ecd645 | 1207 | |
4c6e22b8 | 1208 | mei_irq_compl_handler(dev, &complete_list); |
06ecd645 | 1209 | |
544f9460 | 1210 | end: |
2bf94cab | 1211 | dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets); |
544f9460 | 1212 | mutex_unlock(&dev->device_lock); |
06ecd645 TW |
1213 | return IRQ_HANDLED; |
1214 | } | |
04dd3661 | 1215 | |
827eef51 TW |
1216 | static const struct mei_hw_ops mei_me_hw_ops = { |
1217 | ||
1bd30b6a | 1218 | .fw_status = mei_me_fw_status, |
964a2331 TW |
1219 | .pg_state = mei_me_pg_state, |
1220 | ||
827eef51 TW |
1221 | .host_is_ready = mei_me_host_is_ready, |
1222 | ||
1223 | .hw_is_ready = mei_me_hw_is_ready, | |
1224 | .hw_reset = mei_me_hw_reset, | |
aafae7ec TW |
1225 | .hw_config = mei_me_hw_config, |
1226 | .hw_start = mei_me_hw_start, | |
827eef51 | 1227 | |
3dc196ea | 1228 | .pg_in_transition = mei_me_pg_in_transition, |
ee7e5afd TW |
1229 | .pg_is_enabled = mei_me_pg_is_enabled, |
1230 | ||
827eef51 TW |
1231 | .intr_clear = mei_me_intr_clear, |
1232 | .intr_enable = mei_me_intr_enable, | |
1233 | .intr_disable = mei_me_intr_disable, | |
1234 | ||
1235 | .hbuf_free_slots = mei_me_hbuf_empty_slots, | |
1236 | .hbuf_is_ready = mei_me_hbuf_is_empty, | |
1237 | .hbuf_max_len = mei_me_hbuf_max_len, | |
1238 | ||
1239 | .write = mei_me_write_message, | |
1240 | ||
1241 | .rdbuf_full_slots = mei_me_count_full_read_slots, | |
1242 | .read_hdr = mei_me_mecbrw_read, | |
1243 | .read = mei_me_read_slots | |
1244 | }; | |
1245 | ||
c919951d TW |
1246 | static bool mei_me_fw_type_nm(struct pci_dev *pdev) |
1247 | { | |
1248 | u32 reg; | |
92db1555 | 1249 | |
c919951d TW |
1250 | pci_read_config_dword(pdev, PCI_CFG_HFS_2, ®); |
1251 | /* make sure that bit 9 (NM) is up and bit 10 (DM) is down */ | |
1252 | return (reg & 0x600) == 0x200; | |
1253 | } | |
1254 | ||
1255 | #define MEI_CFG_FW_NM \ | |
1256 | .quirk_probe = mei_me_fw_type_nm | |
1257 | ||
1258 | static bool mei_me_fw_type_sps(struct pci_dev *pdev) | |
1259 | { | |
1260 | u32 reg; | |
1261 | /* Read ME FW Status check for SPS Firmware */ | |
1262 | pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); | |
1263 | /* if bits [19:16] = 15, running SPS Firmware */ | |
1264 | return (reg & 0xf0000) == 0xf0000; | |
1265 | } | |
1266 | ||
1267 | #define MEI_CFG_FW_SPS \ | |
1268 | .quirk_probe = mei_me_fw_type_sps | |
1269 | ||
1270 | ||
8d929d48 AU |
1271 | #define MEI_CFG_LEGACY_HFS \ |
1272 | .fw_status.count = 0 | |
1273 | ||
1274 | #define MEI_CFG_ICH_HFS \ | |
1275 | .fw_status.count = 1, \ | |
1276 | .fw_status.status[0] = PCI_CFG_HFS_1 | |
1277 | ||
1278 | #define MEI_CFG_PCH_HFS \ | |
1279 | .fw_status.count = 2, \ | |
1280 | .fw_status.status[0] = PCI_CFG_HFS_1, \ | |
1281 | .fw_status.status[1] = PCI_CFG_HFS_2 | |
1282 | ||
edca5ea3 AU |
1283 | #define MEI_CFG_PCH8_HFS \ |
1284 | .fw_status.count = 6, \ | |
1285 | .fw_status.status[0] = PCI_CFG_HFS_1, \ | |
1286 | .fw_status.status[1] = PCI_CFG_HFS_2, \ | |
1287 | .fw_status.status[2] = PCI_CFG_HFS_3, \ | |
1288 | .fw_status.status[3] = PCI_CFG_HFS_4, \ | |
1289 | .fw_status.status[4] = PCI_CFG_HFS_5, \ | |
1290 | .fw_status.status[5] = PCI_CFG_HFS_6 | |
8d929d48 AU |
1291 | |
1292 | /* ICH Legacy devices */ | |
1293 | const struct mei_cfg mei_me_legacy_cfg = { | |
1294 | MEI_CFG_LEGACY_HFS, | |
1295 | }; | |
1296 | ||
1297 | /* ICH devices */ | |
1298 | const struct mei_cfg mei_me_ich_cfg = { | |
1299 | MEI_CFG_ICH_HFS, | |
1300 | }; | |
1301 | ||
1302 | /* PCH devices */ | |
1303 | const struct mei_cfg mei_me_pch_cfg = { | |
1304 | MEI_CFG_PCH_HFS, | |
1305 | }; | |
1306 | ||
c919951d TW |
1307 | |
1308 | /* PCH Cougar Point and Patsburg with quirk for Node Manager exclusion */ | |
1309 | const struct mei_cfg mei_me_pch_cpt_pbg_cfg = { | |
1310 | MEI_CFG_PCH_HFS, | |
1311 | MEI_CFG_FW_NM, | |
1312 | }; | |
1313 | ||
edca5ea3 AU |
1314 | /* PCH8 Lynx Point and newer devices */ |
1315 | const struct mei_cfg mei_me_pch8_cfg = { | |
1316 | MEI_CFG_PCH8_HFS, | |
1317 | }; | |
1318 | ||
1319 | /* PCH8 Lynx Point with quirk for SPS Firmware exclusion */ | |
1320 | const struct mei_cfg mei_me_pch8_sps_cfg = { | |
1321 | MEI_CFG_PCH8_HFS, | |
c919951d TW |
1322 | MEI_CFG_FW_SPS, |
1323 | }; | |
1324 | ||
52c34561 | 1325 | /** |
393b148f | 1326 | * mei_me_dev_init - allocates and initializes the mei device structure |
52c34561 TW |
1327 | * |
1328 | * @pdev: The pci device structure | |
8d929d48 | 1329 | * @cfg: per device generation config |
52c34561 | 1330 | * |
a8605ea2 | 1331 | * Return: The mei_device_device pointer on success, NULL on failure. |
52c34561 | 1332 | */ |
8d929d48 AU |
1333 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev, |
1334 | const struct mei_cfg *cfg) | |
52c34561 TW |
1335 | { |
1336 | struct mei_device *dev; | |
4ad96db6 | 1337 | struct mei_me_hw *hw; |
52c34561 TW |
1338 | |
1339 | dev = kzalloc(sizeof(struct mei_device) + | |
1340 | sizeof(struct mei_me_hw), GFP_KERNEL); | |
1341 | if (!dev) | |
1342 | return NULL; | |
4ad96db6 | 1343 | hw = to_me_hw(dev); |
52c34561 | 1344 | |
3a7e9b6c | 1345 | mei_device_init(dev, &pdev->dev, &mei_me_hw_ops); |
4ad96db6 | 1346 | hw->cfg = cfg; |
52c34561 TW |
1347 | return dev; |
1348 | } | |
06ecd645 | 1349 |