aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2013-07-23 04:35:47 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2013-07-23 17:50:29 -0400
commit26b76798e0507429506b93cd49f8c4cfdab06896 (patch)
tree264be6752d1b833de4807f33c18f971993c0f952 /drivers/usb/host
parent063ebeb4335312d05bdf6fb4fc0e41500c6c0afb (diff)
Intel xhci: refactor EHCI/xHCI port switching
Make the Linux xHCI driver automatically try to switchover the EHCI ports to xHCI when an Intel xHCI host is detected, and it also finds an Intel EHCI host. This means we will no longer have to add Intel xHCI hosts to a quirks list when the PCI device IDs change. Simply continuing to add new Intel xHCI PCI device IDs to the quirks list is not sustainable. During suspend ports may be swicthed back to EHCI by BIOS and not properly restored to xHCI at resume. Previously both EHCI and xHCI resume functions switched ports back to XHCI, but it's enough to do it in xHCI only because the hub driver doesn't start running again until after both hosts are resumed. Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-pci.c42
-rw-r--r--drivers/usb/host/pci-quirks.c48
-rw-r--r--drivers/usb/host/pci-quirks.h3
-rw-r--r--drivers/usb/host/xhci-pci.c14
4 files changed, 27 insertions, 80 deletions
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 595d210655b6..6bd299e61f58 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -315,53 +315,11 @@ done:
315 * Also they depend on separate root hub suspend/resume. 315 * Also they depend on separate root hub suspend/resume.
316 */ 316 */
317 317
318static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
319{
320 return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
321 pdev->vendor == PCI_VENDOR_ID_INTEL &&
322 (pdev->device == 0x1E26 ||
323 pdev->device == 0x8C2D ||
324 pdev->device == 0x8C26 ||
325 pdev->device == 0x9C26);
326}
327
328static void ehci_enable_xhci_companion(void)
329{
330 struct pci_dev *companion = NULL;
331
332 /* The xHCI and EHCI controllers are not on the same PCI slot */
333 for_each_pci_dev(companion) {
334 if (!usb_is_intel_switchable_xhci(companion))
335 continue;
336 usb_enable_xhci_ports(companion);
337 return;
338 }
339}
340
341static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) 318static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
342{ 319{
343 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 320 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
344 struct pci_dev *pdev = to_pci_dev(hcd->self.controller); 321 struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
345 322
346 /* The BIOS on systems with the Intel Panther Point chipset may or may
347 * not support xHCI natively. That means that during system resume, it
348 * may switch the ports back to EHCI so that users can use their
349 * keyboard to select a kernel from GRUB after resume from hibernate.
350 *
351 * The BIOS is supposed to remember whether the OS had xHCI ports
352 * enabled before resume, and switch the ports back to xHCI when the
353 * BIOS/OS semaphore is written, but we all know we can't trust BIOS
354 * writers.
355 *
356 * Unconditionally switch the ports back to xHCI after a system resume.
357 * We can't tell whether the EHCI or xHCI controller will be resumed
358 * first, so we have to do the port switchover in both drivers. Writing
359 * a '1' to the port switchover registers should have no effect if the
360 * port was already switched over.
361 */
362 if (usb_is_intel_switchable_ehci(pdev))
363 ehci_enable_xhci_companion();
364
365 if (ehci_resume(hcd, hibernated) != 0) 323 if (ehci_resume(hcd, hibernated) != 0)
366 (void) ehci_pci_reinit(ehci, pdev); 324 (void) ehci_pci_reinit(ehci, pdev);
367 return 0; 325 return 0;
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index b9848e4d3d44..2c76ef1320ea 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -735,32 +735,6 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
735 return -ETIMEDOUT; 735 return -ETIMEDOUT;
736} 736}
737 737
738#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31
739#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31
740
741bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
742{
743 return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
744 pdev->vendor == PCI_VENDOR_ID_INTEL &&
745 pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
746}
747
748/* The Intel Lynx Point chipset also has switchable ports. */
749bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
750{
751 return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
752 pdev->vendor == PCI_VENDOR_ID_INTEL &&
753 (pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI ||
754 pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI);
755}
756
757bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
758{
759 return usb_is_intel_ppt_switchable_xhci(pdev) ||
760 usb_is_intel_lpt_switchable_xhci(pdev);
761}
762EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
763
764/* 738/*
765 * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that 739 * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that
766 * share some number of ports. These ports can be switched between either 740 * share some number of ports. These ports can be switched between either
@@ -779,9 +753,23 @@ EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
779 * terminations before switching the USB 2.0 wires over, so that USB 3.0 753 * terminations before switching the USB 2.0 wires over, so that USB 3.0
780 * devices connect at SuperSpeed, rather than at USB 2.0 speeds. 754 * devices connect at SuperSpeed, rather than at USB 2.0 speeds.
781 */ 755 */
782void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) 756void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
783{ 757{
784 u32 ports_available; 758 u32 ports_available;
759 bool ehci_found = false;
760 struct pci_dev *companion = NULL;
761
762 /* make sure an intel EHCI controller exists */
763 for_each_pci_dev(companion) {
764 if (companion->class == PCI_CLASS_SERIAL_USB_EHCI &&
765 companion->vendor == PCI_VENDOR_ID_INTEL) {
766 ehci_found = true;
767 break;
768 }
769 }
770
771 if (!ehci_found)
772 return;
785 773
786 /* Don't switchover the ports if the user hasn't compiled the xHCI 774 /* Don't switchover the ports if the user hasn't compiled the xHCI
787 * driver. Otherwise they will see "dead" USB ports that don't power 775 * driver. Otherwise they will see "dead" USB ports that don't power
@@ -840,7 +828,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
840 dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over " 828 dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
841 "to xHCI: 0x%x\n", ports_available); 829 "to xHCI: 0x%x\n", ports_available);
842} 830}
843EXPORT_SYMBOL_GPL(usb_enable_xhci_ports); 831EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
844 832
845void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) 833void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
846{ 834{
@@ -921,8 +909,8 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
921 writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); 909 writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
922 910
923hc_init: 911hc_init:
924 if (usb_is_intel_switchable_xhci(pdev)) 912 if (pdev->vendor == PCI_VENDOR_ID_INTEL)
925 usb_enable_xhci_ports(pdev); 913 usb_enable_intel_xhci_ports(pdev);
926 914
927 op_reg_base = base + XHCI_HC_LENGTH(readl(base)); 915 op_reg_base = base + XHCI_HC_LENGTH(readl(base));
928 916
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 4b8a2092432f..0a5e0fb8f466 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -8,8 +8,7 @@ int usb_amd_find_chipset_info(void);
8void usb_amd_dev_put(void); 8void usb_amd_dev_put(void);
9void usb_amd_quirk_pll_disable(void); 9void usb_amd_quirk_pll_disable(void);
10void usb_amd_quirk_pll_enable(void); 10void usb_amd_quirk_pll_enable(void);
11bool usb_is_intel_switchable_xhci(struct pci_dev *pdev); 11void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
12void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
13void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); 12void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
14void sb800_prefetch(struct device *dev, int on); 13void sb800_prefetch(struct device *dev, int on);
15#else 14#else
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index cc24e39b97d5..475e06e10a77 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -250,13 +250,15 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
250 * writers. 250 * writers.
251 * 251 *
252 * Unconditionally switch the ports back to xHCI after a system resume. 252 * Unconditionally switch the ports back to xHCI after a system resume.
253 * We can't tell whether the EHCI or xHCI controller will be resumed 253 * It should not matter whether the EHCI or xHCI controller is
254 * first, so we have to do the port switchover in both drivers. Writing 254 * resumed first. It's enough to do the switchover in xHCI because
255 * a '1' to the port switchover registers should have no effect if the 255 * USB core won't notice anything as the hub driver doesn't start
256 * port was already switched over. 256 * running again until after all the devices (including both EHCI and
257 * xHCI host controllers) have been resumed.
257 */ 258 */
258 if (usb_is_intel_switchable_xhci(pdev)) 259
259 usb_enable_xhci_ports(pdev); 260 if (pdev->vendor == PCI_VENDOR_ID_INTEL)
261 usb_enable_intel_xhci_ports(pdev);
260 262
261 retval = xhci_resume(xhci, hibernated); 263 retval = xhci_resume(xhci, hibernated);
262 return retval; 264 return retval;