Commit c21599a36165dbc78b380846b254017a548b9de5

Authored by Sarah Sharp
Committed by Greg Kroah-Hartman
1 parent 257d585aae

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>

Showing 1 changed file with 10 additions and 8 deletions Side-by-side Diff

drivers/usb/host/xhci-ring.c
... ... @@ -2014,7 +2014,7 @@
2014 2014 irqreturn_t xhci_irq(struct usb_hcd *hcd)
2015 2015 {
2016 2016 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
2017   - u32 status, irq_pending;
  2017 + u32 status;
2018 2018 union xhci_trb *trb;
2019 2019 u64 temp_64;
2020 2020 union xhci_trb *event_ring_deq;
2021 2021  
2022 2022  
... ... @@ -2024,17 +2024,15 @@
2024 2024 trb = xhci->event_ring->dequeue;
2025 2025 /* Check if the xHC generated the interrupt, or the irq is shared */
2026 2026 status = xhci_readl(xhci, &xhci->op_regs->status);
2027   - irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
2028   - if (status == 0xffffffff && irq_pending == 0xffffffff)
  2027 + if (status == 0xffffffff)
2029 2028 goto hw_died;
2030 2029  
2031   - if (!(status & STS_EINT) && !ER_IRQ_PENDING(irq_pending)) {
  2030 + if (!(status & STS_EINT)) {
2032 2031 spin_unlock(&xhci->lock);
2033 2032 xhci_warn(xhci, "Spurious interrupt.\n");
2034 2033 return IRQ_NONE;
2035 2034 }
2036 2035 xhci_dbg(xhci, "op reg status = %08x\n", status);
2037   - xhci_dbg(xhci, "ir set irq_pending = %08x\n", irq_pending);
2038 2036 xhci_dbg(xhci, "Event ring dequeue ptr:\n");
2039 2037 xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
2040 2038 (unsigned long long)
... ... @@ -2063,9 +2061,13 @@
2063 2061 /* FIXME when MSI-X is supported and there are multiple vectors */
2064 2062 /* Clear the MSI-X event interrupt status */
2065 2063  
2066   - /* Acknowledge the interrupt */
2067   - irq_pending |= 0x3;
2068   - xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
  2064 + if (hcd->irq != -1) {
  2065 + u32 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 2072 if (xhci->xhc_state & XHCI_STATE_DYING) {
2071 2073 xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "