xhci: Fix spurious wakeups after S5 on Haswell

Haswell LynxPoint and LynxPoint-LP with the recent Intel BIOS show
mysterious wakeups after shutdown occasionally.  After discussing with
BIOS engineers, they explained that the new BIOS expects that the
wakeup sources are cleared and set to D3 for all wakeup devices when
the system is going to sleep or power off, but the current xhci driver
doesn't do this properly (partly intentionally).

This patch introduces a new quirk, XHCI_SPURIOUS_WAKEUP, for
fixing the spurious wakeups at S5 by calling xhci_reset() in the xhci
shutdown ops as done in xhci_stop(), and setting the device to PCI D3
at shutdown and remove ops.

The PCI D3 call is based on the initial fix patch by Oliver Neukum.

[Note: Sarah changed the quirk name from XHCI_HSW_SPURIOUS_WAKEUP to
XHCI_SPURIOUS_WAKEUP, since none of the other quirks have system names
in them.  Sarah also fixed a collision with a quirk submitted around the
same time, by changing the xhci->quirks bit from 17 to 18.]

This patch should be backported to kernels as old as 3.0, that
contain the commit 1c12443ab8 "xhci: Add
Lynx Point to list of Intel switchable hosts."

Cc: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable@vger.kernel.org
This commit is contained in:
Takashi Iwai 2013-09-12 08:11:06 +02:00 committed by Sarah Sharp
parent e459933967
commit 638298dc66
3 changed files with 25 additions and 0 deletions

View File

@ -35,6 +35,9 @@
#define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_VENDOR_ID_ETRON 0x1b6f
#define PCI_DEVICE_ID_ASROCK_P67 0x7023 #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"; static const char hcd_name[] = "xhci_hcd";
/* called after powerup, by probe or system-pm "wakeup" */ /* called after powerup, by probe or system-pm "wakeup" */
@ -118,6 +121,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_SPURIOUS_REBOOT; xhci->quirks |= XHCI_SPURIOUS_REBOOT;
xhci->quirks |= XHCI_AVOID_BEI; 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 && if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_ASROCK_P67) { pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
xhci->quirks |= XHCI_RESET_ON_RESUME; xhci->quirks |= XHCI_RESET_ON_RESUME;
@ -225,6 +237,11 @@ static void xhci_pci_remove(struct pci_dev *dev)
usb_put_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd);
} }
usb_hcd_pci_remove(dev); 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); kfree(xhci);
} }

View File

@ -730,6 +730,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
spin_lock_irq(&xhci->lock); spin_lock_irq(&xhci->lock);
xhci_halt(xhci); xhci_halt(xhci);
/* Workaround for spurious wakeups at shutdown with HSW */
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
xhci_reset(xhci);
spin_unlock_irq(&xhci->lock); spin_unlock_irq(&xhci->lock);
xhci_cleanup_msix(xhci); xhci_cleanup_msix(xhci);
@ -737,6 +740,10 @@ void xhci_shutdown(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"xhci_shutdown completed - status = %x", "xhci_shutdown completed - status = %x",
xhci_readl(xhci, &xhci->op_regs->status)); xhci_readl(xhci, &xhci->op_regs->status));
/* Yet another workaround for spurious wakeups at shutdown with HSW */
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM

View File

@ -1549,6 +1549,7 @@ struct xhci_hcd {
#define XHCI_AVOID_BEI (1 << 15) #define XHCI_AVOID_BEI (1 << 15)
#define XHCI_PLAT (1 << 16) #define XHCI_PLAT (1 << 16)
#define XHCI_SLOW_SUSPEND (1 << 17) #define XHCI_SLOW_SUSPEND (1 << 17)
#define XHCI_SPURIOUS_WAKEUP (1 << 18)
unsigned int num_active_eps; unsigned int num_active_eps;
unsigned int limit_active_eps; unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */ /* There are two roothubs to keep track of bus suspend info for */