Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: USB troubles with SB600/SB700 chipsets



On Mon, May 18, 2009 at 10:18:04AM +0200, Markus W Kilbinger wrote:
> >>>>> "Christoph" == Christoph Egger <Christoph_Egger%gmx.de@localhost> 
> >>>>> writes:
> 
>     Christoph> hm... maybe the quirk is applied too late. New attached
>     Christoph> patch version applies it *before* the chip is enabled.
> 
> After applying this patch (#3) just leads to:
> 
>   ehci0 at pci0 dev 18 function 2: ATI Technologies SB700/SB800 USB EHCI 
> Controller (rev. 0x00)
>   ehci0: interrupting at ioapic0 pin 17
>   ehci0: dropped intr workaround enabled
>   ehci0: EHCI version 1.0
>   ehci0: companion controllers, 3 ports each: ohci0 ohci1
> 
> , no amdehci (solution) so far. I'll provide some pcictl dump output
> for these devs:

It works for me (after changing it a little bit to not panic with a
DIAGNOSTIC kernel):

amdehci0 at pci0 dev 18 function 2: ATI Technologies SB700/SB800 USB EHCI 
Controller (rev. 0x00)
amdehci0: applying AMD SB600/SB700 USB freeze workaround
ioapic0: int17 0xa062<vector=0x62,delmode=0x0,actlo,level,dest=0x0> 
0x0<target=0x0>
amdehci0: interrupting at ioapic0 pin 17
amdehci0: dropped intr workaround enabled
amdehci0: EHCI version 1.0
amdehci0: companion controllers, 3 ports each: ohci0 ohci1
usb2 at amdehci0: USB revision 2.0

Don't forget to add some lines to your kernel config:

amdehci* at pci? dev ? function ?
usb* at amdehci?

>   $ pcictl /dev/pci0 list
>   [...]
>   000:18:0: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
> interface 0x10)
>   000:18:1: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
> interface 0x10)
>   000:18:2: ATI Technologies SB700/SB800 USB EHCI Controller (USB serial bus, 
> interface 0x20)
>   000:19:0: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
> interface 0x10)
>   000:19:1: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
> interface 0x10)
>   000:19:2: ATI Technologies SB700/SB800 USB EHCI Controller (USB serial bus, 
> interface 0x20)
>   000:20:0: ATI Technologies SB600/SB700/SB800 SMBus Controller (SMBus serial 
> bus, revision 0x3a)

000:18:0: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
interface 0x10)
000:18:1: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
interface 0x10)
000:18:2: ATI Technologies SB700/SB800 USB EHCI Controller (USB serial bus, 
interface 0x20)
000:19:0: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
interface 0x10)
000:19:1: ATI Technologies SB700/SB800 USB OHCI Controller (USB serial bus, 
interface 0x10)
000:19:2: ATI Technologies SB700/SB800 USB EHCI Controller (USB serial bus, 
interface 0x20)
000:20:0: ATI Technologies SB600/SB700/SB800 SMBus Controller (SMBus serial 
bus, revision 0x3a)

[..]

>   pcictl /dev/pci0 dump -d 18       
>   PCI configuration registers:
>     Common header:
>       0x00: 0x43971002 0x02a00117 0x0c031000 0x00804010
>   
>       Vendor Name: ATI Technologies (0x1002)
>       Device Name: SB700/SB800 USB OHCI Controller (0x4397)
[..]

# pcictl pci0 dump -d 18 -f 2
PCI configuration registers:
  Common header:
    0x00: 0x43961002 0x02b00106 0x0c032000 0x00004010

    Vendor Name: ATI Technologies (0x1002)
    Device Name: SB700/SB800 USB EHCI Controller (0x4396)

>   # pcictl /dev/pci0 dump -d 20 
>   PCI configuration registers:
>     Common header:
>       0x00: 0x43851002 0x02300403 0x0c05003a 0x00800000
>   
>       Vendor Name: ATI Technologies (0x1002)
>       Device Name: SB600/SB700/SB800 SMBus Controller (0x4385)
[..]
>       Revision ID: 0x3a
[..]

# pcictl pci0 dump -d 20

PCI configuration registers:
  Common header:
    0x00: 0x43851002 0x02300403 0x0c05003a 0x00800000

    Vendor Name: ATI Technologies (0x1002)
    Device Name: SB600/SB700/SB800 SMBus Controller (0x4385)
[..]
    Revision ID: 0x3a

I have problems with hald, which panics when I insert a usb stick which also
has a cdrom part and there was once a panic while dettaching during a reboot.
Other then that I can finally read from a usb2.0 stick.

I'm not too happy with the new 'device' driver, so here are two patches:
1) a fixed patch to avoid the DIAGNOSTIC panic based on the patch from
   Christoph
2) a patch which doesn't require a new device driver

Here is the kernel output with my patch (#2):

ehci0 at pci0 dev 18 function 2: ATI Technologies SB700/SB800 USB EHCI 
Controller (rev. 0x00)
ehci0: applying AMD SB600/SB700 USB freeze workaround
ioapic0: int17 0xa062<vector=0x62,delmode=0x0,actlo,level,dest=0x0> 
0x0<target=0x0>
ehci0: interrupting at ioapic0 pin 17
ehci0: dropped intr workaround enabled
ehci0: EHCI version 1.0
ehci0: companion controllers, 3 ports each: ohci0 ohci1
usb2 at ehci0: USB revision 2.0

A quick test worked with it.

Bernd

--- ehci_pci.c.orig     2009-04-18 07:18:15.000000000 +0200
+++ ehci_pci.c  2009-06-11 21:08:16.000000000 +0200
@@ -74,9 +74,88 @@
        void                    *sc_ih;         /* interrupt vectoring */
 };
 
