Wed Jun 17 20:33:39 2009 UTC ()
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


(bouyer)
diff -r1.38 -r1.38.10.1 src/sys/dev/pci/ehci_pci.c

cvs diff -r1.38 -r1.38.10.1 src/sys/dev/pci/ehci_pci.c (expand / switch to unified diff)

--- src/sys/dev/pci/ehci_pci.c 2008/04/28 20:23:54 1.38
+++ src/sys/dev/pci/ehci_pci.c 2009/06/17 20:33:39 1.38.10.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ehci_pci.c,v 1.38 2008/04/28 20:23:54 martin Exp $ */ 1/* $NetBSD: ehci_pci.c,v 1.38.10.1 2009/06/17 20:33:39 bouyer Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. 4 * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net). 8 * by Lennart Augustsson (lennart@augustsson.net).
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -20,27 +20,27 @@ @@ -20,27 +20,27 @@
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.38 2008/04/28 20:23:54 martin Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.38.10.1 2009/06/17 20:33:39 bouyer Exp $");
34 34
35#include <sys/param.h> 35#include <sys/param.h>
36#include <sys/systm.h> 36#include <sys/systm.h>
37#include <sys/kernel.h> 37#include <sys/kernel.h>
38#include <sys/device.h> 38#include <sys/device.h>
39#include <sys/proc.h> 39#include <sys/proc.h>
40#include <sys/queue.h> 40#include <sys/queue.h>
41 41
42#include <sys/bus.h> 42#include <sys/bus.h>
43 43
44#include <dev/pci/pcidevs.h> 44#include <dev/pci/pcidevs.h>
45#include <dev/pci/pcivar.h> 45#include <dev/pci/pcivar.h>
46#include <dev/pci/usb_pci.h> 46#include <dev/pci/usb_pci.h>
@@ -50,41 +50,61 @@ __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v @@ -50,41 +50,61 @@ __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v
50#include <dev/usb/usbdivar.h> 50#include <dev/usb/usbdivar.h>
51#include <dev/usb/usb_mem.h> 51#include <dev/usb/usb_mem.h>
52 52
53#include <dev/usb/ehcireg.h> 53#include <dev/usb/ehcireg.h>
54#include <dev/usb/ehcivar.h> 54#include <dev/usb/ehcivar.h>
55 55
56#ifdef EHCI_DEBUG 56#ifdef EHCI_DEBUG
57#define DPRINTF(x) if (ehcidebug) printf x 57#define DPRINTF(x) if (ehcidebug) printf x
58extern int ehcidebug; 58extern int ehcidebug;
59#else 59#else
60#define DPRINTF(x) 60#define DPRINTF(x)
61#endif 61#endif
62 62
 63enum ehci_pci_quirk_flags {
 64 EHCI_PCI_QUIRK_AMD_SB600 = 0x1, /* always need a quirk */
 65 EHCI_PCI_QUIRK_AMD_SB700 = 0x2, /* depends on the SMB revision */
 66};
 67
 68static const struct pci_quirkdata ehci_pci_quirks[] = {
 69 { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_USB_EHCI,
 70 EHCI_PCI_QUIRK_AMD_SB600 },
 71 { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_USB_EHCI,
 72 EHCI_PCI_QUIRK_AMD_SB700 },
 73};
 74
63static void ehci_release_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, 75static void ehci_release_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc,
64 pcitag_t tag); 76 pcitag_t tag);
65static void ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, 77static void ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc,
66 pcitag_t tag); 78 pcitag_t tag);
67static bool ehci_pci_suspend(device_t PMF_FN_PROTO); 79static bool ehci_pci_suspend(device_t PMF_FN_PROTO);
68static bool ehci_pci_resume(device_t PMF_FN_PROTO); 80static bool ehci_pci_resume(device_t PMF_FN_PROTO);
69 81
70struct ehci_pci_softc { 82struct ehci_pci_softc {
71 ehci_softc_t sc; 83 ehci_softc_t sc;
72 pci_chipset_tag_t sc_pc; 84 pci_chipset_tag_t sc_pc;
73 pcitag_t sc_tag; 85 pcitag_t sc_tag;
74 void *sc_ih; /* interrupt vectoring */ 86 void *sc_ih; /* interrupt vectoring */
75}; 87};
76 88
 89static int ehci_sb700_match(struct pci_attach_args *pa);
 90static int ehci_apply_amd_quirks(struct ehci_pci_softc *sc);
 91enum ehci_pci_quirk_flags ehci_pci_lookup_quirkdata(pci_vendor_id_t,
 92 pci_product_id_t);
 93
77#define EHCI_MAX_BIOS_WAIT 1000 /* ms */ 94#define EHCI_MAX_BIOS_WAIT 1000 /* ms */
 95#define EHCI_SBx00_WORKAROUND_REG 0x50
 96#define EHCI_SBx00_WORKAROUND_ENABLE __BIT(27)
 97
