So later could reuse them to do usb handoff much early for x86. will make arch early code get MMIO BAR and do remapping itself. -v2: still keep pci_device *pdev as parameter according to BenH. -v3: expose three functions that take *base instead of including .c file. Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> --- drivers/usb/host/pci-quirks.c | 195 ++++++++++++++++++++++++------------------ drivers/usb/host/pci-quirks.h | 6 + 2 files changed, 120 insertions(+), 81 deletions(-) Index: linux-2.6/drivers/usb/host/pci-quirks.c =================================================================== --- linux-2.6.orig/drivers/usb/host/pci-quirks.c +++ linux-2.6/drivers/usb/host/pci-quirks.c @@ -17,6 +17,19 @@ #include "pci-quirks.h" #include "xhci-ext-caps.h" +static void default_usb_handoff_udelay(unsigned long usecs) +{ + udelay(usecs); +} + +static void __devinit default_usb_handoff_msleep(unsigned long msecs) +{ + msleep(msecs); +} + +void (*usb_handoff_udelay)(unsigned long) = default_usb_handoff_udelay; +void (*usb_handoff_msleep)(unsigned long) __devinitdata = + default_usb_handoff_msleep; #define UHCI_USBLEGSUP 0xc0 /* legacy support */ #define UHCI_USBCMD 0 /* command register */ @@ -71,7 +84,7 @@ void uhci_reset_hc(struct pci_dev *pdev, */ outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); mb(); - udelay(5); + (*usb_handoff_udelay)(5); if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) dev_warn(&pdev->dev, "HCRESET not completed yet!\n"); @@ -106,78 +119,38 @@ int uhci_check_and_reset_hc(struct pci_d */ pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup); if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { - dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n", - __func__, legsup); + dev_printk(KERN_DEBUG, &pdev->dev, + "legsup = 0x%04x\n", legsup); goto reset_needed; } cmd = inw(base + UHCI_USBCMD); if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) || !(cmd & UHCI_USBCMD_EGSM)) { - dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n", - __func__, cmd); + dev_printk(KERN_DEBUG, &pdev->dev, "cmd = 0x%04x\n", cmd); goto reset_needed; } intr = inw(base + UHCI_USBINTR); if (intr & (~UHCI_USBINTR_RESUME)) { - dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n", - __func__, intr); + dev_printk(KERN_DEBUG, &pdev->dev, "intr = 0x%04x\n", intr); goto reset_needed; } return 0; reset_needed: - dev_dbg(&pdev->dev, "Performing full reset\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "Performing full reset\n"); + uhci_reset_hc(pdev, base); + return 1; } EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); -static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) -{ - u16 cmd; - return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); -} - -#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) -#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) - -static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) -{ - unsigned long base = 0; - int i; - - if (!pio_enabled(pdev)) - return; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) - if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { - base = pci_resource_start(pdev, i); - break; - } - - if (base) - uhci_check_and_reset_hc(pdev, base); -} - -static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx) +void __devinit __usb_handoff_ohci(struct pci_dev *pdev, void __iomem *base) { - return pci_resource_start(pdev, idx) && mmio_enabled(pdev); -} - -static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) -{ - void __iomem *base; u32 control; - if (!mmio_resource_enabled(pdev, 0)) - return; - - base = pci_ioremap_bar(pdev, 0); - if (base == NULL) - return; - control = readl(base + OHCI_CONTROL); /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ @@ -193,7 +166,7 @@ static void __devinit quirk_usb_handoff_ while (wait_time > 0 && readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { wait_time -= 10; - msleep(10); + (*usb_handoff_msleep)(10); } if (wait_time <= 0) dev_warn(&pdev->dev, "OHCI: BIOS handoff failed" @@ -210,26 +183,17 @@ static void __devinit quirk_usb_handoff_ */ writel(~(u32)0, base + OHCI_INTRDISABLE); writel(~(u32)0, base + OHCI_INTRSTATUS); - - iounmap(base); } -static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) +void __devinit __usb_handoff_ehci(struct pci_dev *pdev, void __iomem *base) { int wait_time, delta; - void __iomem *base, *op_reg_base; + void *op_reg_base; u32 hcc_params, val; u8 offset, cap_length; int count = 256/4; int tried_handoff = 0; - if (!mmio_resource_enabled(pdev, 0)) - return; - - base = pci_ioremap_bar(pdev, 0); - if (base == NULL) - return; - cap_length = readb(base); op_reg_base = base + cap_length; @@ -247,7 +211,8 @@ static void __devinit quirk_usb_disable_ switch (cap & 0xff) { case 1: /* BIOS/SMM/... handoff support */ if ((cap & EHCI_USBLEGSUP_BIOS)) { - dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n"); + dev_printk(KERN_DEBUG, &pdev->dev, + "EHCI: BIOS handoff\n"); #if 0 /* aleksey_gorelov@xxxxxxxxxxx reports that some systems need SMI forced on, @@ -279,7 +244,7 @@ static void __devinit quirk_usb_disable_ msec = 1000; while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) { tried_handoff = 1; - msleep(10); + (*usb_handoff_msleep)(10); msec -= 10; pci_read_config_dword(pdev, offset, &cap); } @@ -330,18 +295,15 @@ static void __devinit quirk_usb_disable_ delta = 100; do { writel(0x3f, op_reg_base + EHCI_USBSTS); - udelay(delta); + (*usb_handoff_udelay)(delta); wait_time -= delta; val = readl(op_reg_base + EHCI_USBSTS); - if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { + if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) break; - } } while (wait_time > 0); } writel(0, op_reg_base + EHCI_USBINTR); writel(0x3f, op_reg_base + EHCI_USBSTS); - - iounmap(base); } /* @@ -357,7 +319,7 @@ static void __devinit quirk_usb_disable_ * Returns -ETIMEDOUT if this condition is not true after * wait_usec microseconds have passed. */ -static int handshake(void __iomem *ptr, u32 mask, u32 done, +static int __devinit handshake(void __iomem *ptr, u32 mask, u32 done, int wait_usec, int delay_usec) { u32 result; @@ -367,7 +329,7 @@ static int handshake(void __iomem *ptr, result &= mask; if (result == done) return 0; - udelay(delay_usec); + (*usb_handoff_udelay)(delay_usec); wait_usec -= delay_usec; } while (wait_usec > 0); return -ETIMEDOUT; @@ -381,22 +343,13 @@ static int handshake(void __iomem *ptr, * and then waits 5 seconds for the BIOS to hand over control. * If we timeout, assume the BIOS is broken and take control anyway. */ -static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) +void __usb_handoff_xhci(struct pci_dev *pdev, void __iomem *base) { - void __iomem *base; int ext_cap_offset; void __iomem *op_reg_base; u32 val; int timeout; - if (!mmio_resource_enabled(pdev, 0)) - return; - - base = ioremap_nocache(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (base == NULL) - return; - /* * Find the Legacy Support Capability register - * this is optional for xHCI host controllers. @@ -462,6 +415,86 @@ hc_init: "xHCI HW did not halt within %d usec " "status = 0x%x\n", XHCI_MAX_HALT_USEC, val); } +} + +static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) +{ + u16 cmd; + return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); +} + +#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) +#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) + +static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) +{ + unsigned long base = 0; + int i; + + if (!pio_enabled(pdev)) + return; + + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + base = pci_resource_start(pdev, i); + break; + } + + if (!base) + return; + + uhci_check_and_reset_hc(pdev, base); +} + +static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx) +{ + return pci_resource_start(pdev, idx) && mmio_enabled(pdev); +} + +static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) +{ + void __iomem *base; + + if (!mmio_resource_enabled(pdev, 0)) + return; + + base = pci_ioremap_bar(pdev, 0); + if (base == NULL) + return; + + __usb_handoff_ohci(pdev, base); + + iounmap(base); +} + +static void __devinit quirk_usb_handoff_ehci(struct pci_dev *pdev) +{ + void __iomem *base; + + if (!mmio_resource_enabled(pdev, 0)) + return; + + base = pci_ioremap_bar(pdev, 0); + if (base == NULL) + return; + + __usb_handoff_ehci(pdev, base); + + iounmap(base); +} + +static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) +{ + void __iomem *base; + + if (!mmio_resource_enabled(pdev, 0)) + return; + + base = pci_ioremap_bar(pdev, 0); + if (base == NULL) + return; + + __usb_handoff_xhci(pdev, base); iounmap(base); } @@ -473,7 +506,7 @@ static void __devinit quirk_usb_early_ha else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) quirk_usb_handoff_ohci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI) - quirk_usb_disable_ehci(pdev); + quirk_usb_handoff_ehci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) quirk_usb_handoff_xhci(pdev); } Index: linux-2.6/drivers/usb/host/pci-quirks.h =================================================================== --- linux-2.6.orig/drivers/usb/host/pci-quirks.h +++ linux-2.6/drivers/usb/host/pci-quirks.h @@ -3,5 +3,11 @@ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); +void __usb_handoff_ohci(struct pci_dev *pdev, void __iomem *base); +void __usb_handoff_ehci(struct pci_dev *pdev, void __iomem *base); +void __usb_handoff_xhci(struct pci_dev *pdev, void __iomem *base); + +extern void (*usb_handoff_udelay)(unsigned long); +extern void (*usb_handoff_msleep)(unsigned long); #endif /* __LINUX_USB_PCI_QUIRKS_H */ -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html