Skip to content

Commit b8cb91e

Browse files
matnymangregkh
authored andcommitted
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: <[email protected]> Signed-off-by: Mathias Nyman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 45ba215 commit b8cb91e

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

drivers/usb/host/xhci-pci.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737

3838
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
3939
#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
4043

4144
static const char hcd_name[] = "xhci_hcd";
4245

@@ -133,6 +136,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
133136
pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
134137
xhci->quirks |= XHCI_SPURIOUS_REBOOT;
135138
}
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+
}
136145
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
137146
pdev->device == PCI_DEVICE_ID_EJ168) {
138147
xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -159,6 +168,21 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
159168
"QUIRK: Resetting on resume");
160169
}
161170

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+
*/
175+
static 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+
162186
/* called during probe() after chip reset completes */
163187
static int xhci_pci_setup(struct usb_hcd *hcd)
164188
{
@@ -283,6 +307,9 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
283307
if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
284308
pdev->no_d3cold = true;
285309

310+
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
311+
xhci_pme_quirk(xhci);
312+
286313
return xhci_suspend(xhci, do_wakeup);
287314
}
288315

@@ -313,6 +340,9 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
313340
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
314341
usb_enable_intel_xhci_ports(pdev);
315342

343+
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
344+
xhci_pme_quirk(xhci);
345+
316346
retval = xhci_resume(xhci, hibernated);
317347
return retval;
318348
}

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,7 @@ struct xhci_hcd {
15661566
#define XHCI_SPURIOUS_WAKEUP (1 << 18)
15671567
/* For controllers with a broken beyond repair streams implementation */
15681568
#define XHCI_BROKEN_STREAMS (1 << 19)
1569+
#define XHCI_PME_STUCK_QUIRK (1 << 20)
15691570
unsigned int num_active_eps;
15701571
unsigned int limit_active_eps;
15711572
/* There are two roothubs to keep track of bus suspend info for */

0 commit comments

Comments
 (0)