On Tue, Jun 23, 2009 at 05:06:19AM -0400, Brad wrote:
> The following diff for the ATI SB600 / SB700 chipsets needs testing
> with the EHCI controller. There is a temporary printf to see when the
> workaround is being applied.
>
> Attached patch is intended to avoid USB subsystem hang symptoms on
> all ATI SB600 revisions and ATI SB700 south bridge revisions A12 and A13.
>
> The USB subsystem hang symptom is observed when the system has multiple
> USB devices connected to it. 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.
>
> From NetBSD (also in Linux)
Ok well as kettenis pointed out the previous diff was a bit overkill
for infrastructure to do the job.. this is much simpler.
Index: ehci_pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/ehci_pci.c,v
retrieving revision 1.15
diff -u -p -r1.15 ehci_pci.c
--- ehci_pci.c 29 Mar 2009 21:53:52 -0000 1.15
+++ ehci_pci.c 23 Jun 2009 10:12:16 -0000
@@ -65,6 +65,12 @@ struct ehci_pci_softc {
void *sc_ih; /* interrupt vectoring */
};
+int ehci_sb700_match(struct pci_attach_args *pa);
+int ehci_apply_ati_quirks(struct ehci_pci_softc *sc);
+
+#define EHCI_SBx00_WORKAROUND_REG 0x50
+#define EHCI_SBx00_WORKAROUND_ENABLE (1 << 3)
+
int ehci_pci_match(struct device *, void *, void *);
void ehci_pci_attach(struct device *, struct device *, void *);
int ehci_pci_detach(struct device *, int);
@@ -77,7 +83,6 @@ struct cfattach ehci_pci_ca = {
ehci_pci_detach, ehci_activate
};
-
int
ehci_pci_match(struct device *parent, void *match, void *aux)
{
@@ -122,6 +127,19 @@ ehci_pci_attach(struct device *parent, s
DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs));
EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
+ /* Handle quirks */
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI) {
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_ATI_SB600_EHCI:
+ ehci_apply_ati_quirks(sc);
+ break;
+ case PCI_PRODUCT_ATI_SB700_EHCI:
+ if (pci_find_device(NULL, ehci_sb700_match))
+ ehci_apply_ati_quirks(sc);
+ break;
+ }
+ }
+
/* Map and establish the interrupt. */
if (pci_intr_map(pa, &ih)) {
printf(": couldn't map interrupt\n");
@@ -270,4 +288,30 @@ ehci_pci_shutdown(void *v)
/* best not to do this anymore; BIOS SMM spins? */
ehci_pci_givecontroller(sc);
#endif
+}
+
+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_SBX00_SMB &&
+ (PCI_REVISION(pa->pa_class) == 0x3a ||
+ PCI_REVISION(pa->pa_class) == 0x3b))
+ return (1);
+
+ return (0);
+}
+
+int
+ehci_apply_ati_quirks(struct ehci_pci_softc *sc)
+{
+ pcireg_t value;
+
+ printf(", applying ATI SB600/SB700 workaround");
+ 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);
}
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.