svn commit: r199166 - stable/8/sys/dev/usb/controller

Andrew Thompson thompsa at FreeBSD.org
Wed Nov 11 01:33:06 UTC 2009


Author: thompsa
Date: Wed Nov 11 01:33:06 2009
New Revision: 199166
URL: http://svn.freebsd.org/changeset/base/199166

Log:
  MFC r199058
  
   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

Modified:
  stable/8/sys/dev/usb/controller/ehci.c
  stable/8/sys/dev/usb/controller/ehci.h
  stable/8/sys/dev/usb/controller/ehci_pci.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/dev/usb/controller/ehci.c
==============================================================================
--- stable/8/sys/dev/usb/controller/ehci.c	Wed Nov 11 01:27:58 2009	(r199165)
+++ stable/8/sys/dev/usb/controller/ehci.c	Wed Nov 11 01:33:06 2009	(r199166)
@@ -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: stable/8/sys/dev/usb/controller/ehci.h
==============================================================================
--- stable/8/sys/dev/usb/controller/ehci.h	Wed Nov 11 01:27:58 2009	(r199165)
+++ stable/8/sys/dev/usb/controller/ehci.h	Wed Nov 11 01:33:06 2009	(r199166)
@@ -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: stable/8/sys/dev/usb/controller/ehci_pci.c
==============================================================================
--- stable/8/sys/dev/usb/controller/ehci_pci.c	Wed Nov 11 01:27:58 2009	(r199165)
+++ stable/8/sys/dev/usb/controller/ehci_pci.c	Wed Nov 11 01:33:06 2009	(r199166)
@@ -441,6 +441,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-stable mailing list