Skip to content

Commit

Permalink
usb: xhci: handle both SSIC ports in PME stuck quirk
Browse files Browse the repository at this point in the history
[ Upstream commit fa89537 ]

Commit abce329 ("xhci: Workaround to get D3 working in Intel xHCI")
adds a workaround for a limitation of PME storm caused by SSIC port in
some Intel SoCs. This commit only handled one SSIC port, while there
are actually two SSIC ports in the chips. This patch handles both SSIC
ports. Without this fix, users still see PME storm.

Cc: stable@vger.kernel.org # v4.2+
Signed-off-by: Zhuang Jin Can <jin.can.zhuang@intel.com>
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>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
  • Loading branch information
Lu Baolu authored and Sasha Levin committed Feb 15, 2016
1 parent 1c0232f commit 69b8883
Showing 1 changed file with 29 additions and 19 deletions.
48 changes: 29 additions & 19 deletions drivers/usb/host/xhci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
#include "xhci.h"
#include "xhci-trace.h"

#define PORT2_SSIC_CONFIG_REG2 0x883c
#define SSIC_PORT_NUM 2
#define SSIC_PORT_CFG2 0x880c
#define SSIC_PORT_CFG2_OFFSET 0x30
#define PROG_DONE (1 << 30)
#define SSIC_PORT_UNUSED (1 << 31)

Expand Down Expand Up @@ -317,28 +319,36 @@ static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
u32 val;
void __iomem *reg;
int i;

if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {

reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;

/* Notify SSIC that SSIC profile programming is not done */
val = readl(reg) & ~PROG_DONE;
writel(val, reg);

/* Mark SSIC port as unused(suspend) or used(resume) */
val = readl(reg);
if (suspend)
val |= SSIC_PORT_UNUSED;
else
val &= ~SSIC_PORT_UNUSED;
writel(val, reg);

/* Notify SSIC that SSIC profile programming is done */
val = readl(reg) | PROG_DONE;
writel(val, reg);
readl(reg);
for (i = 0; i < SSIC_PORT_NUM; i++) {
reg = (void __iomem *) xhci->cap_regs +
SSIC_PORT_CFG2 +
i * SSIC_PORT_CFG2_OFFSET;

/*
* Notify SSIC that SSIC profile programming
* is not done.
*/
val = readl(reg) & ~PROG_DONE;
writel(val, reg);

/* Mark SSIC port as unused(suspend) or used(resume) */
val = readl(reg);
if (suspend)
val |= SSIC_PORT_UNUSED;
else
val &= ~SSIC_PORT_UNUSED;
writel(val, reg);

/* Notify SSIC that SSIC profile programming is done */
val = readl(reg) | PROG_DONE;
writel(val, reg);
readl(reg);
}
}

reg = (void __iomem *) xhci->cap_regs + 0x80a4;
Expand Down

0 comments on commit 69b8883

Please sign in to comment.