diff options
author | Jason Wessel <jason.wessel@windriver.com> | 2009-08-20 16:39:50 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:38 -0400 |
commit | 093344e1362cbf9525a5da09a565f357d8102f3b (patch) | |
tree | b5e7fe63e9a69799c73e25a37e58d69be331463c /drivers/usb | |
parent | 87a5d15154ae2389251e6ad99216a846b905375c (diff) |
USB: ehci-dbgp: Execute early BIOS hand off
The PCI quirk code executes a BIOS hand off to obtain full control of
the EHCI host controller, the self contained ehci-dbgp driver must do
the same thing using the early PCI API, else the BIOS can cause a
fatal fault.
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: dbrownell@users.sourceforge.net
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/early/ehci-dbgp.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 8de709ac0f55..7deae97fe50f 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c | |||
@@ -435,6 +435,53 @@ static void __init detect_set_debug_port(void) | |||
435 | } | 435 | } |
436 | } | 436 | } |
437 | 437 | ||
438 | /* The code in early_ehci_bios_handoff() is derived from the usb pci | ||
439 | * quirk initialization, but altered so as to use the early PCI | ||
440 | * routines. */ | ||
441 | #define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ | ||
442 | #define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ | ||
443 | static void __init early_ehci_bios_handoff(void) | ||
444 | { | ||
445 | u32 hcc_params = readl(&ehci_caps->hcc_params); | ||
446 | int offset = (hcc_params >> 8) & 0xff; | ||
447 | u32 cap; | ||
448 | int msec; | ||
449 | |||
450 | if (!offset) | ||
451 | return; | ||
452 | |||
453 | cap = read_pci_config(ehci_dev.bus, ehci_dev.slot, | ||
454 | ehci_dev.func, offset); | ||
455 | dbgp_printk("dbgp: ehci BIOS state %08x\n", cap); | ||
456 | |||
457 | if ((cap & 0xff) == 1 && (cap & EHCI_USBLEGSUP_BIOS)) { | ||
458 | dbgp_printk("dbgp: BIOS handoff\n"); | ||
459 | write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, | ||
460 | ehci_dev.func, offset + 3, 1); | ||
461 | } | ||
462 | |||
463 | /* if boot firmware now owns EHCI, spin till it hands it over. */ | ||
464 | msec = 1000; | ||
465 | while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) { | ||
466 | mdelay(10); | ||
467 | msec -= 10; | ||
468 | cap = read_pci_config(ehci_dev.bus, ehci_dev.slot, | ||
469 | ehci_dev.func, offset); | ||
470 | } | ||
471 | |||
472 | if (cap & EHCI_USBLEGSUP_BIOS) { | ||
473 | /* well, possibly buggy BIOS... try to shut it down, | ||
474 | * and hope nothing goes too wrong */ | ||
475 | dbgp_printk("dbgp: BIOS handoff failed: %08x\n", cap); | ||
476 | write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, | ||
477 | ehci_dev.func, offset + 2, 0); | ||
478 | } | ||
479 | |||
480 | /* just in case, always disable EHCI SMIs */ | ||
481 | write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | ||
482 | offset + EHCI_USBLEGCTLSTS, 0); | ||
483 | } | ||
484 | |||
438 | static int __init ehci_setup(void) | 485 | static int __init ehci_setup(void) |
439 | { | 486 | { |
440 | struct usb_debug_descriptor dbgp_desc; | 487 | struct usb_debug_descriptor dbgp_desc; |
@@ -446,6 +493,8 @@ static int __init ehci_setup(void) | |||
446 | int port_map_tried; | 493 | int port_map_tried; |
447 | int playtimes = 3; | 494 | int playtimes = 3; |
448 | 495 | ||
496 | early_ehci_bios_handoff(); | ||
497 | |||
449 | try_next_time: | 498 | try_next_time: |
450 | port_map_tried = 0; | 499 | port_map_tried = 0; |
451 | 500 | ||