Module Name:    src
Committed By:   bouyer
Date:           Wed Jun 17 20:33:39 UTC 2009

Modified Files:
        src/sys/dev/pci [netbsd-5]: ehci_pci.c

Log Message:
Pull up following revision(s) (requested by cegger in ticket #814):
        sys/dev/pci/ehci_pci.c: revision 1.45
Apply hw workaround required for all SB600 revisions and SB700 revisions
A12 and A13 to avoid USB subsystem hang symptom. The USB subsystem hang
symptom is observed when the system has multiple USB devices connected to it
or one USB device is often re-connected. In some cases a USB hub may be
required to observe this symptom.
This patch works around the problem by correcting the internal register setting
that will help by changing the behavior of the internal logic to avoid the
USB subsystem hang issue. The change in the behavior of the logic does not
impact the normal operation of the USB subsystem.
This fix has been discussed, developped, reviewed, polished up
and tested on current-users by several people. Thread starts at:
http://mail-index.netbsd.org/current-users/2009/05/17/msg009460.html


To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.38.10.1 src/sys/dev/pci/ehci_pci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/ehci_pci.c
diff -u src/sys/dev/pci/ehci_pci.c:1.38 src/sys/dev/pci/ehci_pci.c:1.38.10.1
--- src/sys/dev/pci/ehci_pci.c:1.38	Mon Apr 28 20:23:54 2008
+++ src/sys/dev/pci/ehci_pci.c	Wed Jun 17 20:33:39 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehci_pci.c,v 1.38 2008/04/28 20:23:54 martin Exp $	*/
+/*	$NetBSD: ehci_pci.c,v 1.38.10.1 2009/06/17 20:33:39 bouyer Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.38 2008/04/28 20:23:54 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.38.10.1 2009/06/17 20:33:39 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -60,6 +60,18 @@
 #define DPRINTF(x)
 #endif
 
+enum ehci_pci_quirk_flags {
+	EHCI_PCI_QUIRK_AMD_SB600 = 0x1,	/* always need a quirk */
+	EHCI_PCI_QUIRK_AMD_SB700 = 0x2,	/* depends on the SMB revision */
+};
+
+static const struct pci_quirkdata ehci_pci_quirks[] = {
+	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_USB_EHCI,
+	    EHCI_PCI_QUIRK_AMD_SB600 },
+	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_USB_EHCI,
+	    EHCI_PCI_QUIRK_AMD_SB700 },
+};
+
 static void ehci_release_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc,
 				   pcitag_t tag);
 static void ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc,
@@ -74,7 +86,15 @@
 	void 			*sc_ih;		/* interrupt vectoring */
 };
 
+static int ehci_sb700_match(struct pci_attach_args *pa);
+static int ehci_apply_amd_quirks(struct ehci_pci_softc *sc);
+enum ehci_pci_quirk_flags ehci_pci_lookup_quirkdata(pci_vendor_id_t,
+	pci_product_id_t);
+
 #define EHCI_MAX_BIOS_WAIT		1000 /* ms */
+#define EHCI_SBx00_WORKAROUND_REG	0x50
+#define EHCI_SBx00_WORKAROUND_ENABLE	__BIT(27)
+
 
 static int
 ehci_pci_match(struct device *parent, struct cfdata *match,
@@ -106,6 +126,7 @@
 	usbd_status r;
 	int ncomp;
 	struct usb_pci *up;
+	int quirk;
 
 	sc->sc.sc_dev = self;
 	sc->sc.sc_bus.hci_private = sc;
@@ -116,6 +137,10 @@
 	aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
 	    PCI_REVISION(pa->pa_class));
 
+	/* Check for quirks */
+	quirk = ehci_pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id),
+					   PCI_PRODUCT(pa->pa_id));
+
 	/* Map I/O registers */
 	if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
 			   &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) {
@@ -127,6 +152,17 @@
 	sc->sc_tag = tag;
 	sc->sc.sc_bus.dmatag = pa->pa_dmat;
 
+	/* Handle quirks */
+	switch (quirk) {
+	case EHCI_PCI_QUIRK_AMD_SB600:
+		ehci_apply_amd_quirks(sc);
+		break;
+	case EHCI_PCI_QUIRK_AMD_SB700:
+		if (pci_find_device(NULL, ehci_sb700_match))
+			ehci_apply_amd_quirks(sc);
+		break;
+	}
+
 	/* Enable the device. */
 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
 	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
@@ -381,3 +417,47 @@
 	ehci_get_ownership(&sc->sc, sc->sc_pc, sc->sc_tag);
 	return ehci_resume(dv PMF_FN_CALL);
 }
+
+static int
+ehci_sb700_match(struct pci_attach_args *pa)
+{
+	if (!(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI &&
+	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_SMB))
+		return 0;
+
+	switch (PCI_REVISION(pa->pa_class)) {
+	case 0x3a:
+	case 0x3b:
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+ehci_apply_amd_quirks(struct ehci_pci_softc *sc)
+{
+	pcireg_t value;
+ 
+	aprint_normal_dev(sc->sc.sc_dev,
+	    "applying AMD SB600/SB700 USB freeze workaround\n");
+	value = pci_conf_read(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG);
+	pci_conf_write(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG,
+	    value | EHCI_SBx00_WORKAROUND_ENABLE);
+
+	return 0;
+}
+
+enum ehci_pci_quirk_flags
+ehci_pci_lookup_quirkdata(pci_vendor_id_t vendor, pci_product_id_t product)
+{
+	int i;
+
+	for (i = 0; i < __arraycount(ehci_pci_quirks); i++) {
+		if (vendor == ehci_pci_quirks[i].vendor &&
+		    product == ehci_pci_quirks[i].product)
+			return ehci_pci_quirks[i].quirks;
+	}
+	return 0;
+}
+

Reply via email to