From 8e4265b94d8d4700ea9fb14eb02b3c642ed92b82 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 2 May 2006 16:12:01 +0000 Subject: [PATCH] - Add workarounds for dropped interrupts on VIA and ATI controllers. - Include more vendor IDs. Submitted-by: Gary Taken-from: FreeBSD/NetBSD --- sys/bus/usb/ehci.c | 33 ++++++++++++++++++++++++++++++++- sys/bus/usb/ehci_pci.c | 29 ++++++++++++++++++++++++++++- sys/bus/usb/ehcivar.h | 5 ++++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/sys/bus/usb/ehci.c b/sys/bus/usb/ehci.c index 1f6de150c7..43b64fadf5 100644 --- a/sys/bus/usb/ehci.c +++ b/sys/bus/usb/ehci.c @@ -1,7 +1,7 @@ /* * $NetBSD: ehci.c,v 1.67 2004/07/06 04:18:05 mycroft Exp $ * $FreeBSD: src/sys/dev/usb/ehci.c,v 1.5 2003/11/10 00:20:52 joe Exp $ - * $DragonFly: src/sys/bus/usb/ehci.c,v 1.19 2006/04/29 22:05:21 dillon Exp $ + * $DragonFly: src/sys/bus/usb/ehci.c,v 1.20 2006/05/02 16:12:01 dillon Exp $ */ /* @@ -161,6 +161,7 @@ Static void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *); Static void ehci_idone(struct ehci_xfer *); Static void ehci_timeout(void *); Static void ehci_timeout_task(void *); +Static void ehci_intrlist_timeout(void *); Static usbd_status ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); Static void ehci_freem(struct usbd_bus *, usb_dma_t *); @@ -448,6 +449,7 @@ ehci_init(ehci_softc_t *sc) EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); usb_callout_init(sc->sc_tmo_pcd); + usb_callout_init(sc->sc_tmo_intrlist); lockinit(&sc->sc_doorbell_lock, "ehcidb", 0, 0); @@ -651,6 +653,12 @@ ehci_softintr(void *v) ehci_check_intr(sc, ex); } + /* Schedule a callout to catch any dropped transactions. */ + if ((sc->sc_flags & EHCI_SCFLG_LOSTINTRBUG) && + !LIST_EMPTY(&sc->sc_intrhead)) + usb_callout(sc->sc_tmo_intrlist, hz / 5, ehci_intrlist_timeout, + sc); + #ifdef USB_USE_SOFTINTR if (sc->sc_softwake) { sc->sc_softwake = 0; @@ -878,6 +886,7 @@ ehci_detach(struct ehci_softc *sc, int flags) if (rv != 0) return (rv); + usb_uncallout(sc->sc_tmo_intrlist, ehci_intrlist_timeout, sc); usb_uncallout(sc->sc_tmo_pcd, ehci_pcd_enable, sc); if (sc->sc_powerhook != NULL) @@ -2436,6 +2445,28 @@ ehci_timeout_task(void *addr) DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer)); crit_enter(); ehci_abort_xfer(xfer, USBD_TIMEOUT); + crit_exit();; +} + +/* + * Some EHCI chips from VIA seem to trigger interrupts before writing back the + * qTD status, or miss signalling occasionally under heavy load. If the host + * machine is too fast, we we can miss transaction completion - when we scan + * the active list the transaction still seems to be active. This generally + * exhibits itself as a umass stall that never recovers. + * + * We work around this behaviour by setting up this callback after any softintr + * that completes with transactions still pending, giving us another chance to + * check for completion after the writeback has taken place. + */ +void +ehci_intrlist_timeout(void *arg) +{ + ehci_softc_t *sc = arg; + + DPRINTFN(3, ("ehci_intrlist_timeout\n")); + usb_schedsoftintr(&sc->sc_bus); + crit_exit(); } diff --git a/sys/bus/usb/ehci_pci.c b/sys/bus/usb/ehci_pci.c index 1e2085a39e..ccf1b85fc0 100644 --- a/sys/bus/usb/ehci_pci.c +++ b/sys/bus/usb/ehci_pci.c @@ -34,7 +34,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * $FreeBSD: src/sys/dev/usb/ehci_pci.c,v 1.9 2003/12/17 17:15:41 peter Exp $ - * $DragonFly: src/sys/bus/usb/ehci_pci.c,v 1.9 2005/10/12 17:35:49 dillon Exp $ + * $DragonFly: src/sys/bus/usb/ehci_pci.c,v 1.10 2006/05/02 16:12:01 dillon Exp $ */ /* @@ -87,6 +87,7 @@ #define PCI_EHCI_VENDORID_SIS 0x1039 #define PCI_EHCI_VENDORID_NVIDIA 0x12D2 #define PCI_EHCI_VENDORID_NVIDIA2 0x10DE +#define PCI_EHCI_VENDORID_VIA 0x1106 /* AcerLabs/ALi */ #define PCI_EHCI_DEVICEID_M5239 0x523910b9 @@ -134,6 +135,11 @@ static const char *ehci_device_nf4 = "NVIDIA nForce4 USB 2.0 controller"; #define PCI_EHCI_DEVICEID_ISP156X 0x15621131 static const char *ehci_device_isp156x = "Philips ISP156x USB 2.0 controller"; +/* VIA */ +#define PCI_EHCI_DEVICEID_VIA 0x31041106 +static const char *ehci_device_via = "VIA VT6202 USB 2.0 controller"; + +/* Generic */ static const char *ehci_device_generic = "EHCI (generic) USB 2.0 controller"; #define PCI_EHCI_BASE_REG 0x10 @@ -180,6 +186,8 @@ ehci_pci_match(device_t self) return (ehci_device_nf4); case PCI_EHCI_DEVICEID_ISP156X: return (ehci_device_isp156x); + case PCI_EHCI_DEVICEID_VIA: + return (ehci_device_via); default: if (pci_get_class(self) == PCIC_SERIALBUS && pci_get_subclass(self) == PCIS_SERIALBUS_USB @@ -278,6 +286,9 @@ ehci_pci_attach(device_t self) case PCI_EHCI_VENDORID_CMDTECH: sprintf(sc->sc_vendor, "CMDTECH"); break; + case PCI_EHCI_VENDORID_INTEL: + sprintf(sc->sc_vendor, "Intel"); + break; case PCI_EHCI_VENDORID_NEC: sprintf(sc->sc_vendor, "NEC"); break; @@ -291,6 +302,9 @@ ehci_pci_attach(device_t self) case PCI_EHCI_VENDORID_NVIDIA2: sprintf(sc->sc_vendor, "nVidia"); break; + case PCI_EHCI_VENDORID_VIA: + sprintf(sc->sc_vendor, "VIA"); + break; default: if (bootverbose) device_printf(self, "(New EHCI DeviceId=0x%08x)\n", @@ -307,6 +321,19 @@ ehci_pci_attach(device_t self) return ENXIO; } + /* Enable workaround for dropped interrupts as required */ + switch (pci_get_vendor(self)) { + case PCI_EHCI_VENDORID_ATI: + case PCI_EHCI_VENDORID_VIA: + sc->sc_flags |= EHCI_SCFLG_LOSTINTRBUG; + if (bootverbose) + device_printf(self, + "Dropped interrupts workaround enabled\n"); + break; + default: + break; + } + /* * Find companion controllers. According to the spec they always * have lower function numbers so they should be enumerated already. diff --git a/sys/bus/usb/ehcivar.h b/sys/bus/usb/ehcivar.h index 5f21a22518..515cbdcc10 100644 --- a/sys/bus/usb/ehcivar.h +++ b/sys/bus/usb/ehcivar.h @@ -1,7 +1,7 @@ /* * $NetBSD: ehcivar.h,v 1.19 2005/04/29 15:04:29 augustss Exp $ * $FreeBSD: src/sys/dev/usb/ehcivar.h,v 1.2 2004/08/01 18:47:42 iedowse Exp $ - * $DragonFly: src/sys/bus/usb/ehcivar.h,v 1.6 2005/08/27 14:03:23 asmodai Exp $ + * $DragonFly: src/sys/bus/usb/ehcivar.h,v 1.7 2006/05/02 16:12:01 dillon Exp $ */ /* @@ -89,6 +89,7 @@ struct ehci_soft_islot { #define EHCI_HASH_SIZE 128 #define EHCI_COMPANION_MAX 8 +#define EHCI_SCFLG_LOSTINTRBUG 0x0002 /* workaround for VIA chipsets */ typedef struct ehci_softc { struct usbd_bus sc_bus; /* base device */ @@ -102,6 +103,7 @@ typedef struct ehci_softc { struct resource *irq_res; #endif u_int sc_offs; /* offset to operational regs */ + int sc_flags; /* misc flags */ char sc_vendor[32]; /* vendor string for root hub */ int sc_id_vendor; /* vendor ID for root hub */ @@ -145,6 +147,7 @@ typedef struct ehci_softc { struct lock sc_doorbell_lock; usb_callout_t sc_tmo_pcd; + usb_callout_t sc_tmo_intrlist; #if defined(__NetBSD__) || defined(__OpenBSD__) device_ptr_t sc_child; /* /dev/usb# device */ -- 2.41.0