OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From 419992bae5aaa4e06402e0b7c79fcf7bcb6b4764 Mon Sep 17 00:00:00 2001 |
2 | From: Christian Lamparter <chunkeey@googlemail.com> |
||
3 | Date: Thu, 2 Jun 2016 00:48:46 +0200 |
||
4 | Subject: [PATCH] usb: xhci: add firmware loader for uPD720201 and uPD720202 |
||
5 | w/o ROM |
||
6 | |||
7 | This patch adds a firmware loader for the uPD720201K8-711-BAC-A |
||
8 | and uPD720202K8-711-BAA-A variant. Both of these chips are listed |
||
9 | in Renesas' R19UH0078EJ0500 Rev.5.00 "User's Manual: Hardware" as |
||
10 | devices which need the firmware loader on page 2 in order to |
||
11 | work as they "do not support the External ROM". |
||
12 | |||
13 | The "Firmware Download Sequence" is describe in chapter |
||
14 | "7.1 FW Download Interface" R19UH0078EJ0500 Rev.5.00 page 131. |
||
15 | |||
16 | The firmware "K2013080.mem" is available from a USB3.0 Host to |
||
17 | PCIe Adapter (PP2U-E card) "Firmware download" archive. An |
||
18 | alternative version can be sourced from Netgear's WNDR4700 GPL |
||
19 | archives. |
||
20 | |||
21 | The release notes of the PP2U-E's "Firmware Download" ver 2.0.1.3 |
||
22 | (2012-06-15) state that the firmware is for the following devices: |
||
23 | - uPD720201 ES 2.0 sample whose revision ID is 2. |
||
24 | - uPD720201 ES 2.1 sample & CS sample & Mass product, ID is 3. |
||
25 | - uPD720202 ES 2.0 sample & CS sample & Mass product, ID is 2. |
||
26 | |||
27 | If someone from Renesas is listening: It would be great, if these |
||
28 | firmwares could be added to linux-firmware.git. |
||
29 | |||
30 | Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> |
||
31 | Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> |
||
32 | --- |
||
33 | drivers/usb/host/xhci-pci.c | 492 ++++++++++++++++++++++++++++++++++++++++++++ |
||
34 | 1 file changed, 492 insertions(+) |
||
35 | |||
36 | --- a/drivers/usb/host/xhci-pci.c |
||
37 | +++ b/drivers/usb/host/xhci-pci.c |
||
38 | @@ -24,6 +24,8 @@ |
||
39 | #include <linux/slab.h> |
||
40 | #include <linux/module.h> |
||
41 | #include <linux/acpi.h> |
||
42 | +#include <linux/firmware.h> |
||
43 | +#include <asm/unaligned.h> |
||
44 | |||
45 | #include "xhci.h" |
||
46 | #include "xhci-trace.h" |
||
3 | office | 47 | @@ -255,6 +257,458 @@ static void xhci_pme_acpi_rtd3_enable(st |
1 | office | 48 | static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { } |
49 | #endif /* CONFIG_ACPI */ |
||
50 | |||
51 | +static const struct renesas_fw_entry { |
||
52 | + const char *firmware_name; |
||
53 | + u16 device; |
||
54 | + u8 revision; |
||
55 | + u16 expected_version; |
||
56 | +} renesas_fw_table[] = { |
||
57 | + /* |
||
58 | + * Only the uPD720201K8-711-BAC-A or uPD720202K8-711-BAA-A |
||
59 | + * are listed in R19UH0078EJ0500 Rev.5.00 as devices which |
||
60 | + * need the software loader. |
||
61 | + * |
||
62 | + * PP2U/ReleaseNote_USB3-201-202-FW.txt: |
||
63 | + * |
||
64 | + * Note: This firmware is for the following devices. |
||
65 | + * - uPD720201 ES 2.0 sample whose revision ID is 2. |
||
66 | + * - uPD720201 ES 2.1 sample & CS sample & Mass product, ID is 3. |
||
67 | + * - uPD720202 ES 2.0 sample & CS sample & Mass product, ID is 2. |
||
68 | + */ |
||
69 | + { "K2013080.mem", 0x0014, 0x02, 0x2013 }, |
||
70 | + { "K2013080.mem", 0x0014, 0x03, 0x2013 }, |
||
71 | + { "K2013080.mem", 0x0015, 0x02, 0x2013 }, |
||
72 | +}; |
||
73 | + |
||
74 | +static const struct renesas_fw_entry *renesas_needs_fw_dl(struct pci_dev *dev) |
||
75 | +{ |
||
76 | + const struct renesas_fw_entry *entry; |
||
77 | + size_t i; |
||
78 | + |
||
79 | + /* This loader will only work with a RENESAS device. */ |
||
80 | + if (!(dev->vendor == PCI_VENDOR_ID_RENESAS)) |
||
81 | + return NULL; |
||
82 | + |
||
83 | + for (i = 0; i < ARRAY_SIZE(renesas_fw_table); i++) { |
||
84 | + entry = &renesas_fw_table[i]; |
||
85 | + if (entry->device == dev->device && |
||
86 | + entry->revision == dev->revision) |
||
87 | + return entry; |
||
88 | + } |
||
89 | + |
||
90 | + return NULL; |
||
91 | +} |
||
92 | + |
||
93 | +static int renesas_fw_download_image(struct pci_dev *dev, |
||
94 | + const u32 *fw, |
||
95 | + size_t step) |
||
96 | +{ |
||
97 | + size_t i; |
||
98 | + int err; |
||
99 | + u8 fw_status; |
||
100 | + bool data0_or_data1; |
||
101 | + |
||
102 | + /* |
||
103 | + * The hardware does alternate between two 32-bit pages. |
||
104 | + * (This is because each row of the firmware is 8 bytes). |
||
105 | + * |
||
106 | + * for even steps we use DATA0, for odd steps DATA1. |
||
107 | + */ |
||
108 | + data0_or_data1 = (step & 1) == 1; |
||
109 | + |
||
110 | + /* step+1. Read "Set DATAX" and confirm it is cleared. */ |
||
111 | + for (i = 0; i < 10000; i++) { |
||
112 | + err = pci_read_config_byte(dev, 0xF5, &fw_status); |
||
113 | + if (err) |
||
114 | + return pcibios_err_to_errno(err); |
||
115 | + if (!(fw_status & BIT(data0_or_data1))) |
||
116 | + break; |
||
117 | + |
||
118 | + udelay(1); |
||
119 | + } |
||
120 | + if (i == 10000) |
||
121 | + return -ETIMEDOUT; |
||
122 | + |
||
123 | + /* |
||
124 | + * step+2. Write FW data to "DATAX". |
||
125 | + * "LSB is left" => force little endian |
||
126 | + */ |
||
127 | + err = pci_write_config_dword(dev, data0_or_data1 ? 0xFC : 0xF8, |
||
128 | + (__force u32) cpu_to_le32(fw[step])); |
||
129 | + if (err) |
||
130 | + return pcibios_err_to_errno(err); |
||
131 | + |
||
132 | + udelay(100); |
||
133 | + |
||
134 | + /* step+3. Set "Set DATAX". */ |
||
135 | + err = pci_write_config_byte(dev, 0xF5, BIT(data0_or_data1)); |
||
136 | + if (err) |
||
137 | + return pcibios_err_to_errno(err); |
||
138 | + |
||
139 | + return 0; |
||
140 | +} |
||
141 | + |
||
142 | +static int renesas_fw_verify(struct pci_dev *dev, |
||
143 | + const void *fw_data, |
||
144 | + size_t length) |
||
145 | +{ |
||
146 | + const struct renesas_fw_entry *entry = renesas_needs_fw_dl(dev); |
||
147 | + u16 fw_version_pointer; |
||
148 | + u16 fw_version; |
||
149 | + |
||
150 | + if (!entry) |
||
151 | + return -EINVAL; |
||
152 | + |
||
153 | + /* |
||
154 | + * The Firmware's Data Format is describe in |
||
155 | + * "6.3 Data Format" R19UH0078EJ0500 Rev.5.00 page 124 |
||
156 | + */ |
||
157 | + |
||
158 | + /* "Each row is 8 bytes". => firmware size must be a multiple of 8. */ |
||
159 | + if (length % 8 != 0) { |
||
160 | + dev_err(&dev->dev, "firmware size is not a multipe of 8."); |
||
161 | + return -EINVAL; |
||
162 | + } |
||
163 | + |
||
164 | + /* |
||
165 | + * The bootrom chips of the big brother have sizes up to 64k, let's |
||
166 | + * assume that's the biggest the firmware can get. |
||
167 | + */ |
||
168 | + if (length < 0x1000 || length >= 0x10000) { |
||
169 | + dev_err(&dev->dev, "firmware is size %zd is not (4k - 64k).", |
||
170 | + length); |
||
171 | + return -EINVAL; |
||
172 | + } |
||
173 | + |
||
174 | + /* The First 2 bytes are fixed value (55aa). "LSB on Left" */ |
||
175 | + if (get_unaligned_le16(fw_data) != 0x55aa) { |
||
176 | + dev_err(&dev->dev, "no valid firmware header found."); |
||
177 | + return -EINVAL; |
||
178 | + } |
||
179 | + |
||
180 | + /* verify the firmware version position and print it. */ |
||
181 | + fw_version_pointer = get_unaligned_le16(fw_data + 4); |
||
182 | + if (fw_version_pointer + 2 >= length) { |
||
183 | + dev_err(&dev->dev, "firmware version pointer is outside of the firmware image."); |
||
184 | + return -EINVAL; |
||
185 | + } |
||
186 | + |
||
187 | + fw_version = get_unaligned_le16(fw_data + fw_version_pointer); |
||
188 | + dev_dbg(&dev->dev, "got firmware version: %02x.", fw_version); |
||
189 | + |
||
190 | + if (fw_version != entry->expected_version) { |
||
191 | + dev_err(&dev->dev, "firmware version mismatch, expected version: %02x.", |
||
192 | + entry->expected_version); |
||
193 | + return -EINVAL; |
||
194 | + } |
||
195 | + |
||
196 | + return 0; |
||
197 | +} |
||
198 | + |
||
199 | +static int renesas_fw_check_running(struct pci_dev *pdev) |
||
200 | +{ |
||
201 | + int err; |
||
202 | + u8 fw_state; |
||
203 | + |
||
204 | + /* |
||
205 | + * Test if the device is actually needing the firmware. As most |
||
206 | + * BIOSes will initialize the device for us. If the device is |
||
207 | + * initialized. |
||
208 | + */ |
||
209 | + err = pci_read_config_byte(pdev, 0xF4, &fw_state); |
||
210 | + if (err) |
||
211 | + return pcibios_err_to_errno(err); |
||
212 | + |
||
213 | + /* |
||
214 | + * Check if "FW Download Lock" is locked. If it is and the FW is |
||
215 | + * ready we can simply continue. If the FW is not ready, we have |
||
216 | + * to give up. |
||
217 | + */ |
||
218 | + if (fw_state & BIT(1)) { |
||
219 | + dev_dbg(&pdev->dev, "FW Download Lock is engaged."); |
||
220 | + |
||
221 | + if (fw_state & BIT(4)) |
||
222 | + return 0; |
||
223 | + |
||
224 | + dev_err(&pdev->dev, "FW Download Lock is set and FW is not ready. Giving Up."); |
||
225 | + return -EIO; |
||
226 | + } |
||
227 | + |
||
228 | + /* |
||
229 | + * Check if "FW Download Enable" is set. If someone (us?) tampered |
||
230 | + * with it and it can't be resetted, we have to give up too... and |
||
231 | + * ask for a forgiveness and a reboot. |
||
232 | + */ |
||
233 | + if (fw_state & BIT(0)) { |
||
234 | + dev_err(&pdev->dev, "FW Download Enable is stale. Giving Up (poweroff/reboot needed)."); |
||
235 | + return -EIO; |
||
236 | + } |
||
237 | + |
||
238 | + /* Otherwise, Check the "Result Code" Bits (6:4) and act accordingly */ |
||
239 | + switch ((fw_state & 0x70)) { |
||
240 | + case 0: /* No result yet */ |
||
241 | + dev_dbg(&pdev->dev, "FW is not ready/loaded yet."); |
||
242 | + |
||
243 | + /* tell the caller, that this device needs the firmware. */ |
||
244 | + return 1; |
||
245 | + |
||
246 | + case BIT(4): /* Success, device should be working. */ |
||
247 | + dev_dbg(&pdev->dev, "FW is ready."); |
||
248 | + return 0; |
||
249 | + |
||
250 | + case BIT(5): /* Error State */ |
||
251 | + dev_err(&pdev->dev, "hardware is in an error state. Giving up (poweroff/reboot needed)."); |
||
252 | + return -ENODEV; |
||
253 | + |
||
254 | + default: /* All other states are marked as "Reserved states" */ |
||
255 | + dev_err(&pdev->dev, "hardware is in an invalid state %x. Giving up (poweroff/reboot needed).", |
||
256 | + (fw_state & 0x70) >> 4); |
||
257 | + return -EINVAL; |
||
258 | + } |
||
259 | +} |
||
260 | + |
||
261 | +static int renesas_hw_check_run_stop_busy(struct pci_dev *pdev) |
||
262 | +{ |
||
263 | +#if 0 |
||
264 | + u32 val; |
||
265 | + |
||
266 | + /* |
||
267 | + * 7.1.3 Note 3: "... must not set 'FW Download Enable' when |
||
268 | + * 'RUN/STOP' of USBCMD Register is set" |
||
269 | + */ |
||
270 | + val = readl(hcd->regs + 0x20); |
||
271 | + if (val & BIT(0)) { |
||
272 | + dev_err(&pdev->dev, "hardware is busy and can't receive a FW."); |
||
273 | + return -EBUSY; |
||
274 | + } |
||
275 | +#endif |
||
276 | + return 0; |
||
277 | +} |
||
278 | + |
||
279 | +static int renesas_fw_download(struct pci_dev *pdev, |
||
280 | + const struct firmware *fw, unsigned int retry_counter) |
||
281 | +{ |
||
282 | + const u32 *fw_data = (const u32 *) fw->data; |
||
283 | + size_t i; |
||
284 | + int err; |
||
285 | + u8 fw_status; |
||
286 | + |
||
287 | + /* |
||
288 | + * For more information and the big picture: please look at the |
||
289 | + * "Firmware Download Sequence" in "7.1 FW Download Interface" |
||
290 | + * of R19UH0078EJ0500 Rev.5.00 page 131 |
||
291 | + */ |
||
292 | + err = renesas_hw_check_run_stop_busy(pdev); |
||
293 | + if (err) |
||
294 | + return err; |
||
295 | + |
||
296 | + /* |
||
297 | + * 0. Set "FW Download Enable" bit in the |
||
298 | + * "FW Download Control & Status Register" at 0xF4 |
||
299 | + */ |
||
300 | + err = pci_write_config_byte(pdev, 0xF4, BIT(0)); |
||
301 | + if (err) |
||
302 | + return pcibios_err_to_errno(err); |
||
303 | + |
||
304 | + /* 1 - 10 follow one step after the other. */ |
||
305 | + for (i = 0; i < fw->size / 4; i++) { |
||
306 | + err = renesas_fw_download_image(pdev, fw_data, i); |
||
307 | + if (err) { |
||
308 | + dev_err(&pdev->dev, "Firmware Download Step %zd failed at position %zd bytes with (%d).", |
||
309 | + i, i * 4, err); |
||
310 | + return err; |
||
311 | + } |
||
312 | + } |
||
313 | + |
||
314 | + /* |
||
315 | + * This sequence continues until the last data is written to |
||
316 | + * "DATA0" or "DATA1". Naturally, we wait until "SET DATA0/1" |
||
317 | + * is cleared by the hardware beforehand. |
||
318 | + */ |
||
319 | + for (i = 0; i < 10000; i++) { |
||
320 | + err = pci_read_config_byte(pdev, 0xF5, &fw_status); |
||
321 | + if (err) |
||
322 | + return pcibios_err_to_errno(err); |
||
323 | + if (!(fw_status & (BIT(0) | BIT(1)))) |
||
324 | + break; |
||
325 | + |
||
326 | + udelay(1); |
||
327 | + } |
||
328 | + if (i == 10000) |
||
329 | + dev_warn(&pdev->dev, "Final Firmware Download step timed out."); |
||
330 | + |
||
331 | + /* |
||
332 | + * 11. After finishing writing the last data of FW, the |
||
333 | + * System Software must clear "FW Download Enable" |
||
334 | + */ |
||
335 | + err = pci_write_config_byte(pdev, 0xF4, 0); |
||
336 | + if (err) |
||
337 | + return pcibios_err_to_errno(err); |
||
338 | + |
||
339 | + /* 12. Read "Result Code" and confirm it is good. */ |
||
340 | + for (i = 0; i < 10000; i++) { |
||
341 | + err = pci_read_config_byte(pdev, 0xF4, &fw_status); |
||
342 | + if (err) |
||
343 | + return pcibios_err_to_errno(err); |
||
344 | + if (fw_status & BIT(4)) |
||
345 | + break; |
||
346 | + |
||
347 | + udelay(1); |
||
348 | + } |
||
349 | + if (i == 10000) { |
||
350 | + /* Timed out / Error - let's see if we can fix this */ |
||
351 | + err = renesas_fw_check_running(pdev); |
||
352 | + switch (err) { |
||
353 | + case 0: /* |
||
354 | + * we shouldn't end up here. |
||
355 | + * maybe it took a little bit longer. |
||
356 | + * But all should be well? |
||
357 | + */ |
||
358 | + break; |
||
359 | + |
||
360 | + case 1: /* (No result yet? - we can try to retry) */ |
||
361 | + if (retry_counter < 10) { |
||
362 | + retry_counter++; |
||
363 | + dev_warn(&pdev->dev, "Retry Firmware download: %d try.", |
||
364 | + retry_counter); |
||
365 | + return renesas_fw_download(pdev, fw, |
||
366 | + retry_counter); |
||
367 | + } |
||
368 | + return -ETIMEDOUT; |
||
369 | + |
||
370 | + default: |
||
371 | + return err; |
||
372 | + } |
||
373 | + } |
||
374 | + /* |
||
375 | + * Optional last step: Engage Firmware Lock |
||
376 | + * |
||
377 | + * err = pci_write_config_byte(pdev, 0xF4, BIT(2)); |
||
378 | + * if (err) |
||
379 | + * return pcibios_err_to_errno(err); |
||
380 | + */ |
||
381 | + |
||
382 | + return 0; |
||
383 | +} |
||
384 | + |
||
385 | +struct renesas_fw_ctx { |
||
386 | + struct pci_dev *pdev; |
||
387 | + const struct pci_device_id *id; |
||
388 | + bool resume; |
||
389 | +}; |
||
390 | + |
||
391 | +static int xhci_pci_probe(struct pci_dev *pdev, |
||
392 | + const struct pci_device_id *id); |
||
393 | + |
||
394 | +static void renesas_fw_callback(const struct firmware *fw, |
||
395 | + void *context) |
||
396 | +{ |
||
397 | + struct renesas_fw_ctx *ctx = context; |
||
398 | + struct pci_dev *pdev = ctx->pdev; |
||
399 | + struct device *parent = pdev->dev.parent; |
||
400 | + int err = -ENOENT; |
||
401 | + |
||
402 | + if (fw) { |
||
403 | + err = renesas_fw_verify(pdev, fw->data, fw->size); |
||
404 | + if (!err) { |
||
405 | + err = renesas_fw_download(pdev, fw, 0); |
||
406 | + release_firmware(fw); |
||
407 | + if (!err) { |
||
408 | + if (ctx->resume) |
||
409 | + return; |
||
410 | + |
||
411 | + err = xhci_pci_probe(pdev, ctx->id); |
||
412 | + if (!err) { |
||
413 | + /* everything worked */ |
||
414 | + devm_kfree(&pdev->dev, ctx); |
||
415 | + return; |
||
416 | + } |
||
417 | + |
||
418 | + /* in case of an error - fall through */ |
||
419 | + } else { |
||
420 | + dev_err(&pdev->dev, "firmware failed to download (%d).", |
||
421 | + err); |
||
422 | + } |
||
423 | + } |
||
424 | + } else { |
||
425 | + dev_err(&pdev->dev, "firmware failed to load (%d).", err); |
||
426 | + } |
||
427 | + |
||
428 | + dev_info(&pdev->dev, "Unloading driver"); |
||
429 | + |
||
430 | + if (parent) |
||
431 | + device_lock(parent); |
||
432 | + |
||
433 | + device_release_driver(&pdev->dev); |
||
434 | + |
||
435 | + if (parent) |
||
436 | + device_unlock(parent); |
||
437 | + |
||
438 | + pci_dev_put(pdev); |
||
439 | +} |
||
440 | + |
||
441 | +static int renesas_fw_alive_check(struct pci_dev *pdev) |
||
442 | +{ |
||
443 | + const struct renesas_fw_entry *entry; |
||
444 | + int err; |
||
445 | + |
||
446 | + /* check if we have a eligible RENESAS' uPD720201/2 w/o FW. */ |
||
447 | + entry = renesas_needs_fw_dl(pdev); |
||
448 | + if (!entry) |
||
449 | + return 0; |
||
450 | + |
||
451 | + err = renesas_fw_check_running(pdev); |
||
452 | + /* Also go ahead, if the firmware is running */ |
||
453 | + if (err == 0) |
||
454 | + return 0; |
||
455 | + |
||
456 | + /* At this point, we can be sure that the FW isn't ready. */ |
||
457 | + return err; |
||
458 | +} |
||
459 | + |
||
460 | +static int renesas_fw_download_to_hw(struct pci_dev *pdev, |
||
461 | + const struct pci_device_id *id, |
||
462 | + bool do_resume) |
||
463 | +{ |
||
464 | + const struct renesas_fw_entry *entry; |
||
465 | + struct renesas_fw_ctx *ctx; |
||
466 | + int err; |
||
467 | + |
||
468 | + /* check if we have a eligible RENESAS' uPD720201/2 w/o FW. */ |
||
469 | + entry = renesas_needs_fw_dl(pdev); |
||
470 | + if (!entry) |
||
471 | + return 0; |
||
472 | + |
||
473 | + err = renesas_fw_check_running(pdev); |
||
474 | + /* Continue ahead, if the firmware is already running. */ |
||
475 | + if (err == 0) |
||
476 | + return 0; |
||
477 | + |
||
478 | + if (err != 1) |
||
479 | + return err; |
||
480 | + |
||
481 | + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
||
482 | + if (!ctx) |
||
483 | + return -ENOMEM; |
||
484 | + ctx->pdev = pdev; |
||
485 | + ctx->resume = do_resume; |
||
486 | + ctx->id = id; |
||
487 | + |
||
488 | + pci_dev_get(pdev); |
||
489 | + err = request_firmware_nowait(THIS_MODULE, 1, entry->firmware_name, |
||
490 | + &pdev->dev, GFP_KERNEL, ctx, renesas_fw_callback); |
||
491 | + if (err) { |
||
492 | + pci_dev_put(pdev); |
||
493 | + return err; |
||
494 | + } |
||
495 | + |
||
496 | + /* |
||
497 | + * The renesas_fw_callback() callback will continue the probe |
||
498 | + * process, once it aquires the firmware. |
||
499 | + */ |
||
500 | + return 1; |
||
501 | +} |
||
502 | + |
||
503 | /* called during probe() after chip reset completes */ |
||
504 | static int xhci_pci_setup(struct usb_hcd *hcd) |
||
505 | { |
||
3 | office | 506 | @@ -290,6 +744,22 @@ static int xhci_pci_probe(struct pci_dev |
1 | office | 507 | struct hc_driver *driver; |
508 | struct usb_hcd *hcd; |
||
509 | |||
510 | + /* |
||
511 | + * Check if this device is a RENESAS uPD720201/2 device. |
||
512 | + * Otherwise, we can continue with xhci_pci_probe as usual. |
||
513 | + */ |
||
514 | + retval = renesas_fw_download_to_hw(dev, id, false); |
||
515 | + switch (retval) { |
||
516 | + case 0: |
||
517 | + break; |
||
518 | + |
||
519 | + case 1: /* let it load the firmware and recontinue the probe. */ |
||
520 | + return 0; |
||
521 | + |
||
522 | + default: |
||
523 | + return retval; |
||
524 | + }; |
||
525 | + |
||
526 | driver = (struct hc_driver *)id->driver_data; |
||
527 | |||
528 | /* For some HW implementation, a XHCI reset is just not enough... */ |
||
3 | office | 529 | @@ -354,6 +824,16 @@ static void xhci_pci_remove(struct pci_d |
1 | office | 530 | { |
531 | struct xhci_hcd *xhci; |
||
532 | |||
533 | + if (renesas_fw_alive_check(dev)) { |
||
534 | + /* |
||
535 | + * bail out early, if this was a renesas device w/o FW. |
||
536 | + * Else we might hit the NMI watchdog in xhci_handsake |
||
537 | + * during xhci_reset as part of the driver's unloading. |
||
538 | + * which we forced in the renesas_fw_callback(). |
||
539 | + */ |
||
540 | + return; |
||
541 | + } |
||
542 | + |
||
543 | xhci = hcd_to_xhci(pci_get_drvdata(dev)); |
||
544 | xhci->xhc_state |= XHCI_STATE_REMOVING; |
||
545 | if (xhci->shared_hcd) { |