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