78 98
79static int 99static int
80ehci_pci_match(struct device *parent, struct cfdata *match, 100ehci_pci_match(struct device *parent, struct cfdata *match,
81 void *aux) 101 void *aux)
82{ 102{
83 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 103 struct pci_attach_args *pa = (struct pci_attach_args *) aux;
84 104
85 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS && 105 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
86 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB && 106 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB &&
87 PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI) 107 PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI)
88 return (1); 108 return (1);
89 109
90 return (0); 110 return (0);
@@ -96,47 +116,63 @@ ehci_pci_attach(struct device *parent, s @@ -96,47 +116,63 @@ ehci_pci_attach(struct device *parent, s
96 struct ehci_pci_softc *sc = device_private(self); 116 struct ehci_pci_softc *sc = device_private(self);
97 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 117 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
98 pci_chipset_tag_t pc = pa->pa_pc; 118 pci_chipset_tag_t pc = pa->pa_pc;
99 pcitag_t tag = pa->pa_tag; 119 pcitag_t tag = pa->pa_tag;
100 char const *intrstr; 120 char const *intrstr;
101 pci_intr_handle_t ih; 121 pci_intr_handle_t ih;
102 pcireg_t csr; 122 pcireg_t csr;
103 const char *vendor; 123 const char *vendor;
104 const char *devname = device_xname(self); 124 const char *devname = device_xname(self);
105 char devinfo[256]; 125 char devinfo[256];
106 usbd_status r; 126 usbd_status r;
107 int ncomp; 127 int ncomp;
108 struct usb_pci *up; 128 struct usb_pci *up;
 129 int quirk;
109 130
110 sc->sc.sc_dev = self; 131 sc->sc.sc_dev = self;
111 sc->sc.sc_bus.hci_private = sc; 132 sc->sc.sc_bus.hci_private = sc;
112 133
113 aprint_naive(": USB controller\n"); 134 aprint_naive(": USB controller\n");
114 135
115 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 136 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
116 aprint_normal(": %s (rev. 0x%02x)\n", devinfo, 137 aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
117 PCI_REVISION(pa->pa_class)); 138 PCI_REVISION(pa->pa_class));
118 139
 140 /* Check for quirks */
 141 quirk = ehci_pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id),
 142 PCI_PRODUCT(pa->pa_id));
 143
119 /* Map I/O registers */ 144 /* Map I/O registers */
120 if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0, 145 if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
121 &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) { 146 &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) {
122 aprint_error("%s: can't map memory space\n", devname); 147 aprint_error("%s: can't map memory space\n", devname);
123 return; 148 return;
124 } 149 }
125 150
126 sc->sc_pc = pc; 151 sc->sc_pc = pc;
127 sc->sc_tag = tag; 152 sc->sc_tag = tag;
128 sc->sc.sc_bus.dmatag = pa->pa_dmat; 153 sc->sc.sc_bus.dmatag = pa->pa_dmat;
129 154
 155 /* Handle quirks */
 156 switch (quirk) {
 157 case EHCI_PCI_QUIRK_AMD_SB600:
 158 ehci_apply_amd_quirks(sc);
 159 break;
 160 case EHCI_PCI_QUIRK_AMD_SB700:
 161 if (pci_find_device(NULL, ehci_sb700_match))
 162 ehci_apply_amd_quirks(sc);
 163 break;
 164 }
 165
130 /* Enable the device. */ 166 /* Enable the device. */
131 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 167 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
132 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 168 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
133 csr | PCI_COMMAND_MASTER_ENABLE); 169 csr | PCI_COMMAND_MASTER_ENABLE);
134 170
135 /* Disable interrupts, so we don't get any spurious ones. */ 171 /* Disable interrupts, so we don't get any spurious ones. */
136 sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); 172 sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
137 DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs)); 173 DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs));
138 EOWRITE2(&sc->sc, EHCI_USBINTR, 0); 174 EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
139 175
140 /* Map and establish the interrupt. */ 176 /* Map and establish the interrupt. */
141 if (pci_intr_map(pa, &ih)) { 177 if (pci_intr_map(pa, &ih)) {
142 aprint_error("%s: couldn't map interrupt\n", devname); 178 aprint_error("%s: couldn't map interrupt\n", devname);
@@ -371,13 +407,57 @@ ehci_pci_suspend(device_t dv PMF_FN_ARGS @@ -371,13 +407,57 @@ ehci_pci_suspend(device_t dv PMF_FN_ARGS
371 ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); 407 ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag);
372 408
373 return true; 409 return true;
374} 410}
375 411
376static bool 412static bool
377ehci_pci_resume(device_t dv PMF_FN_ARGS) 413ehci_pci_resume(device_t dv PMF_FN_ARGS)
378{ 414{
379 struct ehci_pci_softc *sc = device_private(dv); 415 struct ehci_pci_softc *sc = device_private(dv);
380 416
381 ehci_get_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); 417 ehci_get_ownership(&sc->sc, sc->sc_pc, sc->sc_tag);
382 return ehci_resume(dv PMF_FN_CALL); 418 return ehci_resume(dv PMF_FN_CALL);
383} 419}
 420
 421static int
 422ehci_sb700_match(struct pci_attach_args *pa)
 423{
 424 if (!(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI &&
 425 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_SMB))
 426 return 0;
 427
 428 switch (PCI_REVISION(pa->pa_class)) {
 429 case 0x3a:
 430 case 0x3b:
 431 return 1;
 432 }
 433
 434 return 0;
 435}
 436
 437static int
 438ehci_apply_amd_quirks(struct ehci_pci_softc *sc)
 439{
 440 pcireg_t value;
 441
 442 aprint_normal_dev(sc->sc.sc_dev,
 443 "applying AMD SB600/SB700 USB freeze workaround\n");
 444 value = pci_conf_read(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG);
 445 pci_conf_write(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG,
 446 value | EHCI_SBx00_WORKAROUND_ENABLE);
 447
 448 return 0;
 449}
 450
 451enum ehci_pci_quirk_flags
 452ehci_pci_lookup_quirkdata(pci_vendor_id_t vendor, pci_product_id_t product)
 453{
 454 int i;
 455
 456 for (i = 0; i < __arraycount(ehci_pci_quirks); i++) {
 457 if (vendor == ehci_pci_quirks[i].vendor &&
 458 product == ehci_pci_quirks[i].product)
 459 return ehci_pci_quirks[i].quirks;
 460 }
 461 return 0;
 462}
 463