Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 9 Feb 2010 00:38:40 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r203693 - head/sys/dev/usb/controller
Message-ID:  <201002090038.o190ceuT004528@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Tue Feb  9 00:38:40 2010
New Revision: 203693
URL: http://svn.freebsd.org/changeset/base/203693

Log:
  Disable the use of the IAAD usb doorbell on NVidia controllers as it can cause
  the hardware to stall.
  
  Submitted by:	Hans Petter Selasky

Modified:
  head/sys/dev/usb/controller/ehci.c
  head/sys/dev/usb/controller/ehci.h
  head/sys/dev/usb/controller/ehci_pci.c

Modified: head/sys/dev/usb/controller/ehci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci.c	Mon Feb  8 23:30:28 2010	(r203692)
+++ head/sys/dev/usb/controller/ehci.c	Tue Feb  9 00:38:40 2010	(r203693)
@@ -92,15 +92,23 @@ __FBSDID("$FreeBSD$");
 #if USB_DEBUG
 static int ehcidebug = 0;
 static int ehcinohighspeed = 0;
+static int ehciiaadbug = 0;
+static int ehcilostintrbug = 0;
 
 SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci");
 SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW,
     &ehcidebug, 0, "Debug level");
 SYSCTL_INT(_hw_usb_ehci, OID_AUTO, no_hs, CTLFLAG_RW,
     &ehcinohighspeed, 0, "Disable High Speed USB");
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, iaadbug, CTLFLAG_RW,
+    &ehciiaadbug, 0, "Enable doorbell bug workaround");
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, lostintrbug, CTLFLAG_RW,
+    &ehcilostintrbug, 0, "Enable lost interrupt bug workaround");
 
 TUNABLE_INT("hw.usb.ehci.debug", &ehcidebug);
 TUNABLE_INT("hw.usb.ehci.no_hs", &ehcinohighspeed);
+TUNABLE_INT("hw.usb.ehci.iaadbug", &ehciiaadbug);
+TUNABLE_INT("hw.usb.ehci.lostintrbug", &ehcilostintrbug);
 
 static void ehci_dump_regs(ehci_softc_t *sc);
 static void ehci_dump_sqh(ehci_softc_t *sc, ehci_qh_t *sqh);
@@ -251,6 +259,10 @@ ehci_init(ehci_softc_t *sc)
 	usb_callout_init_mtx(&sc->sc_tmo_poll, &sc->sc_bus.bus_mtx, 0);
 
 #if USB_DEBUG
+	if (ehciiaadbug)
+		sc->sc_flags |= EHCI_SCFLG_IAADBUG;
+	if (ehcilostintrbug)
+		sc->sc_flags |= EHCI_SCFLG_LOSTINTRBUG;
 	if (ehcidebug > 2) {
 		ehci_dump_regs(sc);
 	}
@@ -2280,6 +2292,13 @@ ehci_device_bulk_start(struct usb_xfer *
 	/* put transfer on interrupt queue */
 	ehci_transfer_intr_enqueue(xfer);
 
+	/* 
+	 * XXX Certain nVidia chipsets choke when using the IAAD
+	 * feature too frequently.
+	 */
+	if (sc->sc_flags & EHCI_SCFLG_IAADBUG)
+		return;
+
 	/* XXX Performance quirk: Some Host Controllers have a too low
 	 * interrupt rate. Issue an IAAD to stimulate the Host
 	 * Controller after queueing the BULK transfer.

Modified: head/sys/dev/usb/controller/ehci.h
==============================================================================
--- head/sys/dev/usb/controller/ehci.h	Mon Feb  8 23:30:28 2010	(r203692)
+++ head/sys/dev/usb/controller/ehci.h	Tue Feb  9 00:38:40 2010	(r203693)
@@ -350,6 +350,7 @@ typedef struct ehci_softc {
 #define	EHCI_SCFLG_BIGEMMIO	0x0010	/* big-endian byte order MMIO */
 #define	EHCI_SCFLG_TT		0x0020	/* transaction translator present */
 #define	EHCI_SCFLG_LOSTINTRBUG	0x0040	/* workaround for VIA / ATI chipsets */
+#define	EHCI_SCFLG_IAADBUG	0x0080	/* workaround for nVidia chipsets */
 
 	uint8_t	sc_offs;		/* offset to operational registers */
 	uint8_t	sc_doorbell_disable;	/* set on doorbell failure */

Modified: head/sys/dev/usb/controller/ehci_pci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci_pci.c	Mon Feb  8 23:30:28 2010	(r203692)
+++ head/sys/dev/usb/controller/ehci_pci.c	Tue Feb  9 00:38:40 2010	(r203693)
@@ -466,6 +466,19 @@ ehci_pci_attach(device_t self)
 		break;
 	}
 
+	/* Doorbell feature workaround */
+	switch (pci_get_vendor(self)) {
+	case PCI_EHCI_VENDORID_NVIDIA:
+	case PCI_EHCI_VENDORID_NVIDIA2:
+		sc->sc_flags |= EHCI_SCFLG_IAADBUG;
+		if (bootverbose)
+			device_printf(self,
+			    "Doorbell workaround enabled\n");
+		break;
+	default:
+		break;
+	}
+
 	err = ehci_init(sc);
 	if (!err) {
 		err = device_probe_and_attach(sc->sc_bus.bdev);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002090038.o190ceuT004528>