aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2015-03-06 10:23:19 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-03-06 12:47:48 -0500
commitb8cb91e058cd0c0f02059c1207293c5b31d350fa (patch)
tree4eac133da2e31268645eb19dcf5ea1d837449b26
parent45ba2154d12fc43b70312198ec47085f10be801a (diff)
xhci: Workaround for PME stuck issues in Intel xhci
The xhci in Intel Sunrisepoint and Cherryview platforms need a driver workaround for a Stuck PME that might either block PME events in suspend, or create spurious PME events preventing runtime suspend. Workaround is to clear a internal PME flag, BIT(28) in a vendor specific PMCTRL register at offset 0x80a4, in both suspend resume callbacks Without this, xhci connected usb devices might never be able to wake up the system from suspend, or prevent device from going to suspend (xhci d3) Cc: <stable@vger.kernel.org> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/xhci-pci.c30
-rw-r--r--drivers/usb/host/xhci.h1
2 files changed, 31 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7f76c8a12f89..fd53c9ebd662 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -37,6 +37,9 @@
37 37
38#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 38#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
39#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 39#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
40#define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5
41#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f
42#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f
40 43
41static const char hcd_name[] = "xhci_hcd"; 44static const char hcd_name[] = "xhci_hcd";
42 45
@@ -133,6 +136,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
133 pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) { 136 pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
134 xhci->quirks |= XHCI_SPURIOUS_REBOOT; 137 xhci->quirks |= XHCI_SPURIOUS_REBOOT;
135 } 138 }
139 if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
140 (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
141 pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
142 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) {
143 xhci->quirks |= XHCI_PME_STUCK_QUIRK;
144 }
136 if (pdev->vendor == PCI_VENDOR_ID_ETRON && 145 if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
137 pdev->device == PCI_DEVICE_ID_EJ168) { 146 pdev->device == PCI_DEVICE_ID_EJ168) {
138 xhci->quirks |= XHCI_RESET_ON_RESUME; 147 xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -159,6 +168,21 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
159 "QUIRK: Resetting on resume"); 168 "QUIRK: Resetting on resume");
160} 169}
161 170
171/*
172 * Make sure PME works on some Intel xHCI controllers by writing 1 to clear
173 * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
174 */
175static void xhci_pme_quirk(struct xhci_hcd *xhci)
176{
177 u32 val;
178 void __iomem *reg;
179
180 reg = (void __iomem *) xhci->cap_regs + 0x80a4;
181 val = readl(reg);
182 writel(val | BIT(28), reg);
183 readl(reg);
184}
185
162/* called during probe() after chip reset completes */ 186/* called during probe() after chip reset completes */
163static int xhci_pci_setup(struct usb_hcd *hcd) 187static int xhci_pci_setup(struct usb_hcd *hcd)
164{ 188{
@@ -283,6 +307,9 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
283 if (xhci->quirks & XHCI_COMP_MODE_QUIRK) 307 if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
284 pdev->no_d3cold = true; 308 pdev->no_d3cold = true;
285 309
310 if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
311 xhci_pme_quirk(xhci);
312
286 return xhci_suspend(xhci, do_wakeup); 313 return xhci_suspend(xhci, do_wakeup);
287} 314}
288 315
@@ -313,6 +340,9 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
313 if (pdev->vendor == PCI_VENDOR_ID_INTEL) 340 if (pdev->vendor == PCI_VENDOR_ID_INTEL)
314 usb_enable_intel_xhci_ports(pdev); 341 usb_enable_intel_xhci_ports(pdev);
315 342
343 if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
344 xhci_pme_quirk(xhci);
345
316 retval = xhci_resume(xhci, hibernated); 346 retval = xhci_resume(xhci, hibernated);
317 return retval; 347 return retval;
318} 348}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index d0663931e5ba..265ab1771d24 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1566,6 +1566,7 @@ struct xhci_hcd {
1566#define XHCI_SPURIOUS_WAKEUP (1 << 18) 1566#define XHCI_SPURIOUS_WAKEUP (1 << 18)
1567/* For controllers with a broken beyond repair streams implementation */ 1567/* For controllers with a broken beyond repair streams implementation */
1568#define XHCI_BROKEN_STREAMS (1 << 19) 1568#define XHCI_BROKEN_STREAMS (1 << 19)
1569#define XHCI_PME_STUCK_QUIRK (1 << 20)
1569 unsigned int num_active_eps; 1570 unsigned int num_active_eps;
1570 unsigned int limit_active_eps; 1571 unsigned int limit_active_eps;
1571 /* There are two roothubs to keep track of bus suspend info for */ 1572 /* There are two roothubs to keep track of bus suspend info for */