diff options
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 033c2846ce59..83b5f9cea85a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/acpi.h> | 16 | #include <linux/acpi.h> |
17 | #include "pci-quirks.h" | 17 | #include "pci-quirks.h" |
18 | #include "xhci-ext-caps.h" | ||
18 | 19 | ||
19 | 20 | ||
20 | #define UHCI_USBLEGSUP 0xc0 /* legacy support */ | 21 | #define UHCI_USBLEGSUP 0xc0 /* legacy support */ |
@@ -341,7 +342,127 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) | |||
341 | return; | 342 | return; |
342 | } | 343 | } |
343 | 344 | ||
345 | /* | ||
346 | * handshake - spin reading a register until handshake completes | ||
347 | * @ptr: address of hc register to be read | ||
348 | * @mask: bits to look at in result of read | ||
349 | * @done: value of those bits when handshake succeeds | ||
350 | * @wait_usec: timeout in microseconds | ||
351 | * @delay_usec: delay in microseconds to wait between polling | ||
352 | * | ||
353 | * Polls a register every delay_usec microseconds. | ||
354 | * Returns 0 when the mask bits have the value done. | ||
355 | * Returns -ETIMEDOUT if this condition is not true after | ||
356 | * wait_usec microseconds have passed. | ||
357 | */ | ||
358 | static int handshake(void __iomem *ptr, u32 mask, u32 done, | ||
359 | int wait_usec, int delay_usec) | ||
360 | { | ||
361 | u32 result; | ||
362 | |||
363 | do { | ||
364 | result = readl(ptr); | ||
365 | result &= mask; | ||
366 | if (result == done) | ||
367 | return 0; | ||
368 | udelay(delay_usec); | ||
369 | wait_usec -= delay_usec; | ||
370 | } while (wait_usec > 0); | ||
371 | return -ETIMEDOUT; | ||
372 | } | ||
373 | |||
374 | /** | ||
375 | * PCI Quirks for xHCI. | ||
376 | * | ||
377 | * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS. | ||
378 | * It signals to the BIOS that the OS wants control of the host controller, | ||
379 | * and then waits 5 seconds for the BIOS to hand over control. | ||
380 | * If we timeout, assume the BIOS is broken and take control anyway. | ||
381 | */ | ||
382 | static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | ||
383 | { | ||
384 | void __iomem *base; | ||
385 | int ext_cap_offset; | ||
386 | void __iomem *op_reg_base; | ||
387 | u32 val; | ||
388 | int timeout; | ||
389 | |||
390 | if (!mmio_resource_enabled(pdev, 0)) | ||
391 | return; | ||
392 | |||
393 | base = ioremap_nocache(pci_resource_start(pdev, 0), | ||
394 | pci_resource_len(pdev, 0)); | ||
395 | if (base == NULL) | ||
396 | return; | ||
344 | 397 | ||
398 | /* | ||
399 | * Find the Legacy Support Capability register - | ||
400 | * this is optional for xHCI host controllers. | ||
401 | */ | ||
402 | ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); | ||
403 | do { | ||
404 | if (!ext_cap_offset) | ||
405 | /* We've reached the end of the extended capabilities */ | ||
406 | goto hc_init; | ||
407 | val = readl(base + ext_cap_offset); | ||
408 | if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) | ||
409 | break; | ||
410 | ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset); | ||
411 | } while (1); | ||
412 | |||
413 | /* If the BIOS owns the HC, signal that the OS wants it, and wait */ | ||
414 | if (val & XHCI_HC_BIOS_OWNED) { | ||
415 | writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset); | ||
416 | |||
417 | /* Wait for 5 seconds with 10 microsecond polling interval */ | ||
418 | timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED, | ||
419 | 0, 5000, 10); | ||
420 | |||
421 | /* Assume a buggy BIOS and take HC ownership anyway */ | ||
422 | if (timeout) { | ||
423 | dev_warn(&pdev->dev, "xHCI BIOS handoff failed" | ||
424 | " (BIOS bug ?) %08x\n", val); | ||
425 | writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset); | ||
426 | } | ||
427 | } | ||
428 | |||
429 | /* Disable any BIOS SMIs */ | ||
430 | writel(XHCI_LEGACY_DISABLE_SMI, | ||
431 | base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); | ||
432 | |||
433 | hc_init: | ||
434 | op_reg_base = base + XHCI_HC_LENGTH(readl(base)); | ||
435 | |||
436 | /* Wait for the host controller to be ready before writing any | ||
437 | * operational or runtime registers. Wait 5 seconds and no more. | ||
438 | */ | ||
439 | timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0, | ||
440 | 5000, 10); | ||
441 | /* Assume a buggy HC and start HC initialization anyway */ | ||
442 | if (timeout) { | ||
443 | val = readl(op_reg_base + XHCI_STS_OFFSET); | ||
444 | dev_warn(&pdev->dev, | ||
445 | "xHCI HW not ready after 5 sec (HC bug?) " | ||
446 | "status = 0x%x\n", val); | ||
447 | } | ||
448 | |||
449 | /* Send the halt and disable interrupts command */ | ||
450 | val = readl(op_reg_base + XHCI_CMD_OFFSET); | ||
451 | val &= ~(XHCI_CMD_RUN | XHCI_IRQS); | ||
452 | writel(val, op_reg_base + XHCI_CMD_OFFSET); | ||
453 | |||
454 | /* Wait for the HC to halt - poll every 125 usec (one microframe). */ | ||
455 | timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1, | ||
456 | XHCI_MAX_HALT_USEC, 125); | ||
457 | if (timeout) { | ||
458 | val = readl(op_reg_base + XHCI_STS_OFFSET); | ||
459 | dev_warn(&pdev->dev, | ||
460 | "xHCI HW did not halt within %d usec " | ||
461 | "status = 0x%x\n", XHCI_MAX_HALT_USEC, val); | ||
462 | } | ||
463 | |||
464 | iounmap(base); | ||
465 | } | ||
345 | 466 | ||
346 | static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) | 467 | static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) |
347 | { | 468 | { |
@@ -351,5 +472,7 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) | |||
351 | quirk_usb_handoff_ohci(pdev); | 472 | quirk_usb_handoff_ohci(pdev); |
352 | else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI) | 473 | else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI) |
353 | quirk_usb_disable_ehci(pdev); | 474 | quirk_usb_disable_ehci(pdev); |
475 | else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) | ||
476 | quirk_usb_handoff_xhci(pdev); | ||
354 | } | 477 | } |
355 | DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); | 478 | DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); |