]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
xhci: Switch PPT ports to EHCI on shutdown.
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Mon, 23 Jul 2012 15:59:30 +0000 (18:59 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 26 Aug 2012 22:00:43 +0000 (15:00 -0700)
commit e95829f474f0db3a4d940cae1423783edd966027 upstream.

The Intel desktop boards DH77EB and DH77DF have a hardware issue that
can be worked around by BIOS.  If the USB ports are switched to xHCI on
shutdown, the xHCI host will send a spurious interrupt, which will wake
the system.  Some BIOS will work around this, but not all.

The bug can be avoided if the USB ports are switched back to EHCI on
shutdown.  The Intel Windows driver switches the ports back to EHCI, so
change the Linux xHCI driver to do the same.

Unfortunately, we can't tell the two effected boards apart from other
working motherboards, because the vendors will change the DMI strings
for the DH77EB and DH77DF boards to their own custom names.  One example
is Compulab's mini-desktop, the Intense-PC.  Instead, key off the
Panther Point xHCI host PCI vendor and device ID, and switch the ports
over for all PPT xHCI hosts.

The only impact this will have on non-effected boards is to add a couple
hundred milliseconds delay on boot when the BIOS has to switch the ports
over from EHCI to xHCI.

This patch should be backported to kernels as old as 3.0, that contain
the commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support
EHCI/xHCI port switching."

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Reported-by: Denis Turischev <denis@compulab.co.il>
Tested-by: Denis Turischev <denis@compulab.co.il>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index df0828cb2aa328ecf06cb37cb1a6981fa41d52f3..c5e9e4a76f148d4eed0c4785cf46fb38d143a074 100644 (file)
@@ -800,6 +800,13 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
 }
 EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
 
+void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
+{
+       pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, 0x0);
+       pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, 0x0);
+}
+EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
+
 /**
  * PCI Quirks for xHCI.
  *
index b1002a8ef96f58fc46039d6c37b4bcca18d056cb..ef004a5de20f176c27801f83bd9ae2456570e6b1 100644 (file)
@@ -10,6 +10,7 @@ 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_disable_xhci_ports(struct pci_dev *xhci_pdev);
 #else
 static inline void usb_amd_quirk_pll_disable(void) {}
 static inline void usb_amd_quirk_pll_enable(void) {}
index fccebc05b65589f08051225ce09c4474fa247bb8..f1527404617c57188754347ccfd88b5e29a28209 100644 (file)
@@ -90,6 +90,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
                xhci->limit_active_eps = 64;
                xhci->quirks |= XHCI_SW_BW_CHECKING;
+               /*
+                * PPT desktop boards DH77EB and DH77DF will power back on after
+                * a few seconds of being shutdown.  The fix for this is to
+                * switch the ports from xHCI to EHCI on shutdown.  We can't use
+                * DMI information to find those particular boards (since each
+                * vendor will change the board name), so we have to key off all
+                * PPT chipsets.
+                */
+               xhci->quirks |= XHCI_SPURIOUS_REBOOT;
        }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
index 4cc855dda4f1f6332303e4d2dfcc1df838f3f504..7beed536e6b9aa9587a802ce5e499fc0e56e32cb 100644 (file)
@@ -659,6 +659,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
+       if (xhci->quirks && XHCI_SPURIOUS_REBOOT)
+               usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
+
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
        spin_unlock_irq(&xhci->lock);
index 59434fe9d7d9a2b49001b6a57fb7f83f7851428e..19ae30f1d84adf095dd2619005880ce6b4c4a16d 100644 (file)
@@ -1486,6 +1486,7 @@ struct xhci_hcd {
 #define        XHCI_SW_BW_CHECKING     (1 << 8)
 #define XHCI_AMD_0x96_HOST     (1 << 9)
 #define XHCI_TRUST_TX_LENGTH   (1 << 10)
+#define XHCI_SPURIOUS_REBOOT   (1 << 13)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */