aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-07-23 11:59:30 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-26 18:12:12 -0400
commit0135372d5c4305a59aee0091847da7ce0cf08ffe (patch)
tree743ba66c944d551d15250ccb241863f7e5a4aa02
parentb474a496850d10267320b7c2ff7c0ca09d2de8c9 (diff)
xhci: Switch PPT ports to EHCI on shutdown.
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>
-rw-r--r--drivers/usb/host/pci-quirks.c7
-rw-r--r--drivers/usb/host/pci-quirks.h1
-rw-r--r--drivers/usb/host/xhci-pci.c9
-rw-r--r--drivers/usb/host/xhci.c3
-rw-r--r--drivers/usb/host/xhci.h1
5 files changed, 21 insertions, 0 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 9ab094c0cf3..efba0188585 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -798,6 +798,13 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
798} 798}
799EXPORT_SYMBOL_GPL(usb_enable_xhci_ports); 799EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
800 800
801void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
802{
803 pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, 0x0);
804 pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, 0x0);
805}
806EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
807
801/** 808/**
802 * PCI Quirks for xHCI. 809 * PCI Quirks for xHCI.
803 * 810 *
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index b1002a8ef96..ef004a5de20 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -10,6 +10,7 @@ void 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); 11bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
12void usb_enable_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);
13#else 14#else
14static inline void usb_amd_quirk_pll_disable(void) {} 15static inline void usb_amd_quirk_pll_disable(void) {}
15static inline void usb_amd_quirk_pll_enable(void) {} 16static 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 5c67f845901..b04745817b9 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -140,6 +140,15 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
140 xhci->quirks |= XHCI_SPURIOUS_SUCCESS; 140 xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
141 xhci->quirks |= XHCI_EP_LIMIT_QUIRK; 141 xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
142 xhci->limit_active_eps = 64; 142 xhci->limit_active_eps = 64;
143 /*
144 * PPT desktop boards DH77EB and DH77DF will power back on after
145 * a few seconds of being shutdown. The fix for this is to
146 * switch the ports from xHCI to EHCI on shutdown. We can't use
147 * DMI information to find those particular boards (since each
148 * vendor will change the board name), so we have to key off all
149 * PPT chipsets.
150 */
151 xhci->quirks |= XHCI_SPURIOUS_REBOOT;
143 } 152 }
144 if (pdev->vendor == PCI_VENDOR_ID_ETRON && 153 if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
145 pdev->device == PCI_DEVICE_ID_ASROCK_P67) { 154 pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index fd1421ff0b4..1f9602ad39e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -594,6 +594,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
594{ 594{
595 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 595 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
596 596
597 if (xhci->quirks && XHCI_SPURIOUS_REBOOT)
598 usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
599
597 spin_lock_irq(&xhci->lock); 600 spin_lock_irq(&xhci->lock);
598 xhci_halt(xhci); 601 xhci_halt(xhci);
599 spin_unlock_irq(&xhci->lock); 602 spin_unlock_irq(&xhci->lock);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 25c3e26b999..d88644d9259 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1316,6 +1316,7 @@ struct xhci_hcd {
1316#define XHCI_RESET_ON_RESUME (1 << 7) 1316#define XHCI_RESET_ON_RESUME (1 << 7)
1317#define XHCI_AMD_0x96_HOST (1 << 9) 1317#define XHCI_AMD_0x96_HOST (1 << 9)
1318#define XHCI_TRUST_TX_LENGTH (1 << 10) 1318#define XHCI_TRUST_TX_LENGTH (1 << 10)
1319#define XHCI_SPURIOUS_REBOOT (1 << 13)
1319 unsigned int num_active_eps; 1320 unsigned int num_active_eps;
1320 unsigned int limit_active_eps; 1321 unsigned int limit_active_eps;
1321 /* There are two roothubs to keep track of bus suspend info for */ 1322 /* There are two roothubs to keep track of bus suspend info for */