| From cf710c5355d76e66ab14457e5dd69666feb959e2 Mon Sep 17 00:00:00 2001 |
| From: Lu Baolu <baolu.lu@linux.intel.com> |
| Date: Fri, 7 Apr 2017 17:56:50 +0300 |
| Subject: [PATCH 177/286] 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: 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> |
| (cherry picked from commit d1001ab41064c7fe7bffbc1d7c3921912f3ec32d) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/usb/host/xhci.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/usb/host/xhci.c |
| +++ b/drivers/usb/host/xhci.c |
| @@ -724,7 +724,7 @@ void xhci_stop(struct usb_hcd *hcd) |
| xhci_dbg_trace(xhci, trace_xhci_dbg_init, |
| "// Disabling event ring interrupts"); |
| 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); |
| writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); |
| xhci_print_ir_set(xhci, 0); |
| @@ -1057,7 +1057,7 @@ int xhci_resume(struct xhci_hcd *xhci, b |
| |
| xhci_dbg(xhci, "// Disabling event ring interrupts\n"); |
| 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); |
| writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); |
| xhci_print_ir_set(xhci, 0); |