By delaying root-hub interrupt handling to the soft interrupt we can
makr ehci(4)'s interrupt handler as IPL_MPSAFE.

Index: dev/pci/ehci_pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/ehci_pci.c,v
retrieving revision 1.27
diff -u -p -r1.27 ehci_pci.c
--- dev/pci/ehci_pci.c  16 May 2014 18:17:03 -0000      1.27
+++ dev/pci/ehci_pci.c  27 Oct 2015 15:39:48 -0000
@@ -171,7 +171,8 @@ ehci_pci_attach(struct device *parent, s
                goto unmap_ret;
        }
        intrstr = pci_intr_string(pc, ih);
-       sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, ehci_intr, sc, devname);
+       sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB | IPL_MPSAFE,
+           ehci_intr, sc, devname);
        if (sc->sc_ih == NULL) {
                printf(": couldn't establish interrupt");
                if (intrstr != NULL)
@@ -204,7 +205,7 @@ ehci_pci_attach(struct device *parent, s
        else
                snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor),
                    "vendor 0x%04x", PCI_VENDOR(pa->pa_id));
-       
+
        /* Enable workaround for dropped interrupts as required */
        if (sc->sc.sc_id_vendor == PCI_VENDOR_VIATECH)
                sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND;
Index: dev/usb/ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.187
diff -u -p -r1.187 ehci.c
--- dev/usb/ehci.c      26 Jun 2015 11:17:34 -0000      1.187
+++ dev/usb/ehci.c      27 Oct 2015 15:40:29 -0000
@@ -540,13 +540,12 @@ ehci_intr1(struct ehci_softc *sc)
                return (0);
 
        EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */
-       sc->sc_bus.intr_context++;
        sc->sc_bus.no_intrs++;
+
        if (eintrs & EHCI_STS_HSE) {
                printf("%s: unrecoverable error, controller halted\n",
                       sc->sc_bus.bdev.dv_xname);
                sc->sc_bus.dying = 1;
-               sc->sc_bus.intr_context--;
                return (1);
        }
        if (eintrs & EHCI_STS_IAA) {
@@ -558,12 +557,11 @@ ehci_intr1(struct ehci_softc *sc)
                eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT);
        }
        if (eintrs & EHCI_STS_PCD) {
-               ehci_pcd(sc, sc->sc_intrxfer);
+               atomic_setbits_int(&sc->sc_flags, EHCIF_PCB_INTR);
+               usb_schedsoftintr(&sc->sc_bus);
                eintrs &= ~EHCI_STS_PCD;
        }
 
-       sc->sc_bus.intr_context--;
-
        if (eintrs != 0) {
                /* Block unprocessed interrupts. */
                sc->sc_eintrs &= ~eintrs;
@@ -644,6 +642,11 @@ ehci_softintr(void *v)
                return;
 
        sc->sc_bus.intr_context++;
+
+       if (sc->sc_flags & EHCIF_PCB_INTR) {
+               atomic_clearbits_int(&sc->sc_flags, EHCIF_PCB_INTR);
+               ehci_pcd(sc, sc->sc_intrxfer);
+       }
 
        /*
         * The only explanation I can think of for why EHCI is as brain dead
Index: dev/usb/ehcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.35
diff -u -p -r1.35 ehcivar.h
--- dev/usb/ehcivar.h   10 Apr 2015 13:56:42 -0000      1.35
+++ dev/usb/ehcivar.h   27 Oct 2015 15:35:26 -0000
@@ -129,6 +129,7 @@ struct ehci_softc {
        u_int sc_offs;                  /* offset to operational regs */
        int sc_flags;                   /* misc flags */
 #define EHCIF_DROPPED_INTR_WORKAROUND  0x01
+#define EHCIF_PCB_INTR                 0x02
 
        char sc_vendor[16];             /* vendor string for root hub */
        int sc_id_vendor;               /* vendor ID for root hub */

Reply via email to