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