USB - Reintroduce OHCI fixes without the larger polling infrastructure fixes
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 8 Sep 2009 23:52:33 +0000 (16:52 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 8 Sep 2009 23:52:33 +0000 (16:52 -0700)
* Fix the OHCI interrupt livelock issue.

* Don't fix races with turning polling on and off yet as there appear
  to be other issues with OHCI that break whene we do.

sys/bus/usb/ohci.c
sys/bus/usb/ohcivar.h

index 0f3548a..2a944d9 100644 (file)
@@ -1106,8 +1106,17 @@ ohci_intr(void *p)
        if (sc->sc_dying || (sc->sc_flags & OHCI_SCFLG_DONEINIT) == 0)
                return (0);
 
-       /* If we get an interrupt while polling, then just ignore it. */
+       /*
+        * If we get an interrupt while polling, then remember what it
+        * was and acknowledge it.
+        */
        if (sc->sc_bus.use_polling) {
+               u_int32_t intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);
+
+               intrs &= ~OHCI_MIE;
+               if (intrs)
+                       OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs);
+               sc->sc_dintrs |= intrs;
 #ifdef DIAGNOSTIC
                DPRINTFN(16, ("ohci_intr: ignored interrupt while polling\n"));
 #endif
@@ -1152,11 +1161,14 @@ ohci_intr1(ohci_softc_t *sc)
                        intrs = OHCI_WDH;
                if (done & OHCI_DONE_INTRS) {
                        intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS);
+                       intrs |= sc->sc_dintrs;
                        done &= ~OHCI_DONE_INTRS;
                }
                sc->sc_hcca->hcca_done_head = 0;
        } else {
-               intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & ~OHCI_WDH;
+               intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);
+               intrs |= sc->sc_dintrs;
+               intrs &= ~OHCI_WDH;
        }
 
        if (intrs == 0)         /* nothing to be done (PCI shared interrupt) */
@@ -1164,6 +1176,7 @@ ohci_intr1(ohci_softc_t *sc)
 
        intrs &= ~OHCI_MIE;
        OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); /* Acknowledge */
+       sc->sc_dintrs &= ~intrs;
        eintrs = intrs & sc->sc_eintrs;
        if (!eintrs)
                return (0);
@@ -1634,7 +1647,9 @@ ohci_waitintr(ohci_softc_t *sc, usbd_xfer_handle xfer)
                usb_delay_ms(&sc->sc_bus, 1);
                if (sc->sc_dying)
                        break;
-               intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs;
+               intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);
+               intrs |= sc->sc_dintrs;
+               intrs &= sc->sc_eintrs;
                DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs));
 #ifdef USB_DEBUG
                if (ohcidebug > 15)
index 16eafff..a5e8ee7 100644 (file)
@@ -103,6 +103,7 @@ typedef struct ohci_softc {
        u_int sc_bws[OHCI_NO_INTRS];
 
        u_int32_t sc_eintrs;            /* enabled interrupts */
+       u_int32_t sc_dintrs;            /* delayed interrupts */
 
        ohci_soft_ed_t *sc_isoc_head;
        ohci_soft_ed_t *sc_ctrl_head;