diff options
Diffstat (limited to 'drivers/misc/mei/hw-txe.c')
-rw-r--r-- | drivers/misc/mei/hw-txe.c | 1106 |
1 files changed, 1106 insertions, 0 deletions
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c new file mode 100644 index 000000000000..19579e560dad --- /dev/null +++ b/drivers/misc/mei/hw-txe.c | |||
@@ -0,0 +1,1106 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | ||
4 | * Copyright (c) 2013-2014, Intel Corporation. | ||
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> | ||
18 | #include <linux/jiffies.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/kthread.h> | ||
21 | |||
22 | #include <linux/mei.h> | ||
23 | |||
24 | #include "mei_dev.h" | ||
25 | #include "hw-txe.h" | ||
26 | #include "client.h" | ||
27 | #include "hbm.h" | ||
28 | |||
29 | /** | ||
30 | * mei_txe_reg_read - Reads 32bit data from the device | ||
31 | * | ||
32 | * @base_addr: registers base address | ||
33 | * @offset: register offset | ||
34 | * | ||
35 | */ | ||
36 | static inline u32 mei_txe_reg_read(void __iomem *base_addr, | ||
37 | unsigned long offset) | ||
38 | { | ||
39 | return ioread32(base_addr + offset); | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * mei_txe_reg_write - Writes 32bit data to the device | ||
44 | * | ||
45 | * @base_addr: registers base address | ||
46 | * @offset: register offset | ||
47 | * @value: the value to write | ||
48 | */ | ||
49 | static inline void mei_txe_reg_write(void __iomem *base_addr, | ||
50 | unsigned long offset, u32 value) | ||
51 | { | ||
52 | iowrite32(value, base_addr + offset); | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR | ||
57 | * | ||
58 | * @dev: the device structure | ||
59 | * @offset: register offset | ||
60 | * | ||
61 | * Doesn't check for aliveness while Reads 32bit data from the SeC BAR | ||
62 | */ | ||
63 | static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw, | ||
64 | unsigned long offset) | ||
65 | { | ||
66 | return mei_txe_reg_read(hw->mem_addr[SEC_BAR], offset); | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR | ||
71 | * | ||
72 | * @dev: the device structure | ||
73 | * @offset: register offset | ||
74 | * | ||
75 | * Reads 32bit data from the SeC BAR and shout loud if aliveness is not set | ||
76 | */ | ||
77 | static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw, | ||
78 | unsigned long offset) | ||
79 | { | ||
80 | WARN(!hw->aliveness, "sec read: aliveness not asserted\n"); | ||
81 | return mei_txe_sec_reg_read_silent(hw, offset); | ||
82 | } | ||
83 | /** | ||
84 | * mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR | ||
85 | * doesn't check for aliveness | ||
86 | * | ||
87 | * @dev: the device structure | ||
88 | * @offset: register offset | ||
89 | * @value: value to write | ||
90 | * | ||
91 | * Doesn't check for aliveness while writes 32bit data from to the SeC BAR | ||
92 | */ | ||
93 | static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw, | ||
94 | unsigned long offset, u32 value) | ||
95 | { | ||
96 | mei_txe_reg_write(hw->mem_addr[SEC_BAR], offset, value); | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR | ||
101 | * | ||
102 | * @dev: the device structure | ||
103 | * @offset: register offset | ||
104 | * @value: value to write | ||
105 | * | ||
106 | * Writes 32bit data from the SeC BAR and shout loud if aliveness is not set | ||
107 | */ | ||
108 | static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw, | ||
109 | unsigned long offset, u32 value) | ||
110 | { | ||
111 | WARN(!hw->aliveness, "sec write: aliveness not asserted\n"); | ||
112 | mei_txe_sec_reg_write_silent(hw, offset, value); | ||
113 | } | ||
114 | /** | ||
115 | * mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR | ||
116 | * | ||
117 | * @hw: the device structure | ||
118 | * @offset: offset from which to read the data | ||
119 | * | ||
120 | */ | ||
121 | static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw, | ||
122 | unsigned long offset) | ||
123 | { | ||
124 | return mei_txe_reg_read(hw->mem_addr[BRIDGE_BAR], offset); | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR | ||
129 | * | ||
130 | * @hw: the device structure | ||
131 | * @offset: offset from which to write the data | ||
132 | * @value: the byte to write | ||
133 | */ | ||
134 | static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw, | ||
135 | unsigned long offset, u32 value) | ||
136 | { | ||
137 | mei_txe_reg_write(hw->mem_addr[BRIDGE_BAR], offset, value); | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * mei_txe_aliveness_set - request for aliveness change | ||
142 | * | ||
143 | * @dev: the device structure | ||
144 | * @req: requested aliveness value | ||
145 | * | ||
146 | * Request for aliveness change and returns true if the change is | ||
147 | * really needed and false if aliveness is already | ||
148 | * in the requested state | ||
149 | * Requires device lock to be held | ||
150 | */ | ||
151 | static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req) | ||
152 | { | ||
153 | |||
154 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
155 | bool do_req = hw->aliveness != req; | ||
156 | |||
157 | dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n", | ||
158 | hw->aliveness, req); | ||
159 | if (do_req) { | ||
160 | hw->recvd_aliveness = false; | ||
161 | mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req); | ||
162 | } | ||
163 | return do_req; | ||
164 | } | ||
165 | |||
166 | |||
167 | /** | ||
168 | * mei_txe_aliveness_req_get - get aliveness requested register value | ||
169 | * | ||
170 | * @dev: the device structure | ||
171 | * | ||
172 | * Extract HICR_HOST_ALIVENESS_RESP_ACK bit from | ||
173 | * from HICR_HOST_ALIVENESS_REQ register value | ||
174 | */ | ||
175 | static u32 mei_txe_aliveness_req_get(struct mei_device *dev) | ||
176 | { | ||
177 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
178 | u32 reg; | ||
179 | reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG); | ||
180 | return reg & SICR_HOST_ALIVENESS_REQ_REQUESTED; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * mei_txe_aliveness_get - get aliveness response register value | ||
185 | * @dev: the device structure | ||
186 | * | ||
187 | * Extract HICR_HOST_ALIVENESS_RESP_ACK bit | ||
188 | * from HICR_HOST_ALIVENESS_RESP register value | ||
189 | */ | ||
190 | static u32 mei_txe_aliveness_get(struct mei_device *dev) | ||
191 | { | ||
192 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
193 | u32 reg; | ||
194 | reg = mei_txe_br_reg_read(hw, HICR_HOST_ALIVENESS_RESP_REG); | ||
195 | return reg & HICR_HOST_ALIVENESS_RESP_ACK; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * mei_txe_aliveness_poll - waits for aliveness to settle | ||
200 | * | ||
201 | * @dev: the device structure | ||
202 | * @expected: expected aliveness value | ||
203 | * | ||
204 | * Polls for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set | ||
205 | * returns > 0 if the expected value was received, -ETIME otherwise | ||
206 | */ | ||
207 | static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected) | ||
208 | { | ||
209 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
210 | int t = 0; | ||
211 | |||
212 | do { | ||
213 | hw->aliveness = mei_txe_aliveness_get(dev); | ||
214 | if (hw->aliveness == expected) { | ||
215 | dev_dbg(&dev->pdev->dev, | ||
216 | "aliveness settled after %d msecs\n", t); | ||
217 | return t; | ||
218 | } | ||
219 | mutex_unlock(&dev->device_lock); | ||
220 | msleep(MSEC_PER_SEC / 5); | ||
221 | mutex_lock(&dev->device_lock); | ||
222 | t += MSEC_PER_SEC / 5; | ||
223 | } while (t < SEC_ALIVENESS_WAIT_TIMEOUT); | ||
224 | |||
225 | dev_err(&dev->pdev->dev, "aliveness timed out\n"); | ||
226 | return -ETIME; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * mei_txe_aliveness_wait - waits for aliveness to settle | ||
231 | * | ||
232 | * @dev: the device structure | ||
233 | * @expected: expected aliveness value | ||
234 | * | ||
235 | * Waits for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set | ||
236 | * returns returns 0 on success and < 0 otherwise | ||
237 | */ | ||
238 | static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected) | ||
239 | { | ||
240 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
241 | const unsigned long timeout = | ||
242 | msecs_to_jiffies(SEC_ALIVENESS_WAIT_TIMEOUT); | ||
243 | long err; | ||
244 | int ret; | ||
245 | |||
246 | hw->aliveness = mei_txe_aliveness_get(dev); | ||
247 | if (hw->aliveness == expected) | ||
248 | return 0; | ||
249 | |||
250 | mutex_unlock(&dev->device_lock); | ||
251 | err = wait_event_timeout(hw->wait_aliveness, | ||
252 | hw->recvd_aliveness, timeout); | ||
253 | mutex_lock(&dev->device_lock); | ||
254 | |||
255 | hw->aliveness = mei_txe_aliveness_get(dev); | ||
256 | ret = hw->aliveness == expected ? 0 : -ETIME; | ||
257 | |||
258 | if (ret) | ||
259 | dev_err(&dev->pdev->dev, "aliveness timed out"); | ||
260 | else | ||
261 | dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n", | ||
262 | jiffies_to_msecs(timeout - err)); | ||
263 | hw->recvd_aliveness = false; | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * mei_txe_aliveness_set_sync - sets an wait for aliveness to complete | ||
269 | * | ||
270 | * @dev: the device structure | ||
271 | * | ||
272 | * returns returns 0 on success and < 0 otherwise | ||
273 | */ | ||
274 | int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req) | ||
275 | { | ||
276 | if (mei_txe_aliveness_set(dev, req)) | ||
277 | return mei_txe_aliveness_wait(dev, req); | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt | ||
283 | * | ||
284 | * @dev: the device structure | ||
285 | */ | ||
286 | static void mei_txe_input_ready_interrupt_enable(struct mei_device *dev) | ||
287 | { | ||
288 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
289 | u32 hintmsk; | ||
290 | /* Enable the SEC_IPC_HOST_INT_MASK_IN_RDY interrupt */ | ||
291 | hintmsk = mei_txe_sec_reg_read(hw, SEC_IPC_HOST_INT_MASK_REG); | ||
292 | hintmsk |= SEC_IPC_HOST_INT_MASK_IN_RDY; | ||
293 | mei_txe_sec_reg_write(hw, SEC_IPC_HOST_INT_MASK_REG, hintmsk); | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * mei_txe_input_doorbell_set | ||
298 | * - Sets bit 0 in SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL. | ||
299 | * @dev: the device structure | ||
300 | */ | ||
301 | static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw) | ||
302 | { | ||
303 | /* Clear the interrupt cause */ | ||
304 | clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause); | ||
305 | mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_DOORBELL_REG, 1); | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * mei_txe_output_ready_set - Sets the SICR_SEC_IPC_OUTPUT_STATUS bit to 1 | ||
310 | * | ||
311 | * @dev: the device structure | ||
312 | */ | ||
313 | static void mei_txe_output_ready_set(struct mei_txe_hw *hw) | ||
314 | { | ||
315 | mei_txe_br_reg_write(hw, | ||
316 | SICR_SEC_IPC_OUTPUT_STATUS_REG, | ||
317 | SEC_IPC_OUTPUT_STATUS_RDY); | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * mei_txe_is_input_ready - check if TXE is ready for receiving data | ||
322 | * | ||
323 | * @dev: the device structure | ||
324 | */ | ||
325 | static bool mei_txe_is_input_ready(struct mei_device *dev) | ||
326 | { | ||
327 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
328 | u32 status; | ||
329 | status = mei_txe_sec_reg_read(hw, SEC_IPC_INPUT_STATUS_REG); | ||
330 | return !!(SEC_IPC_INPUT_STATUS_RDY & status); | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * mei_txe_intr_clear - clear all interrupts | ||
335 | * | ||
336 | * @dev: the device structure | ||
337 | */ | ||
338 | static inline void mei_txe_intr_clear(struct mei_device *dev) | ||
339 | { | ||
340 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
341 | mei_txe_sec_reg_write_silent(hw, SEC_IPC_HOST_INT_STATUS_REG, | ||
342 | SEC_IPC_HOST_INT_STATUS_PENDING); | ||
343 | mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_STS_MSK); | ||
344 | mei_txe_br_reg_write(hw, HHISR_REG, IPC_HHIER_MSK); | ||
345 | } | ||
346 | |||
347 | /** | ||
348 | * mei_txe_intr_disable - disable all interrupts | ||
349 | * | ||
350 | * @dev: the device structure | ||
351 | */ | ||
352 | static void mei_txe_intr_disable(struct mei_device *dev) | ||
353 | { | ||
354 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
355 | mei_txe_br_reg_write(hw, HHIER_REG, 0); | ||
356 | mei_txe_br_reg_write(hw, HIER_REG, 0); | ||
357 | } | ||
358 | /** | ||
359 | * mei_txe_intr_disable - enable all interrupts | ||
360 | * | ||
361 | * @dev: the device structure | ||
362 | */ | ||
363 | static void mei_txe_intr_enable(struct mei_device *dev) | ||
364 | { | ||
365 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
366 | mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK); | ||
367 | mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK); | ||
368 | } | ||
369 | |||
370 | /** | ||
371 | * mei_txe_pending_interrupts - check if there are pending interrupts | ||
372 | * only Aliveness, Input ready, and output doorbell are of relevance | ||
373 | * | ||
374 | * @dev: the device structure | ||
375 | * | ||
376 | * Checks if there are pending interrupts | ||
377 | * only Aliveness, Readiness, Input ready, and Output doorbell are relevant | ||
378 | */ | ||
379 | static bool mei_txe_pending_interrupts(struct mei_device *dev) | ||
380 | { | ||
381 | |||
382 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
383 | bool ret = (hw->intr_cause & (TXE_INTR_READINESS | | ||
384 | TXE_INTR_ALIVENESS | | ||
385 | TXE_INTR_IN_READY | | ||
386 | TXE_INTR_OUT_DB)); | ||
387 | |||
388 | if (ret) { | ||
389 | dev_dbg(&dev->pdev->dev, | ||
390 | "Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n", | ||
391 | !!(hw->intr_cause & TXE_INTR_IN_READY), | ||
392 | !!(hw->intr_cause & TXE_INTR_READINESS), | ||
393 | !!(hw->intr_cause & TXE_INTR_ALIVENESS), | ||
394 | !!(hw->intr_cause & TXE_INTR_OUT_DB)); | ||
395 | } | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * mei_txe_input_payload_write - write a dword to the host buffer | ||
401 | * at offset idx | ||
402 | * | ||
403 | * @dev: the device structure | ||
404 | * @idx: index in the host buffer | ||
405 | * @value: value | ||
406 | */ | ||
407 | static void mei_txe_input_payload_write(struct mei_device *dev, | ||
408 | unsigned long idx, u32 value) | ||
409 | { | ||
410 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
411 | mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_PAYLOAD_REG + | ||
412 | (idx * sizeof(u32)), value); | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * mei_txe_out_data_read - read dword from the device buffer | ||
417 | * at offset idx | ||
418 | * | ||
419 | * @dev: the device structure | ||
420 | * @idx: index in the device buffer | ||
421 | * | ||
422 | * returns register value at index | ||
423 | */ | ||
424 | static u32 mei_txe_out_data_read(const struct mei_device *dev, | ||
425 | unsigned long idx) | ||
426 | { | ||
427 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
428 | return mei_txe_br_reg_read(hw, | ||
429 | BRIDGE_IPC_OUTPUT_PAYLOAD_REG + (idx * sizeof(u32))); | ||
430 | } | ||
431 | |||
432 | /* Readiness */ | ||
433 | |||
434 | /** | ||
435 | * mei_txe_readiness_set_host_rdy | ||
436 | * | ||
437 | * @dev: the device structure | ||
438 | */ | ||
439 | static void mei_txe_readiness_set_host_rdy(struct mei_device *dev) | ||
440 | { | ||
441 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
442 | mei_txe_br_reg_write(hw, | ||
443 | SICR_HOST_IPC_READINESS_REQ_REG, | ||
444 | SICR_HOST_IPC_READINESS_HOST_RDY); | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * mei_txe_readiness_clear | ||
449 | * | ||
450 | * @dev: the device structure | ||
451 | */ | ||
452 | static void mei_txe_readiness_clear(struct mei_device *dev) | ||
453 | { | ||
454 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
455 | mei_txe_br_reg_write(hw, SICR_HOST_IPC_READINESS_REQ_REG, | ||
456 | SICR_HOST_IPC_READINESS_RDY_CLR); | ||
457 | } | ||
458 | /** | ||
459 | * mei_txe_readiness_get - Reads and returns | ||
460 | * the HICR_SEC_IPC_READINESS register value | ||
461 | * | ||
462 | * @dev: the device structure | ||
463 | */ | ||
464 | static u32 mei_txe_readiness_get(struct mei_device *dev) | ||
465 | { | ||
466 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
467 | return mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG); | ||
468 | } | ||
469 | |||
470 | |||
471 | /** | ||
472 | * mei_txe_readiness_is_sec_rdy - check readiness | ||
473 | * for HICR_SEC_IPC_READINESS_SEC_RDY | ||
474 | * | ||
475 | * @readiness - cached readiness state | ||
476 | */ | ||
477 | static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness) | ||
478 | { | ||
479 | return !!(readiness & HICR_SEC_IPC_READINESS_SEC_RDY); | ||
480 | } | ||
481 | |||
482 | /** | ||
483 | * mei_txe_hw_is_ready - check if the hw is ready | ||
484 | * | ||
485 | * @dev: the device structure | ||
486 | */ | ||
487 | static bool mei_txe_hw_is_ready(struct mei_device *dev) | ||
488 | { | ||
489 | u32 readiness = mei_txe_readiness_get(dev); | ||
490 | return mei_txe_readiness_is_sec_rdy(readiness); | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * mei_txe_host_is_ready - check if the host is ready | ||
495 | * | ||
496 | * @dev: the device structure | ||
497 | */ | ||
498 | static inline bool mei_txe_host_is_ready(struct mei_device *dev) | ||
499 | { | ||
500 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
501 | u32 reg = mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG); | ||
502 | return !!(reg & HICR_SEC_IPC_READINESS_HOST_RDY); | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * mei_txe_readiness_wait - wait till readiness settles | ||
507 | * | ||
508 | * @dev: the device structure | ||
509 | * | ||
510 | * returns 0 on success and -ETIME on timeout | ||
511 | */ | ||
512 | static int mei_txe_readiness_wait(struct mei_device *dev) | ||
513 | { | ||
514 | if (mei_txe_hw_is_ready(dev)) | ||
515 | return 0; | ||
516 | |||
517 | mutex_unlock(&dev->device_lock); | ||
518 | wait_event_timeout(dev->wait_hw_ready, dev->recvd_hw_ready, | ||
519 | msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT)); | ||
520 | mutex_lock(&dev->device_lock); | ||
521 | if (!dev->recvd_hw_ready) { | ||
522 | dev_err(&dev->pdev->dev, "wait for readiness failed\n"); | ||
523 | return -ETIME; | ||
524 | } | ||
525 | |||
526 | dev->recvd_hw_ready = false; | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * mei_txe_hw_config - configure hardware at the start of the devices | ||
532 | * | ||
533 | * @dev: the device structure | ||
534 | * | ||
535 | * Configure hardware at the start of the device should be done only | ||
536 | * once at the device probe time | ||
537 | */ | ||
538 | static void mei_txe_hw_config(struct mei_device *dev) | ||
539 | { | ||
540 | |||
541 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
542 | /* Doesn't change in runtime */ | ||
543 | dev->hbuf_depth = PAYLOAD_SIZE / 4; | ||
544 | |||
545 | hw->aliveness = mei_txe_aliveness_get(dev); | ||
546 | hw->readiness = mei_txe_readiness_get(dev); | ||
547 | |||
548 | dev_dbg(&dev->pdev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n", | ||
549 | hw->aliveness, hw->readiness); | ||
550 | } | ||
551 | |||
552 | |||
553 | /** | ||
554 | * mei_txe_write - writes a message to device. | ||
555 | * | ||
556 | * @dev: the device structure | ||
557 | * @header: header of message | ||
558 | * @buf: message buffer will be written | ||
559 | * returns 1 if success, 0 - otherwise. | ||
560 | */ | ||
561 | |||
562 | static int mei_txe_write(struct mei_device *dev, | ||
563 | struct mei_msg_hdr *header, unsigned char *buf) | ||
564 | { | ||
565 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
566 | unsigned long rem; | ||
567 | unsigned long length; | ||
568 | u32 *reg_buf = (u32 *)buf; | ||
569 | int i; | ||
570 | |||
571 | if (WARN_ON(!header || !buf)) | ||
572 | return -EINVAL; | ||
573 | |||
574 | length = header->length; | ||
575 | |||
576 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header)); | ||
577 | |||
578 | if ((length + sizeof(struct mei_msg_hdr)) > PAYLOAD_SIZE) { | ||
579 | dev_err(&dev->pdev->dev, "write length exceeded = %ld > %d\n", | ||
580 | length + sizeof(struct mei_msg_hdr), PAYLOAD_SIZE); | ||
581 | return -ERANGE; | ||
582 | } | ||
583 | |||
584 | if (WARN(!hw->aliveness, "txe write: aliveness not asserted\n")) | ||
585 | return -EAGAIN; | ||
586 | |||
587 | /* Enable Input Ready Interrupt. */ | ||
588 | mei_txe_input_ready_interrupt_enable(dev); | ||
589 | |||
590 | if (!mei_txe_is_input_ready(dev)) { | ||
591 | dev_err(&dev->pdev->dev, "Input is not ready"); | ||
592 | return -EAGAIN; | ||
593 | } | ||
594 | |||
595 | mei_txe_input_payload_write(dev, 0, *((u32 *)header)); | ||
596 | |||
597 | for (i = 0; i < length / 4; i++) | ||
598 | mei_txe_input_payload_write(dev, i + 1, reg_buf[i]); | ||
599 | |||
600 | rem = length & 0x3; | ||
601 | if (rem > 0) { | ||
602 | u32 reg = 0; | ||
603 | memcpy(®, &buf[length - rem], rem); | ||
604 | mei_txe_input_payload_write(dev, i + 1, reg); | ||
605 | } | ||
606 | |||
607 | dev->hbuf_is_ready = false; | ||
608 | /* Set Input-Doorbell */ | ||
609 | mei_txe_input_doorbell_set(hw); | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | /** | ||
615 | * mei_txe_hbuf_max_len - mimics the me hbuf circular buffer | ||
616 | * | ||
617 | * @dev: the device structure | ||
618 | * | ||
619 | * returns the PAYLOAD_SIZE - 4 | ||
620 | */ | ||
621 | static size_t mei_txe_hbuf_max_len(const struct mei_device *dev) | ||
622 | { | ||
623 | return PAYLOAD_SIZE - sizeof(struct mei_msg_hdr); | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * mei_txe_hbuf_empty_slots - mimics the me hbuf circular buffer | ||
628 | * | ||
629 | * @dev: the device structure | ||
630 | * | ||
631 | * returns always hbuf_depth | ||
632 | */ | ||
633 | static int mei_txe_hbuf_empty_slots(struct mei_device *dev) | ||
634 | { | ||
635 | return dev->hbuf_depth; | ||
636 | } | ||
637 | |||
638 | /** | ||
639 | * mei_txe_count_full_read_slots - mimics the me device circular buffer | ||
640 | * | ||
641 | * @dev: the device structure | ||
642 | * | ||
643 | * returns always buffer size in dwords count | ||
644 | */ | ||
645 | static int mei_txe_count_full_read_slots(struct mei_device *dev) | ||
646 | { | ||
647 | /* read buffers has static size */ | ||
648 | return PAYLOAD_SIZE / 4; | ||
649 | } | ||
650 | |||
651 | /** | ||
652 | * mei_txe_read_hdr - read message header which is always in 4 first bytes | ||
653 | * | ||
654 | * @dev: the device structure | ||
655 | * | ||
656 | * returns mei message header | ||
657 | */ | ||
658 | |||
659 | static u32 mei_txe_read_hdr(const struct mei_device *dev) | ||
660 | { | ||
661 | return mei_txe_out_data_read(dev, 0); | ||
662 | } | ||
663 | /** | ||
664 | * mei_txe_read - reads a message from the txe device. | ||
665 | * | ||
666 | * @dev: the device structure | ||
667 | * @buf: message buffer will be written | ||
668 | * @len: message size will be read | ||
669 | * | ||
670 | * returns -EINVAL on error wrong argument and 0 on success | ||
671 | */ | ||
672 | static int mei_txe_read(struct mei_device *dev, | ||
673 | unsigned char *buf, unsigned long len) | ||
674 | { | ||
675 | |||
676 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
677 | u32 i; | ||
678 | u32 *reg_buf = (u32 *)buf; | ||
679 | u32 rem = len & 0x3; | ||
680 | |||
681 | if (WARN_ON(!buf || !len)) | ||
682 | return -EINVAL; | ||
683 | |||
684 | dev_dbg(&dev->pdev->dev, | ||
685 | "buffer-length = %lu buf[0]0x%08X\n", | ||
686 | len, mei_txe_out_data_read(dev, 0)); | ||
687 | |||
688 | for (i = 0; i < len / 4; i++) { | ||
689 | /* skip header: index starts from 1 */ | ||
690 | u32 reg = mei_txe_out_data_read(dev, i + 1); | ||
691 | dev_dbg(&dev->pdev->dev, "buf[%d] = 0x%08X\n", i, reg); | ||
692 | *reg_buf++ = reg; | ||
693 | } | ||
694 | |||
695 | if (rem) { | ||
696 | u32 reg = mei_txe_out_data_read(dev, i + 1); | ||
697 | memcpy(reg_buf, ®, rem); | ||
698 | } | ||
699 | |||
700 | mei_txe_output_ready_set(hw); | ||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * mei_txe_hw_reset - resets host and fw. | ||
706 | * | ||
707 | * @dev: the device structure | ||
708 | * @intr_enable: if interrupt should be enabled after reset. | ||
709 | * | ||
710 | * returns 0 on success and < 0 in case of error | ||
711 | */ | ||
712 | static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable) | ||
713 | { | ||
714 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
715 | |||
716 | u32 aliveness_req; | ||
717 | /* | ||
718 | * read input doorbell to ensure consistency between Bridge and SeC | ||
719 | * return value might be garbage return | ||
720 | */ | ||
721 | (void)mei_txe_sec_reg_read_silent(hw, SEC_IPC_INPUT_DOORBELL_REG); | ||
722 | |||
723 | aliveness_req = mei_txe_aliveness_req_get(dev); | ||
724 | hw->aliveness = mei_txe_aliveness_get(dev); | ||
725 | |||
726 | /* Disable interrupts in this stage we will poll */ | ||
727 | mei_txe_intr_disable(dev); | ||
728 | |||
729 | /* | ||
730 | * If Aliveness Request and Aliveness Response are not equal then | ||
731 | * wait for them to be equal | ||
732 | * Since we might have interrupts disabled - poll for it | ||
733 | */ | ||
734 | if (aliveness_req != hw->aliveness) | ||
735 | if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) { | ||
736 | dev_err(&dev->pdev->dev, | ||
737 | "wait for aliveness settle failed ... bailing out\n"); | ||
738 | return -EIO; | ||
739 | } | ||
740 | |||
741 | /* | ||
742 | * If Aliveness Request and Aliveness Response are set then clear them | ||
743 | */ | ||
744 | if (aliveness_req) { | ||
745 | mei_txe_aliveness_set(dev, 0); | ||
746 | if (mei_txe_aliveness_poll(dev, 0) < 0) { | ||
747 | dev_err(&dev->pdev->dev, | ||
748 | "wait for aliveness failed ... bailing out\n"); | ||
749 | return -EIO; | ||
750 | } | ||
751 | } | ||
752 | |||
753 | /* | ||
754 | * Set rediness RDY_CLR bit | ||
755 | */ | ||
756 | mei_txe_readiness_clear(dev); | ||
757 | |||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | /** | ||
762 | * mei_txe_hw_start - start the hardware after reset | ||
763 | * | ||
764 | * @dev: the device structure | ||
765 | * | ||
766 | * returns 0 on success and < 0 in case of error | ||
767 | */ | ||
768 | static int mei_txe_hw_start(struct mei_device *dev) | ||
769 | { | ||
770 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
771 | int ret; | ||
772 | |||
773 | u32 hisr; | ||
774 | |||
775 | /* bring back interrupts */ | ||
776 | mei_txe_intr_enable(dev); | ||
777 | |||
778 | ret = mei_txe_readiness_wait(dev); | ||
779 | if (ret < 0) { | ||
780 | dev_err(&dev->pdev->dev, "wating for readiness failed\n"); | ||
781 | return ret; | ||
782 | } | ||
783 | |||
784 | /* | ||
785 | * If HISR.INT2_STS interrupt status bit is set then clear it. | ||
786 | */ | ||
787 | hisr = mei_txe_br_reg_read(hw, HISR_REG); | ||
788 | if (hisr & HISR_INT_2_STS) | ||
789 | mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_2_STS); | ||
790 | |||
791 | /* Clear the interrupt cause of OutputDoorbell */ | ||
792 | clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause); | ||
793 | |||
794 | ret = mei_txe_aliveness_set_sync(dev, 1); | ||
795 | if (ret < 0) { | ||
796 | dev_err(&dev->pdev->dev, "wait for aliveness failed ... bailing out\n"); | ||
797 | return ret; | ||
798 | } | ||
799 | |||
800 | /* enable input ready interrupts: | ||
801 | * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK | ||
802 | */ | ||
803 | mei_txe_input_ready_interrupt_enable(dev); | ||
804 | |||
805 | |||
806 | /* Set the SICR_SEC_IPC_OUTPUT_STATUS.IPC_OUTPUT_READY bit */ | ||
807 | mei_txe_output_ready_set(hw); | ||
808 | |||
809 | /* Set bit SICR_HOST_IPC_READINESS.HOST_RDY | ||
810 | */ | ||
811 | mei_txe_readiness_set_host_rdy(dev); | ||
812 | |||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | /** | ||
817 | * mei_txe_check_and_ack_intrs - translate multi BAR interrupt into | ||
818 | * single bit mask and acknowledge the interrupts | ||
819 | * | ||
820 | * @dev: the device structure | ||
821 | * @do_ack: acknowledge interrupts | ||
822 | */ | ||
823 | static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack) | ||
824 | { | ||
825 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
826 | u32 hisr; | ||
827 | u32 hhisr; | ||
828 | u32 ipc_isr; | ||
829 | u32 aliveness; | ||
830 | bool generated; | ||
831 | |||
832 | /* read interrupt registers */ | ||
833 | hhisr = mei_txe_br_reg_read(hw, HHISR_REG); | ||
834 | generated = (hhisr & IPC_HHIER_MSK); | ||
835 | if (!generated) | ||
836 | goto out; | ||
837 | |||
838 | hisr = mei_txe_br_reg_read(hw, HISR_REG); | ||
839 | |||
840 | aliveness = mei_txe_aliveness_get(dev); | ||
841 | if (hhisr & IPC_HHIER_SEC && aliveness) | ||
842 | ipc_isr = mei_txe_sec_reg_read_silent(hw, | ||
843 | SEC_IPC_HOST_INT_STATUS_REG); | ||
844 | else | ||
845 | ipc_isr = 0; | ||
846 | |||
847 | generated = generated || | ||
848 | (hisr & HISR_INT_STS_MSK) || | ||
849 | (ipc_isr & SEC_IPC_HOST_INT_STATUS_PENDING); | ||
850 | |||
851 | if (generated && do_ack) { | ||
852 | /* Save the interrupt causes */ | ||
853 | hw->intr_cause |= hisr & HISR_INT_STS_MSK; | ||
854 | if (ipc_isr & SEC_IPC_HOST_INT_STATUS_IN_RDY) | ||
855 | hw->intr_cause |= TXE_INTR_IN_READY; | ||
856 | |||
857 | |||
858 | mei_txe_intr_disable(dev); | ||
859 | /* Clear the interrupts in hierarchy: | ||
860 | * IPC and Bridge, than the High Level */ | ||
861 | mei_txe_sec_reg_write_silent(hw, | ||
862 | SEC_IPC_HOST_INT_STATUS_REG, ipc_isr); | ||
863 | mei_txe_br_reg_write(hw, HISR_REG, hisr); | ||
864 | mei_txe_br_reg_write(hw, HHISR_REG, hhisr); | ||
865 | } | ||
866 | |||
867 | out: | ||
868 | return generated; | ||
869 | } | ||
870 | |||
871 | /** | ||
872 | * mei_txe_irq_quick_handler - The ISR of the MEI device | ||
873 | * | ||
874 | * @irq: The irq number | ||
875 | * @dev_id: pointer to the device structure | ||
876 | * | ||
877 | * returns irqreturn_t | ||
878 | */ | ||
879 | irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id) | ||
880 | { | ||
881 | struct mei_device *dev = dev_id; | ||
882 | |||
883 | if (mei_txe_check_and_ack_intrs(dev, true)) | ||
884 | return IRQ_WAKE_THREAD; | ||
885 | return IRQ_NONE; | ||
886 | } | ||
887 | |||
888 | |||
889 | /** | ||
890 | * mei_txe_irq_thread_handler - txe interrupt thread | ||
891 | * | ||
892 | * @irq: The irq number | ||
893 | * @dev_id: pointer to the device structure | ||
894 | * | ||
895 | * returns irqreturn_t | ||
896 | * | ||
897 | */ | ||
898 | irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) | ||
899 | { | ||
900 | struct mei_device *dev = (struct mei_device *) dev_id; | ||
901 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
902 | struct mei_cl_cb complete_list; | ||
903 | s32 slots; | ||
904 | int rets = 0; | ||
905 | |||
906 | dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n", | ||
907 | mei_txe_br_reg_read(hw, HHISR_REG), | ||
908 | mei_txe_br_reg_read(hw, HISR_REG), | ||
909 | mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG)); | ||
910 | |||
911 | |||
912 | /* initialize our complete list */ | ||
913 | mutex_lock(&dev->device_lock); | ||
914 | mei_io_list_init(&complete_list); | ||
915 | |||
916 | if (pci_dev_msi_enabled(dev->pdev)) | ||
917 | mei_txe_check_and_ack_intrs(dev, true); | ||
918 | |||
919 | /* show irq events */ | ||
920 | mei_txe_pending_interrupts(dev); | ||
921 | |||
922 | hw->aliveness = mei_txe_aliveness_get(dev); | ||
923 | hw->readiness = mei_txe_readiness_get(dev); | ||
924 | |||
925 | /* Readiness: | ||
926 | * Detection of TXE driver going through reset | ||
927 | * or TXE driver resetting the HECI interface. | ||
928 | */ | ||
929 | if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) { | ||
930 | dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n"); | ||
931 | |||
932 | /* Check if SeC is going through reset */ | ||
933 | if (mei_txe_readiness_is_sec_rdy(hw->readiness)) { | ||
934 | dev_dbg(&dev->pdev->dev, "we need to start the dev.\n"); | ||
935 | dev->recvd_hw_ready = true; | ||
936 | } else { | ||
937 | dev->recvd_hw_ready = false; | ||
938 | if (dev->dev_state != MEI_DEV_RESETTING) { | ||
939 | |||
940 | dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n"); | ||
941 | schedule_work(&dev->reset_work); | ||
942 | goto end; | ||
943 | |||
944 | } | ||
945 | } | ||
946 | wake_up(&dev->wait_hw_ready); | ||
947 | } | ||
948 | |||
949 | /************************************************************/ | ||
950 | /* Check interrupt cause: | ||
951 | * Aliveness: Detection of SeC acknowledge of host request that | ||
952 | * it remain alive or host cancellation of that request. | ||
953 | */ | ||
954 | |||
955 | if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) { | ||
956 | /* Clear the interrupt cause */ | ||
957 | dev_dbg(&dev->pdev->dev, | ||
958 | "Aliveness Interrupt: Status: %d\n", hw->aliveness); | ||
959 | hw->recvd_aliveness = true; | ||
960 | if (waitqueue_active(&hw->wait_aliveness)) | ||
961 | wake_up(&hw->wait_aliveness); | ||
962 | } | ||
963 | |||
964 | |||
965 | /* Output Doorbell: | ||
966 | * Detection of SeC having sent output to host | ||
967 | */ | ||
968 | slots = mei_count_full_read_slots(dev); | ||
969 | if (test_and_clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause)) { | ||
970 | /* Read from TXE */ | ||
971 | rets = mei_irq_read_handler(dev, &complete_list, &slots); | ||
972 | if (rets && dev->dev_state != MEI_DEV_RESETTING) { | ||
973 | dev_err(&dev->pdev->dev, | ||
974 | "mei_irq_read_handler ret = %d.\n", rets); | ||
975 | |||
976 | schedule_work(&dev->reset_work); | ||
977 | goto end; | ||
978 | } | ||
979 | } | ||
980 | /* Input Ready: Detection if host can write to SeC */ | ||
981 | if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause)) | ||
982 | dev->hbuf_is_ready = true; | ||
983 | |||
984 | if (hw->aliveness && dev->hbuf_is_ready) { | ||
985 | /* if SeC did not complete reading the written data by host */ | ||
986 | if (!mei_txe_is_input_ready(dev)) { | ||
987 | dev_dbg(&dev->pdev->dev, "got Input Ready Int, but SEC_IPC_INPUT_STATUS_RDY is 0.\n"); | ||
988 | goto end; | ||
989 | } | ||
990 | |||
991 | rets = mei_irq_write_handler(dev, &complete_list); | ||
992 | if (rets) | ||
993 | dev_err(&dev->pdev->dev, | ||
994 | "mei_irq_write_handler ret = %d.\n", rets); | ||
995 | } | ||
996 | |||
997 | |||
998 | |||
999 | mei_irq_compl_handler(dev, &complete_list); | ||
1000 | |||
1001 | end: | ||
1002 | dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets); | ||
1003 | |||
1004 | mutex_unlock(&dev->device_lock); | ||
1005 | |||
1006 | mei_enable_interrupts(dev); | ||
1007 | return IRQ_HANDLED; | ||
1008 | } | ||
1009 | |||
1010 | static const struct mei_hw_ops mei_txe_hw_ops = { | ||
1011 | |||
1012 | .host_is_ready = mei_txe_host_is_ready, | ||
1013 | |||
1014 | .hw_is_ready = mei_txe_hw_is_ready, | ||
1015 | .hw_reset = mei_txe_hw_reset, | ||
1016 | .hw_config = mei_txe_hw_config, | ||
1017 | .hw_start = mei_txe_hw_start, | ||
1018 | |||
1019 | .intr_clear = mei_txe_intr_clear, | ||
1020 | .intr_enable = mei_txe_intr_enable, | ||
1021 | .intr_disable = mei_txe_intr_disable, | ||
1022 | |||
1023 | .hbuf_free_slots = mei_txe_hbuf_empty_slots, | ||
1024 | .hbuf_is_ready = mei_txe_is_input_ready, | ||
1025 | .hbuf_max_len = mei_txe_hbuf_max_len, | ||
1026 | |||
1027 | .write = mei_txe_write, | ||
1028 | |||
1029 | .rdbuf_full_slots = mei_txe_count_full_read_slots, | ||
1030 | .read_hdr = mei_txe_read_hdr, | ||
1031 | |||
1032 | .read = mei_txe_read, | ||
1033 | |||
1034 | }; | ||
1035 | |||
1036 | /** | ||
1037 | * mei_txe_dev_init - allocates and initializes txe hardware specific structure | ||
1038 | * | ||
1039 | * @pdev - pci device | ||
1040 | * returns struct mei_device * on success or NULL; | ||
1041 | * | ||
1042 | */ | ||
1043 | struct mei_device *mei_txe_dev_init(struct pci_dev *pdev) | ||
1044 | { | ||
1045 | struct mei_device *dev; | ||
1046 | struct mei_txe_hw *hw; | ||
1047 | |||
1048 | dev = kzalloc(sizeof(struct mei_device) + | ||
1049 | sizeof(struct mei_txe_hw), GFP_KERNEL); | ||
1050 | if (!dev) | ||
1051 | return NULL; | ||
1052 | |||
1053 | mei_device_init(dev); | ||
1054 | |||
1055 | hw = to_txe_hw(dev); | ||
1056 | |||
1057 | init_waitqueue_head(&hw->wait_aliveness); | ||
1058 | |||
1059 | dev->ops = &mei_txe_hw_ops; | ||
1060 | |||
1061 | dev->pdev = pdev; | ||
1062 | return dev; | ||
1063 | } | ||
1064 | |||
1065 | /** | ||
1066 | * mei_txe_setup_satt2 - SATT2 configuration for DMA support. | ||
1067 | * | ||
1068 | * @dev: the device structure | ||
1069 | * @addr: physical address start of the range | ||
1070 | * @range: physical range size | ||
1071 | */ | ||
1072 | int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range) | ||
1073 | { | ||
1074 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
1075 | |||
1076 | u32 lo32 = lower_32_bits(addr); | ||
1077 | u32 hi32 = upper_32_bits(addr); | ||
1078 | u32 ctrl; | ||
1079 | |||
1080 | /* SATT is limited to 36 Bits */ | ||
1081 | if (hi32 & ~0xF) | ||
1082 | return -EINVAL; | ||
1083 | |||
1084 | /* SATT has to be 16Byte aligned */ | ||
1085 | if (lo32 & 0xF) | ||
1086 | return -EINVAL; | ||
1087 | |||
1088 | /* SATT range has to be 4Bytes aligned */ | ||
1089 | if (range & 0x4) | ||
1090 | return -EINVAL; | ||
1091 | |||
1092 | /* SATT is limited to 32 MB range*/ | ||
1093 | if (range > SATT_RANGE_MAX) | ||
1094 | return -EINVAL; | ||
1095 | |||
1096 | ctrl = SATT2_CTRL_VALID_MSK; | ||
1097 | ctrl |= hi32 << SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT; | ||
1098 | |||
1099 | mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range); | ||
1100 | mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32); | ||
1101 | mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl); | ||
1102 | dev_dbg(&dev->pdev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n", | ||
1103 | range, lo32, ctrl); | ||
1104 | |||
1105 | return 0; | ||
1106 | } | ||