Disable the use of the IAAD usb doorbell on NVidia controllers as it can cause
the hardware to stall. Submitted by: Hans Petter Selasky
This commit is contained in:
parent
ee158a7fc4
commit
cf223a88bc
@ -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 *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.
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user