Commit d1001ab4 authored by Lu Baolu's avatar Lu Baolu Committed by Greg Kroah-Hartman

usb: xhci: clear EINT bit in status correctly

EINT(Event Interrupt) is a write-1-to-clear type of bit in xhci
status register. It should be cleared by writing a 1. Writing 0
to this bit has no effect.

Xhci driver tries to clear this bit by writing 0 to it. This is
not the right way to go. This patch corrects this by reading the
register first, then clearing all RO/RW1C/RsvZ bits and setting
the clearing bit, and writing back the new value at last.

Xhci spec requires that software that uses EINT shall clear it
prior to clearing any IP flags in section 5.4.2. This is the
reason why this patch is CC'ed stable as well.

[old way didn't cause any issues, skip stable, send to next -Mathias]

Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c70a1529
...@@ -724,7 +724,7 @@ void xhci_stop(struct usb_hcd *hcd) ...@@ -724,7 +724,7 @@ void xhci_stop(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"// Disabling event ring interrupts"); "// Disabling event ring interrupts");
temp = readl(&xhci->op_regs->status); temp = readl(&xhci->op_regs->status);
writel(temp & ~STS_EINT, &xhci->op_regs->status); writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
temp = readl(&xhci->ir_set->irq_pending); temp = readl(&xhci->ir_set->irq_pending);
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
xhci_print_ir_set(xhci, 0); xhci_print_ir_set(xhci, 0);
...@@ -1057,7 +1057,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -1057,7 +1057,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
xhci_dbg(xhci, "// Disabling event ring interrupts\n"); xhci_dbg(xhci, "// Disabling event ring interrupts\n");
temp = readl(&xhci->op_regs->status); temp = readl(&xhci->op_regs->status);
writel(temp & ~STS_EINT, &xhci->op_regs->status); writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
temp = readl(&xhci->ir_set->irq_pending); temp = readl(&xhci->ir_set->irq_pending);
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
xhci_print_ir_set(xhci, 0); xhci_print_ir_set(xhci, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment