diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/ehci-pci.c | 39 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 63 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 20 |
4 files changed, 124 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 660b80a75cac..1102ce65a3a9 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c | |||
@@ -348,11 +348,50 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
348 | return rc; | 348 | return rc; |
349 | } | 349 | } |
350 | 350 | ||
351 | static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) | ||
352 | { | ||
353 | return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && | ||
354 | pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
355 | pdev->device == 0x1E26; | ||
356 | } | ||
357 | |||
358 | static void ehci_enable_xhci_companion(void) | ||
359 | { | ||
360 | struct pci_dev *companion = NULL; | ||
361 | |||
362 | /* The xHCI and EHCI controllers are not on the same PCI slot */ | ||
363 | for_each_pci_dev(companion) { | ||
364 | if (!usb_is_intel_switchable_xhci(companion)) | ||
365 | continue; | ||
366 | usb_enable_xhci_ports(companion); | ||
367 | return; | ||
368 | } | ||
369 | } | ||
370 | |||
351 | static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) | 371 | static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) |
352 | { | 372 | { |
353 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 373 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
354 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | 374 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); |
355 | 375 | ||
376 | /* The BIOS on systems with the Intel Panther Point chipset may or may | ||
377 | * not support xHCI natively. That means that during system resume, it | ||
378 | * may switch the ports back to EHCI so that users can use their | ||
379 | * keyboard to select a kernel from GRUB after resume from hibernate. | ||
380 | * | ||
381 | * The BIOS is supposed to remember whether the OS had xHCI ports | ||
382 | * enabled before resume, and switch the ports back to xHCI when the | ||
383 | * BIOS/OS semaphore is written, but we all know we can't trust BIOS | ||
384 | * writers. | ||
385 | * | ||
386 | * Unconditionally switch the ports back to xHCI after a system resume. | ||
387 | * We can't tell whether the EHCI or xHCI controller will be resumed | ||
388 | * first, so we have to do the port switchover in both drivers. Writing | ||
389 | * a '1' to the port switchover registers should have no effect if the | ||
390 | * port was already switched over. | ||
391 | */ | ||
392 | if (usb_is_intel_switchable_ehci(pdev)) | ||
393 | ehci_enable_xhci_companion(); | ||
394 | |||
356 | // maybe restore FLADJ | 395 | // maybe restore FLADJ |
357 | 396 | ||
358 | if (time_before(jiffies, ehci->next_statechange)) | 397 | if (time_before(jiffies, ehci->next_statechange)) |
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index f16c59d5f487..fd930618c28f 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
@@ -69,6 +69,9 @@ | |||
69 | #define NB_PIF0_PWRDOWN_0 0x01100012 | 69 | #define NB_PIF0_PWRDOWN_0 0x01100012 |
70 | #define NB_PIF0_PWRDOWN_1 0x01100013 | 70 | #define NB_PIF0_PWRDOWN_1 0x01100013 |
71 | 71 | ||
72 | #define USB_INTEL_XUSB2PR 0xD0 | ||
73 | #define USB_INTEL_USB3_PSSEN 0xD8 | ||
74 | |||
72 | static struct amd_chipset_info { | 75 | static struct amd_chipset_info { |
73 | struct pci_dev *nb_dev; | 76 | struct pci_dev *nb_dev; |
74 | struct pci_dev *smbus_dev; | 77 | struct pci_dev *smbus_dev; |
@@ -673,6 +676,64 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, | |||
673 | return -ETIMEDOUT; | 676 | return -ETIMEDOUT; |
674 | } | 677 | } |
675 | 678 | ||
679 | bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) | ||
680 | { | ||
681 | return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && | ||
682 | pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
683 | pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; | ||
684 | } | ||
685 | EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); | ||
686 | |||
687 | /* | ||
688 | * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that | ||
689 | * share some number of ports. These ports can be switched between either | ||
690 | * controller. Not all of the ports under the EHCI host controller may be | ||
691 | * switchable. | ||
692 | * | ||
693 | * The ports should be switched over to xHCI before PCI probes for any device | ||
694 | * start. This avoids active devices under EHCI being disconnected during the | ||
695 | * port switchover, which could cause loss of data on USB storage devices, or | ||
696 | * failed boot when the root file system is on a USB mass storage device and is | ||
697 | * enumerated under EHCI first. | ||
698 | * | ||
699 | * We write into the xHC's PCI configuration space in some Intel-specific | ||
700 | * registers to switch the ports over. The USB 3.0 terminations and the USB | ||
701 | * 2.0 data wires are switched separately. We want to enable the SuperSpeed | ||
702 | * terminations before switching the USB 2.0 wires over, so that USB 3.0 | ||
703 | * devices connect at SuperSpeed, rather than at USB 2.0 speeds. | ||
704 | */ | ||
705 | void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) | ||
706 | { | ||
707 | u32 ports_available; | ||
708 | |||
709 | ports_available = 0xffffffff; | ||
710 | /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable | ||
711 | * Register, to turn on SuperSpeed terminations for all | ||
712 | * available ports. | ||
713 | */ | ||
714 | pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, | ||
715 | cpu_to_le32(ports_available)); | ||
716 | |||
717 | pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, | ||
718 | &ports_available); | ||
719 | dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled " | ||
720 | "under xHCI: 0x%x\n", ports_available); | ||
721 | |||
722 | ports_available = 0xffffffff; | ||
723 | /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to | ||
724 | * switch the USB 2.0 power and data lines over to the xHCI | ||
725 | * host. | ||
726 | */ | ||
727 | pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, | ||
728 | cpu_to_le32(ports_available)); | ||
729 | |||
730 | pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, | ||
731 | &ports_available); | ||
732 | dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over " | ||
733 | "to xHCI: 0x%x\n", ports_available); | ||
734 | } | ||
735 | EXPORT_SYMBOL_GPL(usb_enable_xhci_ports); | ||
736 | |||
676 | /** | 737 | /** |
677 | * PCI Quirks for xHCI. | 738 | * PCI Quirks for xHCI. |
678 | * | 739 | * |
@@ -732,6 +793,8 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | |||
732 | writel(XHCI_LEGACY_DISABLE_SMI, | 793 | writel(XHCI_LEGACY_DISABLE_SMI, |
733 | base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); | 794 | base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); |
734 | 795 | ||
796 | if (usb_is_intel_switchable_xhci(pdev)) | ||
797 | usb_enable_xhci_ports(pdev); | ||
735 | hc_init: | 798 | hc_init: |
736 | op_reg_base = base + XHCI_HC_LENGTH(readl(base)); | 799 | op_reg_base = base + XHCI_HC_LENGTH(readl(base)); |
737 | 800 | ||
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index 6ae9f78e9938..b1002a8ef96f 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h | |||
@@ -8,6 +8,8 @@ int usb_amd_find_chipset_info(void); | |||
8 | void usb_amd_dev_put(void); | 8 | void usb_amd_dev_put(void); |
9 | void usb_amd_quirk_pll_disable(void); | 9 | void usb_amd_quirk_pll_disable(void); |
10 | void usb_amd_quirk_pll_enable(void); | 10 | void usb_amd_quirk_pll_enable(void); |
11 | bool usb_is_intel_switchable_xhci(struct pci_dev *pdev); | ||
12 | void usb_enable_xhci_ports(struct pci_dev *xhci_pdev); | ||
11 | #else | 13 | #else |
12 | static inline void usb_amd_quirk_pll_disable(void) {} | 14 | static inline void usb_amd_quirk_pll_disable(void) {} |
13 | static inline void usb_amd_quirk_pll_enable(void) {} | 15 | static inline void usb_amd_quirk_pll_enable(void) {} |
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index cbc4d491e626..faf039ac6573 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -242,8 +242,28 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
242 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | 242 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) |
243 | { | 243 | { |
244 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 244 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
245 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | ||
245 | int retval = 0; | 246 | int retval = 0; |
246 | 247 | ||
248 | /* The BIOS on systems with the Intel Panther Point chipset may or may | ||
249 | * not support xHCI natively. That means that during system resume, it | ||
250 | * may switch the ports back to EHCI so that users can use their | ||
251 | * keyboard to select a kernel from GRUB after resume from hibernate. | ||
252 | * | ||
253 | * The BIOS is supposed to remember whether the OS had xHCI ports | ||
254 | * enabled before resume, and switch the ports back to xHCI when the | ||
255 | * BIOS/OS semaphore is written, but we all know we can't trust BIOS | ||
256 | * writers. | ||
257 | * | ||
258 | * Unconditionally switch the ports back to xHCI after a system resume. | ||
259 | * We can't tell whether the EHCI or xHCI controller will be resumed | ||
260 | * first, so we have to do the port switchover in both drivers. Writing | ||
261 | * a '1' to the port switchover registers should have no effect if the | ||
262 | * port was already switched over. | ||
263 | */ | ||
264 | if (usb_is_intel_switchable_xhci(pdev)) | ||
265 | usb_enable_xhci_ports(pdev); | ||
266 | |||
247 | retval = xhci_resume(xhci, hibernated); | 267 | retval = xhci_resume(xhci, hibernated); |
248 | return retval; | 268 | return retval; |
249 | } | 269 | } |