aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/pci-quirks.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-04-27 22:52:28 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:48 -0400
commit66d4eadd8d067269ea8fead1a50fe87c2979a80d (patch)
treeb0324868818058161e528bd194f6888456924fd4 /drivers/usb/host/pci-quirks.c
parent74c6874199af98e602bb7c5fb1beb9cffda98729 (diff)
USB: xhci: BIOS handoff and HW initialization.
Add PCI initialization code to take control of the xHCI host controller away from the BIOS, halt, and reset the host controller. The xHCI spec says that BIOSes must give up the host controller within 5 seconds. Add some host controller glue functions to handle hardware initialization and memory allocation for the host controller. The current xHCI prototypes use PCI interrupts, but the xHCI spec requires MSI-X interrupts. Add code to support MSI-X interrupts, but use the PCI interrupts for now. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> 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.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 033c2846ce59..83b5f9cea85a 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -15,6 +15,7 @@
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <linux/acpi.h> 16#include <linux/acpi.h>
17#include "pci-quirks.h" 17#include "pci-quirks.h"
18#include "xhci-ext-caps.h"
18 19
19 20
20#define UHCI_USBLEGSUP 0xc0 /* legacy support */ 21#define UHCI_USBLEGSUP 0xc0 /* legacy support */
@@ -341,7 +342,127 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
341 return; 342 return;
342} 343}
343 344
345/*
346 * handshake - spin reading a register until handshake completes
347 * @ptr: address of hc register to be read
348 * @mask: bits to look at in result of read
349 * @done: value of those bits when handshake succeeds
350 * @wait_usec: timeout in microseconds
351 * @delay_usec: delay in microseconds to wait between polling
352 *
353 * Polls a register every delay_usec microseconds.
354 * Returns 0 when the mask bits have the value done.
355 * Returns -ETIMEDOUT if this condition is not true after
356 * wait_usec microseconds have passed.
357 */
358static int handshake(void __iomem *ptr, u32 mask, u32 done,
359 int wait_usec, int delay_usec)
360{
361 u32 result;
362
363 do {
364 result = readl(ptr);
365 result &= mask;
366 if (result == done)
367 return 0;
368 udelay(delay_usec);
369 wait_usec -= delay_usec;
370 } while (wait_usec > 0);
371 return -ETIMEDOUT;
372}
373
374/**
375 * PCI Quirks for xHCI.
376 *
377 * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
378 * It signals to the BIOS that the OS wants control of the host controller,
379 * and then waits 5 seconds for the BIOS to hand over control.
380 * If we timeout, assume the BIOS is broken and take control anyway.
381 */
382static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
383{
384 void __iomem *base;
385 int ext_cap_offset;
386 void __iomem *op_reg_base;
387 u32 val;
388 int timeout;
389
390 if (!mmio_resource_enabled(pdev, 0))
391 return;
392
393 base = ioremap_nocache(pci_resource_start(pdev, 0),
394 pci_resource_len(pdev, 0));
395 if (base == NULL)
396 return;
344 397
398 /*
399 * Find the Legacy Support Capability register -
400 * this is optional for xHCI host controllers.
401 */
402 ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
403 do {
404 if (!ext_cap_offset)
405 /* We've reached the end of the extended capabilities */
406 goto hc_init;
407 val = readl(base + ext_cap_offset);
408 if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
409 break;
410 ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset);
411 } while (1);
412
413 /* If the BIOS owns the HC, signal that the OS wants it, and wait */
414 if (val & XHCI_HC_BIOS_OWNED) {
415 writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
416
417 /* Wait for 5 seconds with 10 microsecond polling interval */
418 timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
419 0, 5000, 10);
420
421 /* Assume a buggy BIOS and take HC ownership anyway */
422 if (timeout) {
423 dev_warn(&pdev->dev, "xHCI BIOS handoff failed"
424 " (BIOS bug ?) %08x\n", val);
425 writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
426 }
427 }
428
429 /* Disable any BIOS SMIs */
430 writel(XHCI_LEGACY_DISABLE_SMI,
431 base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
432
433hc_init:
434 op_reg_base = base + XHCI_HC_LENGTH(readl(base));
435
436 /* Wait for the host controller to be ready before writing any
437 * operational or runtime registers. Wait 5 seconds and no more.
438 */
439 timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
440 5000, 10);
441 /* Assume a buggy HC and start HC initialization anyway */
442 if (timeout) {
443 val = readl(op_reg_base + XHCI_STS_OFFSET);
444 dev_warn(&pdev->dev,
445 "xHCI HW not ready after 5 sec (HC bug?) "
446 "status = 0x%x\n", val);
447 }
448
449 /* Send the halt and disable interrupts command */
450 val = readl(op_reg_base + XHCI_CMD_OFFSET);
451 val &= ~(XHCI_CMD_RUN | XHCI_IRQS);
452 writel(val, op_reg_base + XHCI_CMD_OFFSET);
453
454 /* Wait for the HC to halt - poll every 125 usec (one microframe). */
455 timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1,
456 XHCI_MAX_HALT_USEC, 125);
457 if (timeout) {
458 val = readl(op_reg_base + XHCI_STS_OFFSET);
459 dev_warn(&pdev->dev,
460 "xHCI HW did not halt within %d usec "
461 "status = 0x%x\n", XHCI_MAX_HALT_USEC, val);
462 }
463
464 iounmap(base);
465}
345 466
346static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) 467static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
347{ 468{
@@ -351,5 +472,7 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
351 quirk_usb_handoff_ohci(pdev); 472 quirk_usb_handoff_ohci(pdev);
352 else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI) 473 else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI)
353 quirk_usb_disable_ehci(pdev); 474 quirk_usb_disable_ehci(pdev);
475 else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
476 quirk_usb_handoff_xhci(pdev);
354} 477}
355DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); 478DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);