diff options
Diffstat (limited to 'drivers/usb/host/xhci-pci.c')
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 55 |
1 files changed, 43 insertions, 12 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index f00cb203fae..b8dffd59eb2 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include "xhci.h" +#include "xhci-trace.h" /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 @@ -34,6 +35,9 @@ #define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_DEVICE_ID_ASROCK_P67 0x7023 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 + static const char hcd_name[] = "xhci_hcd"; /* called after powerup, by probe or system-pm "wakeup" */ @@ -64,16 +68,26 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && pdev->revision == 0x0) { xhci->quirks |= XHCI_RESET_EP_QUIRK; - xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" - " endpoint cmd after reset endpoint\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Fresco Logic xHC needs configure" + " endpoint cmd after reset endpoint"); + } + if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && + pdev->revision == 0x4) { + xhci->quirks |= XHCI_SLOW_SUSPEND; + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Fresco Logic xHC revision %u" + "must be suspended extra slowly", + pdev->revision); } /* Fresco Logic confirms: all revisions of this chip do not * support MSI, even though some of them claim to in their PCI * capabilities. */ xhci->quirks |= XHCI_BROKEN_MSI; - xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " - "has broken MSI implementation\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Fresco Logic revision %u " + "has broken MSI implementation", pdev->revision); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } @@ -107,10 +121,20 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SPURIOUS_REBOOT; xhci->quirks |= XHCI_AVOID_BEI; } + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI)) { + /* Workaround for occasional spurious wakeups from S5 (or + * any other sleep) on Haswell machines with LPT and LPT-LP + * with the new Intel BIOS + */ + xhci->quirks |= XHCI_SPURIOUS_WAKEUP; + } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; - xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Resetting on resume"); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_VIA) @@ -213,6 +237,11 @@ static void xhci_pci_remove(struct pci_dev *dev) usb_put_hcd(xhci->shared_hcd); } usb_hcd_pci_remove(dev); + + /* Workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + pci_set_power_state(dev, PCI_D3hot); + kfree(xhci); } @@ -249,13 +278,15 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) * writers. * * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. + * It should not matter whether the EHCI or xHCI controller is + * resumed first. It's enough to do the switchover in xHCI because + * USB core won't notice anything as the hub driver doesn't start + * running again until after all the devices (including both EHCI and + * xHCI host controllers) have been resumed. */ - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); + + if (pdev->vendor == PCI_VENDOR_ID_INTEL) + usb_enable_intel_xhci_ports(pdev); retval = xhci_resume(xhci, hibernated); return retval; @@ -345,7 +376,7 @@ static struct pci_driver xhci_pci_driver = { /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, |