From fb78b32307709090440c198055ab5a88637ae3bd Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 8 Sep 2009 16:52:33 -0700 Subject: [PATCH] USB - Reintroduce OHCI fixes without the larger polling infrastructure fixes * 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 | 21 ++++++++++++++++++--- sys/bus/usb/ohcivar.h | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/sys/bus/usb/ohci.c b/sys/bus/usb/ohci.c index 0f3548a48e..2a944d9525 100644 --- a/sys/bus/usb/ohci.c +++ b/sys/bus/usb/ohci.c @@ -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) diff --git a/sys/bus/usb/ohcivar.h b/sys/bus/usb/ohcivar.h index 16eafffda1..a5e8ee70b6 100644 --- a/sys/bus/usb/ohcivar.h +++ b/sys/bus/usb/ohcivar.h @@ -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; -- 2.41.0