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