[RFC PATCH 1/1] Intel xhci: refactor EHCI/xHCI port switching

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

Signed-off-by: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
---
 drivers/usb/host/ehci-pci.c   |   15 +----------
 drivers/usb/host/pci-quirks.c |   55 ++++++++++++++++++----------------------
 drivers/usb/host/pci-quirks.h |    3 +-
 drivers/usb/host/xhci-pci.c   |    5 ++-
 4 files changed, 30 insertions(+), 48 deletions(-)

diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 595d210..7dd09ea 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -325,19 +325,6 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
 		 pdev->device == 0x9C26);
 }
 
-static void ehci_enable_xhci_companion(void)
-{
-	struct pci_dev		*companion = NULL;
-
-	/* The xHCI and EHCI controllers are not on the same PCI slot */
-	for_each_pci_dev(companion) {
-		if (!usb_is_intel_switchable_xhci(companion))
-			continue;
-		usb_enable_xhci_ports(companion);
-		return;
-	}
-}
-
 static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
@@ -360,7 +347,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 	 * port was already switched over.
 	 */
 	if (usb_is_intel_switchable_ehci(pdev))
-		ehci_enable_xhci_companion();
+		usb_enable_intel_xhci_ports();
 
 	if (ehci_resume(hcd, hibernated) != 0)
 		(void) ehci_pci_reinit(ehci, pdev);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index b9848e4..bbc4e98 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -89,6 +89,11 @@ static struct amd_chipset_info {
 	int probe_result;
 } amd_chipset;
 
+static struct intel_chipset_info {
+	struct pci_dev	*xhci_dev;
+	bool switchable_ports;
+} intel_chipset;
+
 static DEFINE_SPINLOCK(amd_lock);
 
 void sb800_prefetch(struct device *dev, int on)
@@ -735,32 +740,6 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
 	return -ETIMEDOUT;
 }
 
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI	0x8C31
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI	0x9C31
-
-bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
-{
-	return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
-		pdev->vendor == PCI_VENDOR_ID_INTEL &&
-		pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
-}
-
-/* The Intel Lynx Point chipset also has switchable ports. */
-bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
-{
-	return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
-		pdev->vendor == PCI_VENDOR_ID_INTEL &&
-		(pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI ||
-		 pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI);
-}
-
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
-{
-	return usb_is_intel_ppt_switchable_xhci(pdev) ||
-		usb_is_intel_lpt_switchable_xhci(pdev);
-}
-EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
-
 /*
  * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that
  * share some number of ports.  These ports can be switched between either
@@ -779,10 +758,16 @@ EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
  * terminations before switching the USB 2.0 wires over, so that USB 3.0
  * devices connect at SuperSpeed, rather than at USB 2.0 speeds.
  */
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
+void usb_enable_intel_xhci_ports(void)
 {
+	struct pci_dev *xhci_pdev;
 	u32		ports_available;
 
+	if (!intel_chipset.switchable_ports || !intel_chipset.xhci_dev)
+		return;
+
+	xhci_pdev = intel_chipset.xhci_dev;
+
 	/* Don't switchover the ports if the user hasn't compiled the xHCI
 	 * driver.  Otherwise they will see "dead" USB ports that don't power
 	 * the devices.
@@ -840,7 +825,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
 	dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
 			"to xHCI: 0x%x\n", ports_available);
 }
-EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
+EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
 
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
 {
@@ -921,8 +906,18 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
 	writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
 
 hc_init:
-	if (usb_is_intel_switchable_xhci(pdev))
-		usb_enable_xhci_ports(pdev);
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+		struct pci_dev *companion = NULL;
+		for_each_pci_dev(companion) {
+			if (companion->class == PCI_CLASS_SERIAL_USB_EHCI &&
+			    companion->vendor == PCI_VENDOR_ID_INTEL) {
+				intel_chipset.xhci_dev = pdev;
+				intel_chipset.switchable_ports = true;
+				usb_enable_intel_xhci_ports();
+				break;
+			}
+		}
+	}
 
 	op_reg_base = base + XHCI_HC_LENGTH(readl(base));
 
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 4b8a209..03bb3dc 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);
 void usb_amd_dev_put(void);
 void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
+void usb_enable_intel_xhci_ports(void);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
 #else
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 1a30c38..e7aaa74 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -247,8 +247,9 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 	 * a '1' to the port switchover registers should have no effect if the
 	 * port was already switched over.
 	 */
-	if (usb_is_intel_switchable_xhci(pdev))
-		usb_enable_xhci_ports(pdev);
+
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+		usb_enable_intel_xhci_ports();
 
 	retval = xhci_resume(xhci, hibernated);
 	return retval;
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux