aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/pci-quirks.c
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/usb/host/pci-quirks.c
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/usb/host/pci-quirks.c')
-rw-r--r--drivers/usb/host/pci-quirks.c106
1 files changed, 68 insertions, 38 deletions
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