On Tue, Jun 23, 2009 at 06:17:37AM -0400, Brad wrote:
> 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.
And a little simpler over the second rev..
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 11:24:17 -0000
@@ -65,6 +65,11 @@ struct ehci_pci_softc {
void *sc_ih; /* interrupt vectoring */
};
+int ehci_sb700_match(struct pci_attach_args *pa);
+
+#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 +82,6 @@ struct cfattach ehci_pci_ca = {
ehci_pci_detach, ehci_activate
};
-
int
ehci_pci_match(struct device *parent, void *match, void *aux)
{
@@ -122,6 +126,21 @@ 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 &&
+ ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_EHCI ||
+ (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB700_EHCI &&
+ pci_find_device(NULL, ehci_sb700_match))))) {
+ 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);
+ }
+
/* Map and establish the interrupt. */
if (pci_intr_map(pa, &ih)) {
printf(": couldn't map interrupt\n");
@@ -270,4 +289,16 @@ 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);
}
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.