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 */