svn commit: r199058 - head/sys/dev/usb/controller

Andrew Thompson thompsa at FreeBSD.org
Sun Nov 8 20:51:16 UTC 2009


Author: thompsa
Date: Sun Nov  8 20:51:15 2009
New Revision: 199058
URL: http://svn.freebsd.org/changeset/base/199058

Log:
  Integrate lost interrupts patch from the old USB stack.
  
  Some EHCI chips from VIA / ATI 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 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
  
  Submitted by:	Alexander Nedotsuko
  MFC after:	3 days

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	Sun Nov  8 20:44:55 2009	(r199057)
+++ head/sys/dev/usb/controller/ehci.c	Sun Nov  8 20:51:15 2009	(r199058)
@@ -113,10 +113,12 @@ extern struct usb_pipe_methods ehci_devi
 extern struct usb_pipe_methods ehci_device_isoc_fs_methods;
 extern struct usb_pipe_methods ehci_device_isoc_hs_methods;
 
-static void ehci_do_poll(struct usb_bus *bus);
-static void ehci_device_done(struct usb_xfer *xfer, usb_error_t error);
-static uint8_t ehci_check_transfer(struct usb_xfer *xfer);
-static void ehci_timeout(void *arg);
+static void ehci_do_poll(struct usb_bus *);
+static void ehci_device_done(struct usb_xfer *, usb_error_t);
+static uint8_t ehci_check_transfer(struct usb_xfer *);
+static void ehci_timeout(void *);
+static void ehci_poll_timeout(void *);
+
 static void ehci_root_intr(ehci_softc_t *sc);
 
 struct ehci_std_temp {
@@ -243,6 +245,7 @@ ehci_init(ehci_softc_t *sc)
 	DPRINTF("start\n");
 
 	usb_callout_init_mtx(&sc->sc_tmo_pcd, &sc->sc_bus.bus_mtx, 0);
+	usb_callout_init_mtx(&sc->sc_tmo_poll, &sc->sc_bus.bus_mtx, 0);
 
 #if USB_DEBUG
 	if (ehcidebug > 2) {
@@ -520,6 +523,7 @@ ehci_detach(ehci_softc_t *sc)
 	USB_BUS_LOCK(&sc->sc_bus);
 
 	usb_callout_stop(&sc->sc_tmo_pcd);
+	usb_callout_stop(&sc->sc_tmo_poll);
 
 	EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
 	USB_BUS_UNLOCK(&sc->sc_bus);
@@ -532,6 +536,7 @@ ehci_detach(ehci_softc_t *sc)
 	usb_pause_mtx(NULL, hz / 20);
 
 	usb_callout_drain(&sc->sc_tmo_pcd);
+	usb_callout_drain(&sc->sc_tmo_poll);
 }
 
 void
@@ -1472,6 +1477,28 @@ repeat:
 	}
 }
 
+/*
+ * Some EHCI chips from VIA / ATI 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 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.
+ */
+static void
+ehci_poll_timeout(void *arg)
+{
+	ehci_softc_t *sc = arg;
+
+	DPRINTFN(3, "\n");
+	ehci_interrupt_poll(sc);
+}
+
 /*------------------------------------------------------------------------*
  *	ehci_interrupt - EHCI interrupt handler
  *
@@ -1539,6 +1566,11 @@ ehci_interrupt(ehci_softc_t *sc)
 	/* poll all the USB transfers */
 	ehci_interrupt_poll(sc);
 
+	if (sc->sc_flags & EHCI_SCFLG_LOSTINTRBUG) {
+		usb_callout_reset(&sc->sc_tmo_poll, hz / 128,
+		    (void *)&ehci_poll_timeout, sc);
+	}
+
 done:
 	USB_BUS_UNLOCK(&sc->sc_bus);
 }

Modified: head/sys/dev/usb/controller/ehci.h
==============================================================================
--- head/sys/dev/usb/controller/ehci.h	Sun Nov  8 20:44:55 2009	(r199057)
+++ head/sys/dev/usb/controller/ehci.h	Sun Nov  8 20:51:15 2009	(r199058)
@@ -321,6 +321,7 @@ typedef struct ehci_softc {
 	struct ehci_hw_softc sc_hw;
 	struct usb_bus sc_bus;		/* base device */
 	struct usb_callout sc_tmo_pcd;
+	struct usb_callout sc_tmo_poll;
 	union ehci_hub_desc sc_hub_desc;
 
 	struct usb_device *sc_devices[EHCI_MAX_DEVICES];
@@ -348,6 +349,7 @@ typedef struct ehci_softc {
 #define	EHCI_SCFLG_BIGEDESC	0x0008	/* big-endian byte order descriptors */
 #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 */
 
 	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	Sun Nov  8 20:44:55 2009	(r199057)
+++ head/sys/dev/usb/controller/ehci_pci.c	Sun Nov  8 20:51:15 2009	(r199058)
@@ -439,6 +439,19 @@ ehci_pci_attach(device_t self)
 		break;
 	}
 
+	/* Dropped interrupts workaround */
+	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;
+	}
+
 	err = ehci_init(sc);
 	if (!err) {
 		err = device_probe_and_attach(sc->sc_bus.bdev);


More information about the svn-src-all mailing list