diff options
author | Lu Baolu <baolu.lu@linux.intel.com> | 2016-01-26 10:50:06 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-02-03 17:01:47 -0500 |
commit | 7e70cbffe236721051bbaff965e477df06dcb190 (patch) | |
tree | 3466842559a275718caff8340cb333753fc35d8e | |
parent | fa89537783cb442263fa5a14df6c7693eaf32f11 (diff) |
usb: xhci: add a quirk bit for ssic port unused
Two workarounds introduced by commit b8cb91e058cd ("xhci: Workaround
for PME stuck issues in Intel xhci") and commit abce329c27b3 ("xhci:
Workaround to get D3 working in Intel xHCI") share a single quirk bit
XHCI_PME_STUCK_QUIRK. These two workarounds actually are different and
might happen on different hardwares. Need to separate them by adding a
quirk bit for the later.
Cc: stable@vger.kernel.org
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
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.c | 79 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 1 |
2 files changed, 46 insertions, 34 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 67471fb28de5..86377a0955e6 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -156,6 +156,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) | |||
156 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) { | 156 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) { |
157 | xhci->quirks |= XHCI_PME_STUCK_QUIRK; | 157 | xhci->quirks |= XHCI_PME_STUCK_QUIRK; |
158 | } | 158 | } |
159 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
160 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { | ||
161 | xhci->quirks |= XHCI_SSIC_PORT_UNUSED; | ||
162 | } | ||
159 | if (pdev->vendor == PCI_VENDOR_ID_ETRON && | 163 | if (pdev->vendor == PCI_VENDOR_ID_ETRON && |
160 | pdev->device == PCI_DEVICE_ID_EJ168) { | 164 | pdev->device == PCI_DEVICE_ID_EJ168) { |
161 | xhci->quirks |= XHCI_RESET_ON_RESUME; | 165 | xhci->quirks |= XHCI_RESET_ON_RESUME; |
@@ -314,46 +318,47 @@ static void xhci_pci_remove(struct pci_dev *dev) | |||
314 | * SSIC PORT need to be marked as "unused" before putting xHCI | 318 | * SSIC PORT need to be marked as "unused" before putting xHCI |
315 | * into D3. After D3 exit, the SSIC port need to be marked as "used". | 319 | * into D3. After D3 exit, the SSIC port need to be marked as "used". |
316 | * Without this change, xHCI might not enter D3 state. | 320 | * Without this change, xHCI might not enter D3 state. |
317 | * Make sure PME works on some Intel xHCI controllers by writing 1 to clear | ||
318 | * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 | ||
319 | */ | 321 | */ |
320 | static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend) | 322 | static void xhci_ssic_port_unused_quirk(struct usb_hcd *hcd, bool suspend) |
321 | { | 323 | { |
322 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 324 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
323 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | ||
324 | u32 val; | 325 | u32 val; |
325 | void __iomem *reg; | 326 | void __iomem *reg; |
326 | int i; | 327 | int i; |
327 | 328 | ||
328 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | 329 | for (i = 0; i < SSIC_PORT_NUM; i++) { |
329 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { | 330 | reg = (void __iomem *) xhci->cap_regs + |
330 | 331 | SSIC_PORT_CFG2 + | |
331 | for (i = 0; i < SSIC_PORT_NUM; i++) { | 332 | i * SSIC_PORT_CFG2_OFFSET; |
332 | reg = (void __iomem *) xhci->cap_regs + | 333 | |
333 | SSIC_PORT_CFG2 + | 334 | /* Notify SSIC that SSIC profile programming is not done. */ |
334 | i * SSIC_PORT_CFG2_OFFSET; | 335 | val = readl(reg) & ~PROG_DONE; |
335 | 336 | writel(val, reg); | |
336 | /* | 337 | |
337 | * Notify SSIC that SSIC profile programming | 338 | /* Mark SSIC port as unused(suspend) or used(resume) */ |
338 | * is not done. | 339 | val = readl(reg); |
339 | */ | 340 | if (suspend) |
340 | val = readl(reg) & ~PROG_DONE; | 341 | val |= SSIC_PORT_UNUSED; |
341 | writel(val, reg); | 342 | else |
342 | 343 | val &= ~SSIC_PORT_UNUSED; | |
343 | /* Mark SSIC port as unused(suspend) or used(resume) */ | 344 | writel(val, reg); |
344 | val = readl(reg); | 345 | |
345 | if (suspend) | 346 | /* Notify SSIC that SSIC profile programming is done */ |
346 | val |= SSIC_PORT_UNUSED; | 347 | val = readl(reg) | PROG_DONE; |
347 | else | 348 | writel(val, reg); |
348 | val &= ~SSIC_PORT_UNUSED; | 349 | readl(reg); |
349 | writel(val, reg); | ||
350 | |||
351 | /* Notify SSIC that SSIC profile programming is done */ | ||
352 | val = readl(reg) | PROG_DONE; | ||
353 | writel(val, reg); | ||
354 | readl(reg); | ||
355 | } | ||
356 | } | 350 | } |
351 | } | ||
352 | |||
353 | /* | ||
354 | * Make sure PME works on some Intel xHCI controllers by writing 1 to clear | ||
355 | * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 | ||
356 | */ | ||
357 | static void xhci_pme_quirk(struct usb_hcd *hcd) | ||
358 | { | ||
359 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
360 | void __iomem *reg; | ||
361 | u32 val; | ||
357 | 362 | ||
358 | reg = (void __iomem *) xhci->cap_regs + 0x80a4; | 363 | reg = (void __iomem *) xhci->cap_regs + 0x80a4; |
359 | val = readl(reg); | 364 | val = readl(reg); |
@@ -374,7 +379,10 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
374 | pdev->no_d3cold = true; | 379 | pdev->no_d3cold = true; |
375 | 380 | ||
376 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) | 381 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) |
377 | xhci_pme_quirk(hcd, true); | 382 | xhci_pme_quirk(hcd); |
383 | |||
384 | if (xhci->quirks & XHCI_SSIC_PORT_UNUSED) | ||
385 | xhci_ssic_port_unused_quirk(hcd, true); | ||
378 | 386 | ||
379 | return xhci_suspend(xhci, do_wakeup); | 387 | return xhci_suspend(xhci, do_wakeup); |
380 | } | 388 | } |
@@ -406,8 +414,11 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
406 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) | 414 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) |
407 | usb_enable_intel_xhci_ports(pdev); | 415 | usb_enable_intel_xhci_ports(pdev); |
408 | 416 | ||
417 | if (xhci->quirks & XHCI_SSIC_PORT_UNUSED) | ||
418 | xhci_ssic_port_unused_quirk(hcd, false); | ||
419 | |||
409 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) | 420 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) |
410 | xhci_pme_quirk(hcd, false); | 421 | xhci_pme_quirk(hcd); |
411 | 422 | ||
412 | retval = xhci_resume(xhci, hibernated); | 423 | retval = xhci_resume(xhci, hibernated); |
413 | return retval; | 424 | return retval; |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9be7348872ba..cc651383ce5a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1631,6 +1631,7 @@ struct xhci_hcd { | |||
1631 | #define XHCI_BROKEN_STREAMS (1 << 19) | 1631 | #define XHCI_BROKEN_STREAMS (1 << 19) |
1632 | #define XHCI_PME_STUCK_QUIRK (1 << 20) | 1632 | #define XHCI_PME_STUCK_QUIRK (1 << 20) |
1633 | #define XHCI_MTK_HOST (1 << 21) | 1633 | #define XHCI_MTK_HOST (1 << 21) |
1634 | #define XHCI_SSIC_PORT_UNUSED (1 << 22) | ||
1634 | unsigned int num_active_eps; | 1635 | unsigned int num_active_eps; |
1635 | unsigned int limit_active_eps; | 1636 | unsigned int limit_active_eps; |
1636 | /* There are two roothubs to keep track of bus suspend info for */ | 1637 | /* There are two roothubs to keep track of bus suspend info for */ |