+static int (*ehci_pci_applyquirks)(struct ehci_pci_softc *) = NULL;
+
 #define EHCI_MAX_BIOS_WAIT             1000 /* ms */
 
 static int
+ehci_pci_match(device_t, cfdata_t, void *);
+static void ehci_pci_attach(device_t, device_t, void *);
+static int ehci_pci_detach(device_t, int);
+
+CFATTACH_DECL3_NEW(ehci_pci, sizeof(struct ehci_pci_softc),
+    ehci_pci_match, ehci_pci_attach, ehci_pci_detach, ehci_activate, NULL,
+    ehci_childdet, DVF_DETACH_SHUTDOWN);
+
+
+static int amdehci_match(device_t, cfdata_t, void *);
+static void amdehci_attach(device_t, device_t, void *);
+
+CFATTACH_DECL3_NEW(amdehci, sizeof(struct ehci_pci_softc),
+    amdehci_match, amdehci_attach, ehci_pci_detach, ehci_activate, NULL,
+    ehci_childdet, DVF_DETACH_SHUTDOWN);
+
+
+static int
+amdehci_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
+amdehci_match(device_t parent, cfdata_t match, void *aux)
+{
+       struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+
+       if (!(PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
+           PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB &&
+           PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI &&
+           PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI))
+               return 0;
+
+       switch (PCI_PRODUCT(pa->pa_id)) {
+       case PCI_PRODUCT_ATI_SB600_USB_EHCI:
+               return 10;      /* beat ehci_pci */
+       case PCI_PRODUCT_ATI_SB700_USB_EHCI:
+               if (pci_find_device(NULL, amdehci_sb700_match))
+                       return 10;      /* beat ehci_pci */
+       default:
+               return 0;
+       }
+}
+
+static int
+amdehci_applyquirks(struct ehci_pci_softc *sc)
+{
+       uint32_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, 0x50);
+       value |= (1U << 27);
+       pci_conf_write(sc->sc_pc, sc->sc_tag, 0x50, value);
+
+        return 0;
+}
+
+static void
+amdehci_attach(device_t parent, device_t self, void *aux)
+{
+       ehci_pci_applyquirks = amdehci_applyquirks;
+       ehci_pci_attach(parent, self, aux);
+}
+
+static int
 ehci_pci_match(device_t parent, cfdata_t match, void *aux)
 {
        struct pci_attach_args *pa = (struct pci_attach_args *) aux;
@@ -126,6 +205,9 @@
        sc->sc_tag = tag;
        sc->sc.sc_bus.dmatag = pa->pa_dmat;
 
+       if (ehci_pci_applyquirks)
+               ehci_pci_applyquirks(sc);
+
        /* Enable the device. */
        csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
@@ -248,10 +330,6 @@
        return 0;
 }
 
-CFATTACH_DECL3_NEW(ehci_pci, sizeof(struct ehci_pci_softc),
-    ehci_pci_match, ehci_pci_attach, ehci_pci_detach, ehci_activate, NULL,
-    ehci_childdet, DVF_DETACH_SHUTDOWN);
-
 #ifdef EHCI_DEBUG
 static void
 ehci_dump_caps(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag)
--- files.pci.orig      2009-02-20 22:36:25.000000000 +0100
+++ files.pci   2009-06-11 16:36:43.000000000 +0200
@@ -588,9 +588,13 @@
 attach ohci at pci with ohci_pci
 file   dev/pci/ohci_pci.c              ohci_pci
 
+# AMD SB600/SB700 EHCI USB controller
+device  amdehci: usbus, usbroothub
+attach amdehci at pci
+
 # EHCI USB controller
 attach ehci at pci with ehci_pci
-file   dev/pci/ehci_pci.c              ehci_pci
+file   dev/pci/ehci_pci.c              ehci_pci | amdehci
 
 file   dev/pci/usb_pci.c               ehci_pci | ehci_cardbus
 
--- ehci_pci.c.orig     2009-04-18 07:18:15.000000000 +0200
+++ ehci_pci.c  2009-06-12 00:12:30.000000000 +0200
@@ -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,6 +86,11 @@
        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
@@ -105,6 +122,7 @@
        usbd_status r;
        int ncomp;
        struct usb_pci *up;
+       int quirk;
 
        sc->sc.sc_dev = self;
        sc->sc.sc_bus.hci_private = sc;
@@ -115,6 +133,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)) {
@@ -126,6 +148,15 @@
        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);
+       case EHCI_PCI_QUIRK_AMD_SB700:
+               if (pci_find_device(NULL, ehci_sb700_match))
+                       ehci_apply_amd_quirks(sc);
+       }
+
        /* Enable the device. */
        csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
@@ -386,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)
+{
+       uint32_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, 0x50);
+       value |= (1U << 27);
+       pci_conf_write(sc->sc_pc, sc->sc_tag, 0x50, value);
+
+        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 < (sizeof ehci_pci_quirks / sizeof ehci_pci_quirks[0]);
+           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