Split xhci_irq() into top and bottom half
handlers. Note that to make this work, we had to fix
MSI interrupts as well to use threaded_irqs.

Signed-off-by: Felipe Balbi <felipe.ba...@linux.intel.com>
---
 drivers/usb/host/xhci-ring.c | 70 +++++++++++++++++++++++++++++---------------
 drivers/usb/host/xhci.c      | 15 +++++-----
 drivers/usb/host/xhci.h      |  2 ++
 3 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7cf66212ceae..695b04d7751e 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2679,36 +2679,18 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
        return 1;
 }
 
-/*
- * xHCI spec says we can get an interrupt, and if the HC has an error 
condition,
- * we might get bad data out of the event ring.  Section 4.10.2.7 has a list of
- * indicators of an event TRB error, but we check the status *first* to be 
safe.
- */
-irqreturn_t xhci_irq(struct usb_hcd *hcd)
+irqreturn_t xhci_threaded_irq(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        u32 status;
        u64 temp_64;
        union xhci_trb *event_ring_deq;
        dma_addr_t deq;
+       unsigned long flags;
 
-       spin_lock(&xhci->lock);
+       spin_lock_irqsave(&xhci->lock, flags);
        /* Check if the xHC generated the interrupt, or the irq is shared */
        status = readl(&xhci->op_regs->status);
-       if (status == 0xffffffff)
-               goto hw_died;
-
-       if (!(status & STS_EINT)) {
-               spin_unlock(&xhci->lock);
-               return IRQ_NONE;
-       }
-       if (status & STS_FATAL) {
-               xhci_warn(xhci, "WARNING: Host System Error\n");
-               xhci_halt(xhci);
-hw_died:
-               spin_unlock(&xhci->lock);
-               return IRQ_HANDLED;
-       }
 
        /*
         * Clear the op reg interrupt status first,
@@ -2737,7 +2719,7 @@ hw_died:
                temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
                xhci_write_64(xhci, temp_64 | ERST_EHB,
                                &xhci->ir_set->erst_dequeue);
-               spin_unlock(&xhci->lock);
+               spin_unlock_irqrestore(&xhci->lock, flags);
 
                return IRQ_HANDLED;
        }
@@ -2765,11 +2747,53 @@ hw_died:
        temp_64 |= ERST_EHB;
        xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
 
-       spin_unlock(&xhci->lock);
+       spin_unlock_irqrestore(&xhci->lock, flags);
 
        return IRQ_HANDLED;
 }
 
+/*
+ * xHCI spec says we can get an interrupt, and if the HC has an error 
condition,
+ * we might get bad data out of the event ring.  Section 4.10.2.7 has a list of
+ * indicators of an event TRB error, but we check the status *first* to be 
safe.
+ */
+irqreturn_t xhci_irq(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       u32 status;
+
+       /* Check if the xHC generated the interrupt, or the irq is shared */
+       status = readl(&xhci->op_regs->status);
+       if (status == 0xffffffff)
+               return IRQ_HANDLED;
+
+       if (!(status & STS_EINT))
+               return IRQ_NONE;
+
+       if (status & STS_FATAL) {
+               xhci_warn(xhci, "WARNING: Host System Error\n");
+               xhci_halt(xhci);
+               return IRQ_HANDLED;
+       }
+
+       /*
+        * Clear the op reg interrupt status first,
+        * so we can receive interrupts from other MSI-X interrupters.
+        * Write 1 to clear the interrupt status.
+        */
+       status |= STS_EINT;
+       writel(status, &xhci->op_regs->status);
+       /* FIXME when MSI-X is supported and there are multiple vectors */
+       /* Clear the MSI-X event interrupt status */
+
+       return IRQ_WAKE_THREAD;
+}
+
+irqreturn_t xhci_msi_threaded_irq(int irq, void *hcd)
+{
+       return xhci_threaded_irq(hcd);
+}
+
 irqreturn_t xhci_msi_irq(int irq, void *hcd)
 {
        return xhci_irq(hcd);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index d51ee0c3cf9f..13af72be51c6 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -239,8 +239,8 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
                return ret;
        }
 
-       ret = request_irq(pdev->irq, xhci_msi_irq,
-                               0, "xhci_hcd", xhci_to_hcd(xhci));
+       ret = request_threaded_irq(pdev->irq, xhci_msi_irq, 
xhci_msi_threaded_irq,
+                               IRQF_ONESHOT, "xhci_hcd", xhci_to_hcd(xhci));
        if (ret) {
                xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                                "disable MSI interrupt");
@@ -312,9 +312,9 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
        }
 
        for (i = 0; i < xhci->msix_count; i++) {
-               ret = request_irq(xhci->msix_entries[i].vector,
-                               xhci_msi_irq,
-                               0, "xhci_hcd", xhci_to_hcd(xhci));
+               ret = request_threaded_irq(xhci->msix_entries[i].vector,
+                               xhci_msi_irq, xhci_msi_threaded_irq,
+                               IRQF_ONESHOT, "xhci_hcd", xhci_to_hcd(xhci));
                if (ret)
                        goto disable_msix;
        }
@@ -408,8 +408,8 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
                         hcd->driver->description, hcd->self.busnum);
 
        /* fall back to legacy interrupt*/
-       ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
-                       hcd->irq_descr, hcd);
+       ret = request_threaded_irq(pdev->irq, usb_hcd_irq, usb_hcd_threaded_irq,
+                       IRQF_SHARED | IRQF_ONESHOT, hcd->irq_descr, hcd);
        if (ret) {
                xhci_err(xhci, "request interrupt %d failed\n",
                                pdev->irq);
@@ -4989,6 +4989,7 @@ static const struct hc_driver xhci_hc_driver = {
         * generic hardware linkage
         */
        .irq =                  xhci_irq,
+       .threaded_irq =         xhci_threaded_irq,
        .flags =                HCD_MEMORY | HCD_USB3 | HCD_SHARED,
 
        /*
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index e293e0974f48..a65ccf4b5a0b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1851,6 +1851,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
 int xhci_get_frame(struct usb_hcd *hcd);
 irqreturn_t xhci_irq(struct usb_hcd *hcd);
 irqreturn_t xhci_msi_irq(int irq, void *hcd);
+irqreturn_t xhci_threaded_irq(struct usb_hcd *hcd);
+irqreturn_t xhci_msi_threaded_irq(int irq, void *hcd);
 int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
 void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
 int xhci_alloc_tt_info(struct xhci_hcd *xhci,
-- 
2.8.0.rc2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to