aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2006-01-24 10:15:30 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 20:23:35 -0500
commit401feafa621ba98ecaeed5db1a53ab878943c225 (patch)
tree225ffa420c626ca5c4525a96f476706cd95f8933 /drivers
parent3fa97c9db4f6f93f41f7a40d08872dbfd8dc907e (diff)
[PATCH] USB: fix EHCI early handoff issues
This moves the previously widely-used ehci-pci.c BIOS handoff code into the pci-quirks.c file, replacing the less widely used "early handoff" version that seems to cause problems lately. One notable change: the "early handoff" version always enabled an SMI IRQ ... and did so even if the pre-Linux code said it was not using EHCI (and not expecting EHCI SMIs). Looks like a goof in a workaround for some unknown BIOS version. This merged version only forcibly enables those IRQs when pre-Linux code says it's using EHCI. And now it always forces them off "just in case". Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-pci.c63
-rw-r--r--drivers/usb/host/pci-quirks.c106
2 files changed, 71 insertions, 98 deletions
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 08ca0f849dab..286b2f4acdc2 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -24,40 +24,6 @@
24 24
25/*-------------------------------------------------------------------------*/ 25/*-------------------------------------------------------------------------*/
26 26
27/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
28 * off the controller (maybe it can boot from highspeed USB disks).
29 */
30static int bios_handoff(struct ehci_hcd *ehci, int where, u32 cap)
31{
32 struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
33
34 /* always say Linux will own the hardware */
35 pci_write_config_byte(pdev, where + 3, 1);
36
37 /* maybe wait a while for BIOS to respond */
38 if (cap & (1 << 16)) {
39 int msec = 5000;
40
41 do {
42 msleep(10);
43 msec -= 10;
44 pci_read_config_dword(pdev, where, &cap);
45 } while ((cap & (1 << 16)) && msec);
46 if (cap & (1 << 16)) {
47 ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
48 where, cap);
49 // some BIOS versions seem buggy...
50 // return 1;
51 ehci_warn(ehci, "continuing after BIOS bug...\n");
52 /* disable all SMIs, and clear "BIOS owns" flag */
53 pci_write_config_dword(pdev, where + 4, 0);
54 pci_write_config_byte(pdev, where + 2, 0);
55 } else
56 ehci_dbg(ehci, "BIOS handoff succeeded\n");
57 }
58 return 0;
59}
60
61/* called after powerup, by probe or system-pm "wakeup" */ 27/* called after powerup, by probe or system-pm "wakeup" */
62static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) 28static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
63{ 29{
@@ -84,32 +50,9 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
84 } 50 }
85 } 51 }
86 52
87 temp = HCC_EXT_CAPS(readl(&ehci->caps->hcc_params)); 53 /* we expect static quirk code to handle the "extended capabilities"
88 54 * (currently just BIOS handoff) allowed starting with EHCI 0.96
89 /* EHCI 0.96 and later may have "extended capabilities" */ 55 */
90 while (temp && count--) {
91 u32 cap;
92
93 pci_read_config_dword(pdev, temp, &cap);
94 ehci_dbg(ehci, "capability %04x at %02x\n", cap, temp);
95 switch (cap & 0xff) {
96 case 1: /* BIOS/SMM/... handoff */
97 if (bios_handoff(ehci, temp, cap) != 0)
98 return -EOPNOTSUPP;
99 break;
100 case 0: /* illegal reserved capability */
101 ehci_dbg(ehci, "illegal capability!\n");
102 cap = 0;
103 /* FALLTHROUGH */
104 default: /* unknown */
105 break;
106 }
107 temp = (cap >> 8) & 0xff;
108 }
109 if (!count) {
110 ehci_err(ehci, "bogus capabilities ... PCI problems!\n");
111 return -EIO;
112 }
113 56
114 /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */ 57 /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
115 retval = pci_set_mwi(pdev); 58 retval = pci_set_mwi(pdev);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 3ef2c0cdf1db..e9e5bc178cef 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -190,7 +190,7 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
190 msleep(10); 190 msleep(10);
191 } 191 }
192 if (wait_time <= 0) 192 if (wait_time <= 0)
193 printk(KERN_WARNING "%s %s: early BIOS handoff " 193 printk(KERN_WARNING "%s %s: BIOS handoff "
194 "failed (BIOS bug ?)\n", 194 "failed (BIOS bug ?)\n",
195 pdev->dev.bus_id, "OHCI"); 195 pdev->dev.bus_id, "OHCI");
196 196
@@ -212,8 +212,9 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
212{ 212{
213 int wait_time, delta; 213 int wait_time, delta;
214 void __iomem *base, *op_reg_base; 214 void __iomem *base, *op_reg_base;
215 u32 hcc_params, val, temp; 215 u32 hcc_params, val;
216 u8 cap_length; 216 u8 offset, cap_length;
217 int count = 256/4;
217 218
218 if (!mmio_resource_enabled(pdev, 0)) 219 if (!mmio_resource_enabled(pdev, 0))
219 return; 220 return;
@@ -224,51 +225,80 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
224 225
225 cap_length = readb(base); 226 cap_length = readb(base);
226 op_reg_base = base + cap_length; 227 op_reg_base = base + cap_length;
228
229 /* EHCI 0.96 and later may have "extended capabilities"
230 * spec section 5.1 explains the bios handoff, e.g. for
231 * booting from USB disk or using a usb keyboard
232 */
227 hcc_params = readl(base + EHCI_HCC_PARAMS); 233 hcc_params = readl(base + EHCI_HCC_PARAMS);
228 hcc_params = (hcc_params >> 8) & 0xff; 234 offset = (hcc_params >> 8) & 0xff;
229 if (hcc_params) { 235 while (offset && count--) {
230 pci_read_config_dword(pdev, 236 u32 cap;
231 hcc_params + EHCI_USBLEGSUP, 237 int msec;
232 &val); 238
233 if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) { 239 pci_read_config_dword(pdev, offset, &cap);
234 /* 240 switch (cap & 0xff) {
235 * Ok, BIOS is in smm mode, try to hand off... 241 case 1: /* BIOS/SMM/... handoff support */
242 if ((cap & EHCI_USBLEGSUP_BIOS)) {
243 pr_debug("%s %s: BIOS handoff\n",
244 pdev->dev.bus_id, "EHCI");
245
246 /* BIOS workaround (?): be sure the
247 * pre-Linux code receives the SMI
248 */
249 pci_read_config_dword(pdev,
250 offset + EHCI_USBLEGCTLSTS,
251 &val);
252 pci_write_config_dword(pdev,
253 offset + EHCI_USBLEGCTLSTS,
254 val | EHCI_USBLEGCTLSTS_SOOE);
255 }
256
257 /* always say Linux will own the hardware
258 * by setting EHCI_USBLEGSUP_OS.
236 */ 259 */
237 pci_read_config_dword(pdev, 260 pci_write_config_byte(pdev, offset + 3, 1);
238 hcc_params + EHCI_USBLEGCTLSTS,
239 &temp);
240 pci_write_config_dword(pdev,
241 hcc_params + EHCI_USBLEGCTLSTS,
242 temp | EHCI_USBLEGCTLSTS_SOOE);
243 val |= EHCI_USBLEGSUP_OS;
244 pci_write_config_dword(pdev,
245 hcc_params + EHCI_USBLEGSUP,
246 val);
247 261
248 wait_time = 500; 262 /* if boot firmware now owns EHCI, spin till
249 do { 263 * it hands it over.
264 */
265 msec = 5000;
266 while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
250 msleep(10); 267 msleep(10);
251 wait_time -= 10; 268 msec -= 10;
252 pci_read_config_dword(pdev, 269 pci_read_config_dword(pdev, offset, &cap);
253 hcc_params + EHCI_USBLEGSUP, 270 }
254 &val); 271
255 } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); 272 if (cap & EHCI_USBLEGSUP_BIOS) {
256 if (!wait_time) { 273 /* well, possibly buggy BIOS... try to shut
257 /* 274 * it down, and hope nothing goes too wrong
258 * well, possibly buggy BIOS...
259 */ 275 */
260 printk(KERN_WARNING "%s %s: early BIOS handoff " 276 printk(KERN_WARNING "%s %s: BIOS handoff "
261 "failed (BIOS bug ?)\n", 277 "failed (BIOS bug ?)\n",
262 pdev->dev.bus_id, "EHCI"); 278 pdev->dev.bus_id, "EHCI");
263 pci_write_config_dword(pdev, 279 pci_write_config_byte(pdev, offset + 2, 0);
264 hcc_params + EHCI_USBLEGSUP,
265 EHCI_USBLEGSUP_OS);
266 pci_write_config_dword(pdev,
267 hcc_params + EHCI_USBLEGCTLSTS,
268 0);
269 } 280 }
281
282 /* just in case, always disable EHCI SMIs */
283 pci_write_config_dword(pdev,
284 offset + EHCI_USBLEGCTLSTS,
285 0);
286 break;
287 case 0: /* illegal reserved capability */
288 cap = 0;
289 /* FALLTHROUGH */
290 default:
291 printk(KERN_WARNING "%s %s: unrecognized "
292 "capability %02x\n",
293 pdev->dev.bus_id, "EHCI",
294 cap & 0xff);
295 break;
270 } 296 }
297 offset = (cap >> 8) & 0xff;
271 } 298 }
299 if (!count)
300 printk(KERN_DEBUG "%s %s: capability loop?\n",
301 pdev->dev.bus_id, "EHCI");
272 302
273 /* 303 /*
274 * halt EHCI & disable its interrupts in any case 304 * halt EHCI & disable its interrupts in any case