NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/40056: ATI SB700/SB800 ehci problem with uhub's
Please try attached patch!
Christoph
Index: ehci_pci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/ehci_pci.c,v
retrieving revision 1.44
diff -u -p -r1.44 ehci_pci.c
--- ehci_pci.c 26 Apr 2009 09:47:31 -0000 1.44
+++ ehci_pci.c 12 Jun 2009 09:27:27 -0000
@@ -60,6 +60,18 @@ extern int ehcidebug;
#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,6 +86,11 @@ struct ehci_pci_softc {
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 */
static int
@@ -104,6 +121,7 @@ ehci_pci_attach(device_t parent, device_
usbd_status r;
int ncomp;
struct usb_pci *up;
+ int quirk;
sc->sc.sc_dev = self;
sc->sc.sc_bus.hci_private = sc;
@@ -114,6 +132,10 @@ ehci_pci_attach(device_t parent, device_
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)) {
@@ -131,6 +153,17 @@ ehci_pci_attach(device_t parent, device_
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,
@@ -403,3 +436,50 @@ ehci_pci_resume(device_t dv PMF_FN_ARGS)
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;
+}
+
+#define EHCI_SBx00_WORKAROUND_REG 0x50
+#define EHCI_SBx00_WORKAROUND_ENABLE __BIT(27)
+
+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;
+}
+
Home |
Main Index |
Thread Index |
Old Index