aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2010-07-30 01:13:00 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 17:35:45 -0400
commitc21599a36165dbc78b380846b254017a548b9de5 (patch)
treef6e0cdf815e2e1a991f39489e6bd02c10afa22f1 /drivers/usb/host
parent257d585aaec469ded6ec15d8a8e7ebada21d7277 (diff)
USB: xhci: Reduce reads and writes of interrupter registers.
The interrupter register set includes a register that says whether interrupts are pending for each event ring (the IP bit). Each MSI-X vector will get its own interrupter set with separate IP bits. The status register includes an "Event Interrupt (EINT)" bit that is set when an IP bit is set in any of the interrupters. When PCI interrupts are used, the EINT bit exactly mirrors the IP bit in the single interrupter set, and it is a waste of time to check both registers when trying to figure out if the xHC interrupted or another device on the shared IRQ line interrupted. Only check the IP bit to reduce register reads. The IP bit is automatically cleared by the xHC when MSI or MSI-X is enabled. It doesn't make sense to read that register to check for shared interrupts (since MSI and MSI-X aren't shared). It also doesn't make sense to write to that register to clear the IP bit, since it is cleared by the hardware. We can tell whether MSI or MSI-X is enabled by looking at the irq number in hcd->irq. If it's -1, we know MSI or MSI-X is enabled. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/xhci-ring.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index f479f73711ac..6860e9f097bb 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2014,7 +2014,7 @@ static void xhci_handle_event(struct xhci_hcd *xhci)
2014irqreturn_t xhci_irq(struct usb_hcd *hcd) 2014irqreturn_t xhci_irq(struct usb_hcd *hcd)
2015{ 2015{
2016 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 2016 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
2017 u32 status, irq_pending; 2017 u32 status;
2018 union xhci_trb *trb; 2018 union xhci_trb *trb;
2019 u64 temp_64; 2019 u64 temp_64;
2020 union xhci_trb *event_ring_deq; 2020 union xhci_trb *event_ring_deq;
@@ -2024,17 +2024,15 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
2024 trb = xhci->event_ring->dequeue; 2024 trb = xhci->event_ring->dequeue;
2025 /* Check if the xHC generated the interrupt, or the irq is shared */ 2025 /* Check if the xHC generated the interrupt, or the irq is shared */
2026 status = xhci_readl(xhci, &xhci->op_regs->status); 2026 status = xhci_readl(xhci, &xhci->op_regs->status);
2027 irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); 2027 if (status == 0xffffffff)
2028 if (status == 0xffffffff && irq_pending == 0xffffffff)
2029 goto hw_died; 2028 goto hw_died;
2030 2029
2031 if (!(status & STS_EINT) && !ER_IRQ_PENDING(irq_pending)) { 2030 if (!(status & STS_EINT)) {
2032 spin_unlock(&xhci->lock); 2031 spin_unlock(&xhci->lock);
2033 xhci_warn(xhci, "Spurious interrupt.\n"); 2032 xhci_warn(xhci, "Spurious interrupt.\n");
2034 return IRQ_NONE; 2033 return IRQ_NONE;
2035 } 2034 }
2036 xhci_dbg(xhci, "op reg status = %08x\n", status); 2035 xhci_dbg(xhci, "op reg status = %08x\n", status);
2037 xhci_dbg(xhci, "ir set irq_pending = %08x\n", irq_pending);
2038 xhci_dbg(xhci, "Event ring dequeue ptr:\n"); 2036 xhci_dbg(xhci, "Event ring dequeue ptr:\n");
2039 xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n", 2037 xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
2040 (unsigned long long) 2038 (unsigned long long)
@@ -2063,9 +2061,13 @@ hw_died:
2063 /* FIXME when MSI-X is supported and there are multiple vectors */ 2061 /* FIXME when MSI-X is supported and there are multiple vectors */
2064 /* Clear the MSI-X event interrupt status */ 2062 /* Clear the MSI-X event interrupt status */
2065 2063
2066 /* Acknowledge the interrupt */ 2064 if (hcd->irq != -1) {
2067 irq_pending |= 0x3; 2065 u32 irq_pending;
2068 xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending); 2066 /* Acknowledge the PCI interrupt */
2067 irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
2068 irq_pending |= 0x3;
2069 xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
2070 }
2069 2071
2070 if (xhci->xhc_state & XHCI_STATE_DYING) { 2072 if (xhci->xhc_state & XHCI_STATE_DYING) {
2071 xhci_dbg(xhci, "xHCI dying, ignoring interrupt. " 2073 xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "