diff options
Diffstat (limited to 'drivers/usb/host')
60 files changed, 599 insertions, 3440 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3f1431d..d6bb128 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -95,6 +95,11 @@ config USB_EHCI_TT_NEWSCHED If unsure, say Y. +config USB_EHCI_PCI + tristate + depends on USB_EHCI_HCD && PCI + default y + config USB_EHCI_HCD_PMC_MSP tristate "EHCI support for on-chip PMC MSP71xx USB controller" depends on USB_EHCI_HCD && MSP_HAS_USB @@ -215,9 +220,13 @@ config USB_W90X900_EHCI Enables support for the W90X900 USB controller config USB_CNS3XXX_EHCI - bool "Cavium CNS3XXX EHCI Module" + bool "Cavium CNS3XXX EHCI Module (DEPRECATED)" depends on USB_EHCI_HCD && ARCH_CNS3XXX + select USB_EHCI_HCD_PLATFORM ---help--- + This option is deprecated now and the driver was removed, use + USB_EHCI_HCD_PLATFORM instead. + Enable support for the CNS3XXX SOC's on-chip EHCI controller. It is needed for high-speed (480Mbit/sec) USB 2.0 device support. @@ -333,16 +342,6 @@ config USB_OHCI_ATH79 Enables support for the built-in OHCI controller present on the Atheros AR71XX/AR7240 SoCs. -config USB_OHCI_HCD_PPC_SOC - bool "OHCI support for on-chip PPC USB controller" - depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) - default y - select USB_OHCI_BIG_ENDIAN_DESC - select USB_OHCI_BIG_ENDIAN_MMIO - ---help--- - Enables support for the USB controller on the MPC52xx or - STB03xxx processor chip. If unsure, say Y. - config USB_OHCI_HCD_PPC_OF_BE bool "OHCI support for OF platform bus (big endian)" depends on USB_OHCI_HCD && PPC_OF @@ -393,9 +392,13 @@ config USB_OHCI_HCD_SSB If unsure, say N. config USB_OHCI_SH - bool "OHCI support for SuperH USB controller" + bool "OHCI support for SuperH USB controller (DEPRECATED)" depends on USB_OHCI_HCD && SUPERH + select USB_OHCI_HCD_PLATFORM ---help--- + This option is deprecated now and the driver was removed, use + USB_OHCI_HCD_PLATFORM instead. + Enables support for the on-chip OHCI controller on the SuperH. If you use the PCI OHCI controller, this option is not necessary. @@ -406,9 +409,13 @@ config USB_OHCI_EXYNOS Enable support for the Samsung Exynos SOC's on-chip OHCI controller. config USB_CNS3XXX_OHCI - bool "Cavium CNS3XXX OHCI Module" + bool "Cavium CNS3XXX OHCI Module (DEPRECATED)" depends on USB_OHCI_HCD && ARCH_CNS3XXX + select USB_OHCI_HCD_PLATFORM ---help--- + This option is deprecated now and the driver was removed, use + USB_OHCI_HCD_PLATFORM instead. + Enable support for the CNS3XXX SOC's on-chip OHCI controller. It is needed for low-speed USB 1.0 device support. @@ -423,7 +430,7 @@ config USB_OHCI_HCD_PLATFORM If unsure, say N. config USB_EHCI_HCD_PLATFORM - bool "Generic EHCI driver for a platform device" + tristate "Generic EHCI driver for a platform device" depends on USB_EHCI_HCD default n ---help--- diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 9e0a89c..1eb4c30 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -24,6 +24,9 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci/ obj-$(CONFIG_PCI) += pci-quirks.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o +obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o +obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o + obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-hcd.o @@ -40,6 +43,5 @@ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o -obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o diff --git a/drivers/usb/host/alchemy-common.c b/drivers/usb/host/alchemy-common.c deleted file mode 100644 index 936af83..0000000 --- a/drivers/usb/host/alchemy-common.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * USB block power/access management abstraction. - * - * Au1000+: The OHCI block control register is at the far end of the OHCI memory - * area. Au1550 has OHCI on different base address. No need to handle - * UDC here. - * Au1200: one register to control access and clocks to O/EHCI, UDC and OTG - * as well as the PHY for EHCI and UDC. - * - */ - -#include <linux/init.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/syscore_ops.h> -#include <asm/mach-au1x00/au1000.h> - -/* control register offsets */ -#define AU1000_OHCICFG 0x7fffc -#define AU1550_OHCICFG 0x07ffc -#define AU1200_USBCFG 0x04 - -/* Au1000 USB block config bits */ -#define USBHEN_RD (1 << 4) /* OHCI reset-done indicator */ -#define USBHEN_CE (1 << 3) /* OHCI block clock enable */ -#define USBHEN_E (1 << 2) /* OHCI block enable */ -#define USBHEN_C (1 << 1) /* OHCI block coherency bit */ -#define USBHEN_BE (1 << 0) /* OHCI Big-Endian */ - -/* Au1200 USB config bits */ -#define USBCFG_PFEN (1 << 31) /* prefetch enable (undoc) */ -#define USBCFG_RDCOMB (1 << 30) /* read combining (undoc) */ -#define USBCFG_UNKNOWN (5 << 20) /* unknown, leave this way */ -#define USBCFG_SSD (1 << 23) /* serial short detect en */ -#define USBCFG_PPE (1 << 19) /* HS PHY PLL */ -#define USBCFG_UCE (1 << 18) /* UDC clock enable */ -#define USBCFG_ECE (1 << 17) /* EHCI clock enable */ -#define USBCFG_OCE (1 << 16) /* OHCI clock enable */ -#define USBCFG_FLA(x) (((x) & 0x3f) << 8) -#define USBCFG_UCAM (1 << 7) /* coherent access (undoc) */ -#define USBCFG_GME (1 << 6) /* OTG mem access */ -#define USBCFG_DBE (1 << 5) /* UDC busmaster enable */ -#define USBCFG_DME (1 << 4) /* UDC mem enable */ -#define USBCFG_EBE (1 << 3) /* EHCI busmaster enable */ -#define USBCFG_EME (1 << 2) /* EHCI mem enable */ -#define USBCFG_OBE (1 << 1) /* OHCI busmaster enable */ -#define USBCFG_OME (1 << 0) /* OHCI mem enable */ -#define USBCFG_INIT_AU1200 (USBCFG_PFEN | USBCFG_RDCOMB | USBCFG_UNKNOWN |\ - USBCFG_SSD | USBCFG_FLA(0x20) | USBCFG_UCAM | \ - USBCFG_GME | USBCFG_DBE | USBCFG_DME | \ - USBCFG_EBE | USBCFG_EME | USBCFG_OBE | \ - USBCFG_OME) - -/* Au1300 USB config registers */ -#define USB_DWC_CTRL1 0x00 -#define USB_DWC_CTRL2 0x04 -#define USB_VBUS_TIMER 0x10 -#define USB_SBUS_CTRL 0x14 -#define USB_MSR_ERR 0x18 -#define USB_DWC_CTRL3 0x1C -#define USB_DWC_CTRL4 0x20 -#define USB_OTG_STATUS 0x28 -#define USB_DWC_CTRL5 0x2C -#define USB_DWC_CTRL6 0x30 -#define USB_DWC_CTRL7 0x34 -#define USB_PHY_STATUS 0xC0 -#define USB_INT_STATUS 0xC4 -#define USB_INT_ENABLE 0xC8 - -#define USB_DWC_CTRL1_OTGD 0x04 /* set to DISable OTG */ -#define USB_DWC_CTRL1_HSTRS 0x02 /* set to ENable EHCI */ -#define USB_DWC_CTRL1_DCRS 0x01 /* set to ENable UDC */ - -#define USB_DWC_CTRL2_PHY1RS 0x04 /* set to enable PHY1 */ -#define USB_DWC_CTRL2_PHY0RS 0x02 /* set to enable PHY0 */ -#define USB_DWC_CTRL2_PHYRS 0x01 /* set to enable PHY */ - -#define USB_DWC_CTRL3_OHCI1_CKEN (1 << 19) -#define USB_DWC_CTRL3_OHCI0_CKEN (1 << 18) -#define USB_DWC_CTRL3_EHCI0_CKEN (1 << 17) -#define USB_DWC_CTRL3_OTG0_CKEN (1 << 16) - -#define USB_SBUS_CTRL_SBCA 0x04 /* coherent access */ - -#define USB_INTEN_FORCE 0x20 -#define USB_INTEN_PHY 0x10 -#define USB_INTEN_UDC 0x08 -#define USB_INTEN_EHCI 0x04 -#define USB_INTEN_OHCI1 0x02 -#define USB_INTEN_OHCI0 0x01 - -static DEFINE_SPINLOCK(alchemy_usb_lock); - -static inline void __au1300_usb_phyctl(void __iomem *base, int enable) -{ - unsigned long r, s; - - r = __raw_readl(base + USB_DWC_CTRL2); - s = __raw_readl(base + USB_DWC_CTRL3); - - s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN | - USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN; - - if (enable) { - /* simply enable all PHYs */ - r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | - USB_DWC_CTRL2_PHYRS; - __raw_writel(r, base + USB_DWC_CTRL2); - wmb(); - } else if (!s) { - /* no USB block active, do disable all PHYs */ - r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | - USB_DWC_CTRL2_PHYRS); - __raw_writel(r, base + USB_DWC_CTRL2); - wmb(); - } -} - -static inline void __au1300_ohci_control(void __iomem *base, int enable, int id) -{ - unsigned long r; - - if (enable) { - __raw_writel(1, base + USB_DWC_CTRL7); /* start OHCI clock */ - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); /* enable OHCI block */ - r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN - : USB_DWC_CTRL3_OHCI1_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); /* power up the PHYs */ - - r = __raw_readl(base + USB_INT_ENABLE); - r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - /* reset the OHCI start clock bit */ - __raw_writel(0, base + USB_DWC_CTRL7); - wmb(); - } else { - r = __raw_readl(base + USB_INT_ENABLE); - r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1); - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); - r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN - : USB_DWC_CTRL3_OHCI1_CKEN); - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline void __au1300_ehci_control(void __iomem *base, int enable) -{ - unsigned long r; - - if (enable) { - r = __raw_readl(base + USB_DWC_CTRL3); - r |= USB_DWC_CTRL3_EHCI0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r |= USB_DWC_CTRL1_HSTRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - - r = __raw_readl(base + USB_INT_ENABLE); - r |= USB_INTEN_EHCI; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - } else { - r = __raw_readl(base + USB_INT_ENABLE); - r &= ~USB_INTEN_EHCI; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r &= ~USB_DWC_CTRL1_HSTRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); - r &= ~USB_DWC_CTRL3_EHCI0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline void __au1300_udc_control(void __iomem *base, int enable) -{ - unsigned long r; - - if (enable) { - r = __raw_readl(base + USB_DWC_CTRL1); - r |= USB_DWC_CTRL1_DCRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - - r = __raw_readl(base + USB_INT_ENABLE); - r |= USB_INTEN_UDC; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - } else { - r = __raw_readl(base + USB_INT_ENABLE); - r &= ~USB_INTEN_UDC; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r &= ~USB_DWC_CTRL1_DCRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline void __au1300_otg_control(void __iomem *base, int enable) -{ - unsigned long r; - if (enable) { - r = __raw_readl(base + USB_DWC_CTRL3); - r |= USB_DWC_CTRL3_OTG0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r &= ~USB_DWC_CTRL1_OTGD; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - } else { - r = __raw_readl(base + USB_DWC_CTRL1); - r |= USB_DWC_CTRL1_OTGD; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); - r &= ~USB_DWC_CTRL3_OTG0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline int au1300_usb_control(int block, int enable) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); - int ret = 0; - - switch (block) { - case ALCHEMY_USB_OHCI0: - __au1300_ohci_control(base, enable, 0); - break; - case ALCHEMY_USB_OHCI1: - __au1300_ohci_control(base, enable, 1); - break; - case ALCHEMY_USB_EHCI0: - __au1300_ehci_control(base, enable); - break; - case ALCHEMY_USB_UDC0: - __au1300_udc_control(base, enable); - break; - case ALCHEMY_USB_OTG0: - __au1300_otg_control(base, enable); - break; - default: - ret = -ENODEV; - } - return ret; -} - -static inline void au1300_usb_init(void) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); - - /* set some sane defaults. Note: we don't fiddle with DWC_CTRL4 - * here at all: Port 2 routing (EHCI or UDC) must be set either - * by boot firmware or platform init code; I can't autodetect - * a sane setting. - */ - __raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */ - wmb(); - __raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */ - wmb(); - __raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */ - wmb(); - __raw_writel(~0, base + USB_INT_STATUS); /* clear int status */ - wmb(); - /* set coherent access bit */ - __raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL); - wmb(); -} - -static inline void __au1200_ohci_control(void __iomem *base, int enable) -{ - unsigned long r = __raw_readl(base + AU1200_USBCFG); - if (enable) { - __raw_writel(r | USBCFG_OCE, base + AU1200_USBCFG); - wmb(); - udelay(2000); - } else { - __raw_writel(r & ~USBCFG_OCE, base + AU1200_USBCFG); - wmb(); - udelay(1000); - } -} - -static inline void __au1200_ehci_control(void __iomem *base, int enable) -{ - unsigned long r = __raw_readl(base + AU1200_USBCFG); - if (enable) { - __raw_writel(r | USBCFG_ECE | USBCFG_PPE, base + AU1200_USBCFG); - wmb(); - udelay(1000); - } else { - if (!(r & USBCFG_UCE)) /* UDC also off? */ - r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ - __raw_writel(r & ~USBCFG_ECE, base + AU1200_USBCFG); - wmb(); - udelay(1000); - } -} - -static inline void __au1200_udc_control(void __iomem *base, int enable) -{ - unsigned long r = __raw_readl(base + AU1200_USBCFG); - if (enable) { - __raw_writel(r | USBCFG_UCE | USBCFG_PPE, base + AU1200_USBCFG); - wmb(); - } else { - if (!(r & USBCFG_ECE)) /* EHCI also off? */ - r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ - __raw_writel(r & ~USBCFG_UCE, base + AU1200_USBCFG); - wmb(); - } -} - -static inline int au1200_coherency_bug(void) -{ -#if defined(CONFIG_DMA_COHERENT) - /* Au1200 AB USB does not support coherent memory */ - if (!(read_c0_prid() & 0xff)) { - printk(KERN_INFO "Au1200 USB: this is chip revision AB !!\n"); - printk(KERN_INFO "Au1200 USB: update your board or re-configure" - " the kernel\n"); - return -ENODEV; - } -#endif - return 0; -} - -static inline int au1200_usb_control(int block, int enable) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); - int ret = 0; - - switch (block) { - case ALCHEMY_USB_OHCI0: - ret = au1200_coherency_bug(); - if (ret && enable) - goto out; - __au1200_ohci_control(base, enable); - break; - case ALCHEMY_USB_UDC0: - __au1200_udc_control(base, enable); - break; - case ALCHEMY_USB_EHCI0: - ret = au1200_coherency_bug(); - if (ret && enable) - goto out; - __au1200_ehci_control(base, enable); - break; - default: - ret = -ENODEV; - } -out: - return ret; -} - - -/* initialize USB block(s) to a known working state */ -static inline void au1200_usb_init(void) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); - __raw_writel(USBCFG_INIT_AU1200, base + AU1200_USBCFG); - wmb(); - udelay(1000); -} - -static inline void au1000_usb_init(unsigned long rb, int reg) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg); - unsigned long r = __raw_readl(base); - -#if defined(__BIG_ENDIAN) - r |= USBHEN_BE; -#endif - r |= USBHEN_C; - - __raw_writel(r, base); - wmb(); - udelay(1000); -} - - -static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(rb); - unsigned long r = __raw_readl(base + creg); - - if (enable) { - __raw_writel(r | USBHEN_CE, base + creg); - wmb(); - udelay(1000); - __raw_writel(r | USBHEN_CE | USBHEN_E, base + creg); - wmb(); - udelay(1000); - - /* wait for reset complete (read reg twice: au1500 erratum) */ - while (__raw_readl(base + creg), - !(__raw_readl(base + creg) & USBHEN_RD)) - udelay(1000); - } else { - __raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg); - wmb(); - } -} - -static inline int au1000_usb_control(int block, int enable, unsigned long rb, - int creg) -{ - int ret = 0; - - switch (block) { - case ALCHEMY_USB_OHCI0: - __au1xx0_ohci_control(enable, rb, creg); - break; - default: - ret = -ENODEV; - } - return ret; -} - -/* - * alchemy_usb_control - control Alchemy on-chip USB blocks - * @block: USB block to target - * @enable: set 1 to enable a block, 0 to disable - */ -int alchemy_usb_control(int block, int enable) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&alchemy_usb_lock, flags); - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000: - case ALCHEMY_CPU_AU1500: - case ALCHEMY_CPU_AU1100: - ret = au1000_usb_control(block, enable, - AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); - break; - case ALCHEMY_CPU_AU1550: - ret = au1000_usb_control(block, enable, - AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); - break; - case ALCHEMY_CPU_AU1200: - ret = au1200_usb_control(block, enable); - break; - case ALCHEMY_CPU_AU1300: - ret = au1300_usb_control(block, enable); - break; - default: - ret = -ENODEV; - } - spin_unlock_irqrestore(&alchemy_usb_lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(alchemy_usb_control); - - -static unsigned long alchemy_usb_pmdata[2]; - -static void au1000_usb_pm(unsigned long br, int creg, int susp) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(br); - - if (susp) { - alchemy_usb_pmdata[0] = __raw_readl(base + creg); - /* There appears to be some undocumented reset register.... */ - __raw_writel(0, base + 0x04); - wmb(); - __raw_writel(0, base + creg); - wmb(); - } else { - __raw_writel(alchemy_usb_pmdata[0], base + creg); - wmb(); - } -} - -static void au1200_usb_pm(int susp) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1200_USB_OTG_PHYS_ADDR); - if (susp) { - /* save OTG_CAP/MUX registers which indicate port routing */ - /* FIXME: write an OTG driver to do that */ - alchemy_usb_pmdata[0] = __raw_readl(base + 0x00); - alchemy_usb_pmdata[1] = __raw_readl(base + 0x04); - } else { - /* restore access to all MMIO areas */ - au1200_usb_init(); - - /* restore OTG_CAP/MUX registers */ - __raw_writel(alchemy_usb_pmdata[0], base + 0x00); - __raw_writel(alchemy_usb_pmdata[1], base + 0x04); - wmb(); - } -} - -static void au1300_usb_pm(int susp) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); - /* remember Port2 routing */ - if (susp) { - alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4); - } else { - au1300_usb_init(); - __raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4); - wmb(); - } -} - -static void alchemy_usb_pm(int susp) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000: - case ALCHEMY_CPU_AU1500: - case ALCHEMY_CPU_AU1100: - au1000_usb_pm(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG, susp); - break; - case ALCHEMY_CPU_AU1550: - au1000_usb_pm(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG, susp); - break; - case ALCHEMY_CPU_AU1200: - au1200_usb_pm(susp); - break; - case ALCHEMY_CPU_AU1300: - au1300_usb_pm(susp); - break; - } -} - -static int alchemy_usb_suspend(void) -{ - alchemy_usb_pm(1); - return 0; -} - -static void alchemy_usb_resume(void) -{ - alchemy_usb_pm(0); -} - -static struct syscore_ops alchemy_usb_pm_ops = { - .suspend = alchemy_usb_suspend, - .resume = alchemy_usb_resume, -}; - -static int __init alchemy_usb_init(void) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000: - case ALCHEMY_CPU_AU1500: - case ALCHEMY_CPU_AU1100: - au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); - break; - case ALCHEMY_CPU_AU1550: - au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); - break; - case ALCHEMY_CPU_AU1200: - au1200_usb_init(); - break; - case ALCHEMY_CPU_AU1300: - au1300_usb_init(); - break; - } - - register_syscore_ops(&alchemy_usb_pm_ops); - - return 0; -} -arch_initcall(alchemy_usb_init); diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 411bb74..d23321e 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -53,18 +53,11 @@ static void atmel_stop_ehci(struct platform_device *pdev) static int ehci_atmel_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; /* registers start at offset 0x0 */ ehci->caps = hcd->regs; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; + return ehci_setup(hcd); } static const struct hc_driver ehci_atmel_hc_driver = { diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c deleted file mode 100644 index 65c945e..0000000 --- a/drivers/usb/host/ehci-au1xxx.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * EHCI HCD (Host Controller Driver) for USB. - * - * Bus Glue for AMD Alchemy Au1xxx - * - * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org> - * - * Modified for AMD Alchemy Au1200 EHC - * by K.Boge <karsten.boge@amd.com> - * - * This file is licenced under the GPL. - */ - -#include <linux/platform_device.h> -#include <asm/mach-au1x00/au1000.h> - - -extern int usb_disabled(void); - -static int au1xxx_ehci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; - - ehci->caps = hcd->regs; - ret = ehci_setup(hcd); - - ehci->need_io_watchdog = 0; - return ret; -} - -static const struct hc_driver ehci_au1xxx_hc_driver = { - .description = hcd_name, - .product_desc = "Au1xxx EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - * - * FIXME -- ehci_init() doesn't do enough here. - * See ehci-ppc-soc for a complete implementation. - */ - .reset = au1xxx_ehci_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int ret; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - hcd = usb_create_hcd(&ehci_au1xxx_hc_driver, &pdev->dev, "Au1xxx"); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (!hcd->regs) { - pr_debug("devm_request_and_ioremap failed"); - ret = -ENOMEM; - goto err1; - } - - if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) { - printk(KERN_INFO "%s: controller init failed!\n", pdev->name); - ret = -ENODEV; - goto err1; - } - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - bool do_wakeup = device_may_wakeup(dev); - int rc; - - rc = ehci_suspend(hcd, do_wakeup); - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); - - return rc; -} - -static int ehci_hcd_au1xxx_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - alchemy_usb_control(ALCHEMY_USB_EHCI0, 1); - ehci_resume(hcd, false); - - return 0; -} - -static const struct dev_pm_ops au1xxx_ehci_pmops = { - .suspend = ehci_hcd_au1xxx_drv_suspend, - .resume = ehci_hcd_au1xxx_drv_resume, -}; - -#define AU1XXX_EHCI_PMOPS &au1xxx_ehci_pmops - -#else -#define AU1XXX_EHCI_PMOPS NULL -#endif - -static struct platform_driver ehci_hcd_au1xxx_driver = { - .probe = ehci_hcd_au1xxx_drv_probe, - .remove = ehci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "au1xxx-ehci", - .owner = THIS_MODULE, - .pm = AU1XXX_EHCI_PMOPS, - } -}; - -MODULE_ALIAS("platform:au1xxx-ehci"); diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c deleted file mode 100644 index d91708d..0000000 --- a/drivers/usb/host/ehci-cns3xxx.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - */ - -#include <linux/platform_device.h> -#include <linux/atomic.h> -#include <mach/cns3xxx.h> -#include <mach/pm.h> - -static int cns3xxx_ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - * - * Set USB AHB INCR length to 16 - */ - if (atomic_inc_return(&usb_pwr_ref) == 1) { - cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); - cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); - __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), - MISC_CHIP_CONFIG_REG); - } - - ehci->caps = hcd->regs; - - hcd->has_tt = 0; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver cns3xxx_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "CNS3XXX EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = cns3xxx_ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .get_frame_number = ehci_get_frame, - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int cns3xxx_ehci_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; - const struct hc_driver *driver = &cns3xxx_ehci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Found HC with no IRQ.\n"); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr.\n"); - retval = -ENODEV; - goto err1; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (hcd->regs == NULL) { - dev_dbg(dev, "error mapping memory\n"); - retval = -EFAULT; - goto err1; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval == 0) - return retval; - -err1: - usb_put_hcd(hcd); - - return retval; -} - -static int cns3xxx_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - */ - if (atomic_dec_return(&usb_pwr_ref) == 0) - cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -MODULE_ALIAS("platform:cns3xxx-ehci"); - -static struct platform_driver cns3xxx_ehci_driver = { - .probe = cns3xxx_ehci_probe, - .remove = cns3xxx_ehci_remove, - .driver = { - .name = "cns3xxx-ehci", - }, -}; diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 1599806..70b496d 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -18,21 +18,6 @@ /* this file is part of ehci-hcd.c */ -#define ehci_dbg(ehci, fmt, args...) \ - dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_err(ehci, fmt, args...) \ - dev_err (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_info(ehci, fmt, args...) \ - dev_info (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_warn(ehci, fmt, args...) \ - dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) - -#ifdef VERBOSE_DEBUG -# define ehci_vdbg ehci_dbg -#else - static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {} -#endif - #ifdef DEBUG /* check the values in the HCSPARAMS register @@ -352,11 +337,6 @@ static int debug_async_open(struct inode *, struct file *); static int debug_periodic_open(struct inode *, struct file *); static int debug_registers_open(struct inode *, struct file *); static int debug_async_open(struct inode *, struct file *); -static ssize_t debug_lpm_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -static ssize_t debug_lpm_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos); -static int debug_lpm_close(struct inode *inode, struct file *file); static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); static int debug_close(struct inode *, struct file *); @@ -382,14 +362,6 @@ static const struct file_operations debug_registers_fops = { .release = debug_close, .llseek = default_llseek, }; -static const struct file_operations debug_lpm_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = debug_lpm_read, - .write = debug_lpm_write, - .release = debug_lpm_close, - .llseek = noop_llseek, -}; static struct dentry *ehci_debug_root; @@ -971,86 +943,6 @@ static int debug_registers_open(struct inode *inode, struct file *file) return file->private_data ? 0 : -ENOMEM; } -static int debug_lpm_close(struct inode *inode, struct file *file) -{ - return 0; -} - -static ssize_t debug_lpm_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - /* TODO: show lpm stats */ - return 0; -} - -static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - char buf[50]; - size_t len; - u32 temp; - unsigned long port; - u32 __iomem *portsc ; - u32 params; - - hcd = bus_to_hcd(file->private_data); - ehci = hcd_to_ehci(hcd); - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - if (strncmp(buf, "enable", 5) == 0) { - if (strict_strtoul(buf + 7, 10, &port)) - return -EINVAL; - params = ehci_readl(ehci, &ehci->caps->hcs_params); - if (port > HCS_N_PORTS(params)) { - ehci_dbg(ehci, "ERR: LPM on bad port %lu\n", port); - return -ENODEV; - } - portsc = &ehci->regs->port_status[port-1]; - temp = ehci_readl(ehci, portsc); - if (!(temp & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "LPM: no device attached\n"); - return -ENODEV; - } - temp |= PORT_LPM; - ehci_writel(ehci, temp, portsc); - printk(KERN_INFO "force enable LPM for port %lu\n", port); - } else if (strncmp(buf, "hird=", 5) == 0) { - unsigned long hird; - if (strict_strtoul(buf + 5, 16, &hird)) - return -EINVAL; - printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird); - ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24); - ehci_writel(ehci, ehci->command, &ehci->regs->command); - } else if (strncmp(buf, "disable", 7) == 0) { - if (strict_strtoul(buf + 8, 10, &port)) - return -EINVAL; - params = ehci_readl(ehci, &ehci->caps->hcs_params); - if (port > HCS_N_PORTS(params)) { - ehci_dbg(ehci, "ERR: LPM off bad port %lu\n", port); - return -ENODEV; - } - portsc = &ehci->regs->port_status[port-1]; - temp = ehci_readl(ehci, portsc); - if (!(temp & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "ERR: no device attached\n"); - return -ENODEV; - } - temp &= ~PORT_LPM; - ehci_writel(ehci, temp, portsc); - printk(KERN_INFO "disabled LPM for port %lu\n", port); - } else - return -EOPNOTSUPP; - return count; -} - static inline void create_debug_files (struct ehci_hcd *ehci) { struct usb_bus *bus = &ehci_to_hcd(ehci)->self; @@ -1071,10 +963,6 @@ static inline void create_debug_files (struct ehci_hcd *ehci) &debug_registers_fops)) goto file_error; - if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus, - &debug_lpm_fops)) - goto file_error; - return; file_error: diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 9bfde82..fd9b542 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -222,7 +222,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, if (pdata->controller_ver < 0) { dev_warn(hcd->self.controller, "Could not get controller version\n"); - return; + return -ENODEV; } portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); @@ -349,7 +349,6 @@ static int ehci_fsl_reinit(struct ehci_hcd *ehci) { if (ehci_fsl_usb_setup(ehci)) return -EINVAL; - ehci_port_power(ehci, 0); return 0; } diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index 3180cb3..da42695 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -34,22 +34,6 @@ #define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */ -/* called during probe() after chip reset completes */ -static int ehci_grlib_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 1); - - return retval; -} - - static const struct hc_driver ehci_grlib_hc_driver = { .description = hcd_name, .product_desc = "GRLIB GRUSBHC EHCI", @@ -64,7 +48,7 @@ static const struct hc_driver ehci_grlib_hc_driver = { /* * basic lifecycle operations */ - .reset = ehci_grlib_setup, + .reset = ehci_setup, .start = ehci_run, .stop = ehci_stop, .shutdown = ehci_shutdown, diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 6bf6c42..28f694e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -39,7 +39,6 @@ #include <linux/dma-mapping.h> #include <linux/debugfs.h> #include <linux/slab.h> -#include <linux/uaccess.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -108,19 +107,39 @@ static bool ignore_oc = 0; module_param (ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); -/* for link power management(LPM) feature */ -static unsigned int hird; -module_param(hird, int, S_IRUGO); -MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); - #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) /*-------------------------------------------------------------------------*/ #include "ehci.h" -#include "ehci-dbg.c" #include "pci-quirks.h" +/* + * The MosChip MCS9990 controller updates its microframe counter + * a little before the frame counter, and occasionally we will read + * the invalid intermediate value. Avoid problems by checking the + * microframe number (the low-order 3 bits); if they are 0 then + * re-read the register to get the correct value. + */ +static unsigned ehci_moschip_read_frame_index(struct ehci_hcd *ehci) +{ + unsigned uf; + + uf = ehci_readl(ehci, &ehci->regs->frame_index); + if (unlikely((uf & 7) == 0)) + uf = ehci_readl(ehci, &ehci->regs->frame_index); + return uf; +} + +static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) +{ + if (ehci->frame_index_bug) + return ehci_moschip_read_frame_index(ehci); + return ehci_readl(ehci, &ehci->regs->frame_index); +} + +#include "ehci-dbg.c" + /*-------------------------------------------------------------------------*/ /* @@ -293,7 +312,6 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); #include "ehci-timer.c" #include "ehci-hub.c" -#include "ehci-lpm.c" #include "ehci-mem.c" #include "ehci-q.c" #include "ehci-sched.c" @@ -353,24 +371,6 @@ static void ehci_shutdown(struct usb_hcd *hcd) hrtimer_cancel(&ehci->hrtimer); } -static void ehci_port_power (struct ehci_hcd *ehci, int is_on) -{ - unsigned port; - - if (!HCS_PPC (ehci->hcs_params)) - return; - - ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down"); - for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) - (void) ehci_hub_control(ehci_to_hcd(ehci), - is_on ? SetPortFeature : ClearPortFeature, - USB_PORT_FEAT_POWER, - port--, NULL, 0); - /* Flush those writes */ - ehci_readl(ehci, &ehci->regs->command); - msleep(20); -} - /*-------------------------------------------------------------------------*/ /* @@ -503,7 +503,7 @@ static int ehci_init(struct usb_hcd *hcd) /* controllers may cache some of the periodic schedule ... */ if (HCC_ISOC_CACHE(hcc_params)) // full frame cache - ehci->i_thresh = 2 + 8; + ehci->i_thresh = 0; else // N microframes cached ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); @@ -555,17 +555,6 @@ static int ehci_init(struct usb_hcd *hcd) temp &= ~(3 << 2); temp |= (EHCI_TUNE_FLS << 2); } - if (HCC_LPM(hcc_params)) { - /* support link power management EHCI 1.1 addendum */ - ehci_dbg(ehci, "support lpm\n"); - ehci->has_lpm = 1; - if (hird > 0xf) { - ehci_dbg(ehci, "hird %d invalid, use default 0", - hird); - hird = 0; - } - temp |= hird << 24; - } ehci->command = temp; /* Accept arbitrarily long scatter-gather lists */ @@ -660,7 +649,7 @@ static int ehci_run (struct usb_hcd *hcd) return 0; } -static int ehci_setup(struct usb_hcd *hcd) +int ehci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; @@ -691,6 +680,7 @@ static int ehci_setup(struct usb_hcd *hcd) return 0; } +EXPORT_SYMBOL_GPL(ehci_setup); /*-------------------------------------------------------------------------*/ @@ -1096,7 +1086,7 @@ static int ehci_get_frame (struct usb_hcd *hcd) /* These routines handle the generic parts of controller suspend/resume */ -static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) +int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -1119,9 +1109,10 @@ static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) return 0; } +EXPORT_SYMBOL_GPL(ehci_suspend); /* Returns 0 if power was preserved, 1 if power was lost */ -static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated) +int ehci_resume(struct usb_hcd *hcd, bool hibernated) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -1177,33 +1168,82 @@ static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated) ehci->rh_state = EHCI_RH_SUSPENDED; spin_unlock_irq(&ehci->lock); - /* here we "know" root ports should always stay powered */ - ehci_port_power(ehci, 1); - return 1; } +EXPORT_SYMBOL_GPL(ehci_resume); #endif /*-------------------------------------------------------------------------*/ /* - * The EHCI in ChipIdea HDRC cannot be a separate module or device, - * because its registers (and irq) are shared between host/gadget/otg - * functions and in order to facilitate role switching we cannot - * give the ehci driver exclusive access to those. + * Generic structure: This gets copied for platform drivers so that + * individual entries can be overridden as needed. */ -#ifndef CHIPIDEA_EHCI + +static const struct hc_driver ehci_hc_driver = { + .description = hcd_name, + .product_desc = "EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, +}; + +void ehci_init_driver(struct hc_driver *drv, + const struct ehci_driver_overrides *over) +{ + /* Copy the generic table to drv and then apply the overrides */ + *drv = ehci_hc_driver; + + drv->product_desc = over->product_desc; + drv->hcd_priv_size += over->extra_priv_size; + if (over->reset) + drv->reset = over->reset; +} +EXPORT_SYMBOL_GPL(ehci_init_driver); + +/*-------------------------------------------------------------------------*/ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_LICENSE ("GPL"); -#ifdef CONFIG_PCI -#include "ehci-pci.c" -#define PCI_DRIVER ehci_pci_driver -#endif - #ifdef CONFIG_USB_EHCI_FSL #include "ehci-fsl.c" #define PLATFORM_DRIVER ehci_fsl_driver @@ -1219,11 +1259,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_sh_driver #endif -#ifdef CONFIG_MIPS_ALCHEMY -#include "ehci-au1xxx.c" -#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver -#endif - #ifdef CONFIG_USB_EHCI_HCD_OMAP #include "ehci-omap.c" #define PLATFORM_DRIVER ehci_hcd_omap_driver @@ -1249,11 +1284,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_orion_driver #endif -#ifdef CONFIG_ARCH_IXP4XX -#include "ehci-ixp4xx.c" -#define PLATFORM_DRIVER ixp4xx_ehci_driver -#endif - #ifdef CONFIG_USB_W90X900_EHCI #include "ehci-w90x900.c" #define PLATFORM_DRIVER ehci_hcd_w90x900_driver @@ -1269,11 +1299,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_octeon_driver #endif -#ifdef CONFIG_USB_CNS3XXX_EHCI -#include "ehci-cns3xxx.c" -#define PLATFORM_DRIVER cns3xxx_ehci_driver -#endif - #ifdef CONFIG_ARCH_VT8500 #include "ehci-vt8500.c" #define PLATFORM_DRIVER vt8500_ehci_driver @@ -1314,34 +1339,23 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_grlib_driver #endif -#ifdef CONFIG_CPU_XLR -#include "ehci-xls.c" -#define PLATFORM_DRIVER ehci_xls_driver -#endif - #ifdef CONFIG_USB_EHCI_MV #include "ehci-mv.c" #define PLATFORM_DRIVER ehci_mv_driver #endif -#ifdef CONFIG_MACH_LOONGSON1 -#include "ehci-ls1x.c" -#define PLATFORM_DRIVER ehci_ls1x_driver -#endif - #ifdef CONFIG_MIPS_SEAD3 #include "ehci-sead3.c" #define PLATFORM_DRIVER ehci_hcd_sead3_driver #endif -#ifdef CONFIG_USB_EHCI_HCD_PLATFORM -#include "ehci-platform.c" -#define PLATFORM_DRIVER ehci_platform_driver -#endif - -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ - !defined(XILINX_OF_PLATFORM_DRIVER) +#if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \ + !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ + !defined(CONFIG_USB_CHIPIDEA_HOST) && \ + !defined(PLATFORM_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ + !defined(XILINX_OF_PLATFORM_DRIVER) #error "missing bus glue for ehci-hcd" #endif @@ -1378,12 +1392,6 @@ static int __init ehci_hcd_init(void) goto clean0; #endif -#ifdef PCI_DRIVER - retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) - goto clean1; -#endif - #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); if (retval < 0) @@ -1415,10 +1423,6 @@ clean3: ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); clean2: #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -clean1: -#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); clean0: @@ -1444,9 +1448,6 @@ static void __exit ehci_hcd_cleanup(void) #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -#endif #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif @@ -1456,5 +1457,3 @@ static void __exit ehci_hcd_cleanup(void) clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); } module_exit(ehci_hcd_cleanup); - -#endif /* CHIPIDEA_EHCI */ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 914ce93..4ccb97c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -56,6 +56,19 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) if (!ehci->owned_ports) return; + /* Make sure the ports are powered */ + port = HCS_N_PORTS(ehci->hcs_params); + while (port--) { + if (test_bit(port, &ehci->owned_ports)) { + reg = &ehci->regs->port_status[port]; + status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; + if (!(status & PORT_POWER)) { + status |= PORT_POWER; + ehci_writel(ehci, status, reg); + } + } + } + /* Give the connections some time to appear */ msleep(20); @@ -384,11 +397,24 @@ static int ehci_bus_resume (struct usb_hcd *hcd) ehci_writel(ehci, ehci->command, &ehci->regs->command); ehci->rh_state = EHCI_RH_RUNNING; - /* Some controller/firmware combinations need a delay during which - * they set up the port statuses. See Bugzilla #8190. */ - spin_unlock_irq(&ehci->lock); - msleep(8); - spin_lock_irq(&ehci->lock); + /* + * According to Bugzilla #8190, the port status for some controllers + * will be wrong without a delay. At their wrong status, the port + * is enabled, but not suspended neither resumed. + */ + i = HCS_N_PORTS(ehci->hcs_params); + while (i--) { + temp = ehci_readl(ehci, &ehci->regs->port_status[i]); + if ((temp & PORT_PE) && + !(temp & (PORT_SUSPEND | PORT_RESUME))) { + ehci_dbg(ehci, "Port status(0x%x) is wrong\n", temp); + spin_unlock_irq(&ehci->lock); + msleep(8); + spin_lock_irq(&ehci->lock); + break; + } + } + if (ehci->shutdown) goto shutdown; @@ -764,11 +790,6 @@ static int ehci_hub_control ( status_reg); break; case USB_PORT_FEAT_C_CONNECTION: - if (ehci->has_lpm) { - /* clear PORTSC bits on disconnect */ - temp &= ~PORT_LPM; - temp &= ~PORT_DEV_ADDR; - } ehci_writel(ehci, temp | PORT_CSC, status_reg); break; case USB_PORT_FEAT_C_OVER_CURRENT: @@ -1088,8 +1109,7 @@ error_exit: return retval; } -static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd, - int portnum) +static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -1098,8 +1118,7 @@ static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd, set_owner(ehci, --portnum, PORT_OWNER); } -static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd, - int portnum) +static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); u32 __iomem *reg; diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c deleted file mode 100644 index f224c0a..0000000 --- a/drivers/usb/host/ehci-ixp4xx.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * IXP4XX EHCI Host Controller Driver - * - * Author: Vladimir Barinov <vbarinov@embeddedalley.com> - * - * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com> - * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include <linux/platform_device.h> - -static int ixp4xx_ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval = 0; - - ehci->big_endian_desc = 1; - ehci->big_endian_mmio = 1; - - ehci->caps = hcd->regs + 0x100; - - hcd->has_tt = 1; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver ixp4xx_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "IXP4XX EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = ixp4xx_ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .get_frame_number = ehci_get_frame, - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#if defined(CONFIG_PM) - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ixp4xx_ehci_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - const struct hc_driver *driver = &ixp4xx_ehci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto fail_create_hcd; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto fail_request_resource; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto fail_request_resource; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval) - goto fail_request_resource; - - return retval; - -fail_request_resource: - usb_put_hcd(hcd); -fail_create_hcd: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); - return retval; -} - -static int ixp4xx_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -MODULE_ALIAS("platform:ixp4xx-ehci"); - -static struct platform_driver ixp4xx_ehci_driver = { - .probe = ixp4xx_ehci_probe, - .remove = ixp4xx_ehci_remove, - .driver = { - .name = "ixp4xx-ehci", - }, -}; diff --git a/drivers/usb/host/ehci-lpm.c b/drivers/usb/host/ehci-lpm.c deleted file mode 100644 index 2111627..0000000 --- a/drivers/usb/host/ehci-lpm.c +++ /dev/null @@ -1,84 +0,0 @@ -/* ehci-lpm.c EHCI HCD LPM support code - * Copyright (c) 2008 - 2010, Intel Corporation. - * Author: Jacob Pan <jacob.jun.pan@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* this file is part of ehci-hcd.c */ -static int __maybe_unused ehci_lpm_set_da(struct ehci_hcd *ehci, - int dev_addr, int port_num) -{ - u32 __iomem portsc; - - ehci_dbg(ehci, "set dev address %d for port %d\n", dev_addr, port_num); - if (port_num > HCS_N_PORTS(ehci->hcs_params)) { - ehci_dbg(ehci, "invalid port number %d\n", port_num); - return -ENODEV; - } - portsc = ehci_readl(ehci, &ehci->regs->port_status[port_num-1]); - portsc &= ~PORT_DEV_ADDR; - portsc |= dev_addr<<25; - ehci_writel(ehci, portsc, &ehci->regs->port_status[port_num-1]); - return 0; -} - -/* - * this function is used to check if the device support LPM - * if yes, mark the PORTSC register with PORT_LPM bit - */ -static int __maybe_unused ehci_lpm_check(struct ehci_hcd *ehci, int port) -{ - u32 __iomem *portsc ; - u32 val32; - int retval; - - portsc = &ehci->regs->port_status[port-1]; - val32 = ehci_readl(ehci, portsc); - if (!(val32 & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "LPM: no device attached\n"); - return -ENODEV; - } - val32 |= PORT_LPM; - ehci_writel(ehci, val32, portsc); - msleep(5); - val32 |= PORT_SUSPEND; - ehci_dbg(ehci, "Sending LPM 0x%08x to port %d\n", val32, port); - ehci_writel(ehci, val32, portsc); - /* wait for ACK */ - msleep(10); - retval = handshake(ehci, &ehci->regs->port_status[port-1], PORT_SSTS, - PORTSC_SUSPEND_STS_ACK, 125); - dbg_port(ehci, "LPM", port, val32); - if (retval != -ETIMEDOUT) { - ehci_dbg(ehci, "LPM: device ACK for LPM\n"); - val32 |= PORT_LPM; - /* - * now device should be in L1 sleep, let's wake up the device - * so that we can complete enumeration. - */ - ehci_writel(ehci, val32, portsc); - msleep(10); - val32 |= PORT_RESUME; - ehci_writel(ehci, val32, portsc); - } else { - ehci_dbg(ehci, "LPM: device does not ACK, disable LPM %d\n", - retval); - val32 &= ~PORT_LPM; - retval = -ETIMEDOUT; - ehci_writel(ehci, val32, portsc); - } - - return retval; -} diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c deleted file mode 100644 index ca75965..0000000 --- a/drivers/usb/host/ehci-ls1x.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Bus Glue for Loongson LS1X built-in EHCI controller. - * - * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - - -#include <linux/platform_device.h> - -static int ehci_ls1x_reset(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; - - ehci->caps = hcd->regs; - - ret = ehci_setup(hcd); - if (ret) - return ret; - - ehci_port_power(ehci, 0); - - return 0; -} - -static const struct hc_driver ehci_ls1x_hc_driver = { - .description = hcd_name, - .product_desc = "LOONGSON1 EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_ls1x_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_ls1x_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int irq; - int ret; - - pr_debug("initializing loongson1 ehci USB Controller\n"); - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - - hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -EFAULT; - goto err_put_hcd; - } - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) - goto err_put_hcd; - - return ret; - -err_put_hcd: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_hcd_ls1x_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ehci_ls1x_driver = { - .probe = ehci_hcd_ls1x_probe, - .remove = ehci_hcd_ls1x_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ls1x-ehci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci"); diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 4af4dc5..7fa1ba4 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -53,7 +53,6 @@ static int ehci_msm_reset(struct usb_hcd *hcd) /* Disable streaming mode and select host mode */ writel(0x13, USB_USBMODE); - ehci_port_power(ehci, 1); return 0; } diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 4a08fc0..a37224a 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -40,16 +40,10 @@ struct ehci_mxc_priv { static int ehci_mxc_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; hcd->has_tt = 1; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - return 0; + return ehci_setup(hcd); } static const struct hc_driver ehci_mxc_hc_driver = { diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index ba26957a..a89750f 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -159,9 +159,6 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hcd); - /* root ports should always stay powered */ - ehci_port_power(ehci, 1); - return 0; err3: ehci_octeon_stop(); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index d7fe287..44e7d0f 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -146,9 +146,6 @@ static int omap_ehci_init(struct usb_hcd *hcd) gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); } - /* root ports should always stay powered */ - ehci_port_power(ehci, 1); - return rc; } diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 8e7eca6..96da679 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -101,20 +101,6 @@ static void orion_usb_phy_v1_setup(struct usb_hcd *hcd) wrl(USB_MODE, 0x13); } -static int ehci_orion_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - static const struct hc_driver ehci_orion_hc_driver = { .description = hcd_name, .product_desc = "Marvell Orion EHCI", @@ -129,7 +115,7 @@ static const struct hc_driver ehci_orion_hc_driver = { /* * basic lifecycle operations */ - .reset = ehci_orion_setup, + .reset = ehci_setup, .start = ehci_run, .stop = ehci_stop, .shutdown = ehci_shutdown, @@ -160,7 +146,7 @@ static const struct hc_driver ehci_orion_hc_driver = { .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; -static void __init +static void __devinit ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, const struct mbus_dram_target_info *dram) { diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 2cb7d37..46018e9 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -18,9 +18,18 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef CONFIG_PCI -#error "This file is PCI bus glue. CONFIG_PCI must be defined." -#endif +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ehci.h" +#include "pci-quirks.h" + +#define DRIVER_DESC "EHCI PCI platform driver" + +static const char hcd_name[] = "ehci-pci"; /* defined here to avoid adding to pci_ids.h for single instance use */ #define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70 @@ -103,7 +112,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) } break; case PCI_VENDOR_ID_INTEL: - ehci->fs_i_thresh = 1; if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) hcd->has_tt = 1; break; @@ -203,11 +211,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; case PCI_VENDOR_ID_INTEL: ehci->need_io_watchdog = 0; - if (pdev->device == 0x0806 || pdev->device == 0x0811 - || pdev->device == 0x0829) { - ehci_info(ehci, "disable lpm for langwell/penwell\n"); - ehci->has_lpm = 0; - } break; case PCI_VENDOR_ID_NVIDIA: switch (pdev->device) { @@ -217,8 +220,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) * devices with PPCD enabled. */ case 0x0d9d: - ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89"); - ehci->has_lpm = 0; + ehci_info(ehci, "disable ppcd for nvidia mcp89\n"); ehci->has_ppcd = 0; ehci->command &= ~CMD_PPCEE; break; @@ -304,7 +306,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); #endif - ehci_port_power(ehci, 1); retval = ehci_pci_reinit(ehci, pdev); done: return retval; @@ -323,11 +324,6 @@ done: * Also they depend on separate root hub suspend/resume. */ -static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - return ehci_suspend(hcd, do_wakeup); -} - static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && @@ -378,76 +374,18 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) (void) ehci_pci_reinit(ehci, pdev); return 0; } -#endif -static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int rc = 0; - - if (!udev->parent) /* udev is root hub itself, impossible */ - rc = -1; - /* we only support lpm device connected to root hub yet */ - if (ehci->has_lpm && !udev->parent->parent) { - rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); - if (!rc) - rc = ehci_lpm_check(ehci, udev->portnum); - } - return rc; -} +#else -static const struct hc_driver ehci_pci_hc_driver = { - .description = hcd_name, - .product_desc = "EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), +#define ehci_suspend NULL +#define ehci_pci_resume NULL +#endif /* CONFIG_PM */ - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, +static struct hc_driver __read_mostly ehci_pci_hc_driver; - /* - * basic lifecycle operations - */ +static const struct ehci_driver_overrides overrides = { + .product_desc = "EHCI PCI host controller", .reset = ehci_pci_setup, - .start = ehci_run, -#ifdef CONFIG_PM - .pci_suspend = ehci_pci_suspend, - .pci_resume = ehci_pci_resume, -#endif - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* - * call back when device connected and addressed - */ - .update_device = ehci_update_device, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; /*-------------------------------------------------------------------------*/ @@ -480,3 +418,31 @@ static struct pci_driver ehci_pci_driver = { }, #endif }; + +static int __init ehci_pci_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_pci_hc_driver, &overrides); + + /* Entries for the PCI suspend/resume callbacks are special */ + ehci_pci_hc_driver.pci_suspend = ehci_suspend; + ehci_pci_hc_driver.pci_resume = ehci_pci_resume; + + return pci_register_driver(&ehci_pci_driver); +} +module_init(ehci_pci_init); + +static void __exit ehci_pci_cleanup(void) +{ + pci_unregister_driver(&ehci_pci_driver); +} +module_exit(ehci_pci_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("David Brownell"); +MODULE_AUTHOR("Alan Stern"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 764e010..feeedf8 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -18,9 +18,21 @@ * * Licensed under the GNU/GPL. See COPYING for details. */ +#include <linux/kernel.h> +#include <linux/hrtimer.h> +#include <linux/io.h> +#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> #include <linux/usb/ehci_pdriver.h> +#include "ehci.h" + +#define DRIVER_DESC "EHCI generic platform driver" + +static const char hcd_name[] = "ehci-platform"; + static int ehci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); @@ -38,44 +50,16 @@ static int ehci_platform_reset(struct usb_hcd *hcd) if (retval) return retval; - if (pdata->port_power_on) - ehci_port_power(ehci, 1); - if (pdata->port_power_off) - ehci_port_power(ehci, 0); - + if (pdata->no_io_watchdog) + ehci->need_io_watchdog = 0; return 0; } -static const struct hc_driver ehci_platform_hc_driver = { - .description = hcd_name, - .product_desc = "Generic Platform EHCI Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - .reset = ehci_platform_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, +static struct hc_driver __read_mostly ehci_platform_hc_driver; - .get_frame_number = ehci_get_frame, - - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#if defined(CONFIG_PM) - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +static const struct ehci_driver_overrides platform_overrides = { + .product_desc = "Generic Platform EHCI controller", + .reset = ehci_platform_reset, }; static int __devinit ehci_platform_probe(struct platform_device *dev) @@ -96,12 +80,12 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provided"); + dev_err(&dev->dev, "no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provided"); + dev_err(&dev->dev, "no memory resource provided"); return -ENXIO; } @@ -121,29 +105,19 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_err("controller already in use"); - err = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&dev->dev, res_mem); if (!hcd->regs) { err = -ENOMEM; - goto err_release_region; + goto err_put_hcd; } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_iounmap; + goto err_put_hcd; platform_set_drvdata(dev, hcd); return err; -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put_hcd: usb_put_hcd(hcd); err_power: @@ -159,8 +133,6 @@ static int __devexit ehci_platform_remove(struct platform_device *dev) struct usb_ehci_pdata *pdata = dev->dev.platform_data; usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(dev, NULL); @@ -233,3 +205,26 @@ static struct platform_driver ehci_platform_driver = { .pm = &ehci_platform_pm_ops, } }; + +static int __init ehci_platform_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); + return platform_driver_register(&ehci_platform_driver); +} +module_init(ehci_platform_init); + +static void __exit ehci_platform_cleanup(void) +{ + platform_driver_unregister(&ehci_platform_driver); +} +module_exit(ehci_platform_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_AUTHOR("Alan Stern"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index 087aee2..363890e 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c @@ -90,7 +90,6 @@ static int ehci_msp_setup(struct usb_hcd *hcd) return retval; usb_hcd_tdi_set_mode(ehci); - ehci_port_power(ehci, 0); return retval; } diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 85b74be..abc178d 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -136,7 +136,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev) goto fail_clk; } - err = clk_enable(s5p_ehci->clk); + err = clk_prepare_enable(s5p_ehci->clk); if (err) goto fail_clk; @@ -183,7 +183,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev) return 0; fail_io: - clk_disable(s5p_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); fail_clk: usb_put_hcd(hcd); return err; @@ -200,7 +200,7 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(s5p_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); usb_put_hcd(hcd); @@ -231,7 +231,7 @@ static int s5p_ehci_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(s5p_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); return rc; } @@ -243,7 +243,7 @@ static int s5p_ehci_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; - clk_enable(s5p_ehci->clk); + clk_prepare_enable(s5p_ehci->clk); if (pdata && pdata->phy_init) pdata->phy_init(pdev, S5P_USB_PHY_HOST); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 7cf3da7..2e14714 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -36,29 +36,6 @@ static int ehci_get_frame (struct usb_hcd *hcd); -#ifdef CONFIG_PCI - -static unsigned ehci_read_frame_index(struct ehci_hcd *ehci) -{ - unsigned uf; - - /* - * The MosChip MCS9990 controller updates its microframe counter - * a little before the frame counter, and occasionally we will read - * the invalid intermediate value. Avoid problems by checking the - * microframe number (the low-order 3 bits); if they are 0 then - * re-read the register to get the correct value. - */ - uf = ehci_readl(ehci, &ehci->regs->frame_index); - if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0))) - uf = ehci_readl(ehci, &ehci->regs->frame_index); - return uf; -} - -#endif - -/*-------------------------------------------------------------------------*/ - /* * periodic_next_shadow - return "next" pointer on shadow list * @periodic: host pointer to qh/itd/sitd @@ -1361,7 +1338,7 @@ sitd_slot_ok ( * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! */ -#define SCHEDULE_SLOP 80 /* microframes */ +#define SCHEDULING_DELAY 40 /* microframes */ static int iso_stream_schedule ( @@ -1370,7 +1347,7 @@ iso_stream_schedule ( struct ehci_iso_stream *stream ) { - u32 now, next, start, period, span; + u32 now, base, next, start, period, span; int status; unsigned mod = ehci->periodic_size << 3; struct ehci_iso_sched *sched = urb->hcpriv; @@ -1382,62 +1359,72 @@ iso_stream_schedule ( span <<= 3; } - if (span > mod - SCHEDULE_SLOP) { - ehci_dbg (ehci, "iso request %p too long\n", urb); - status = -EFBIG; - goto fail; - } - now = ehci_read_frame_index(ehci) & (mod - 1); /* Typical case: reuse current schedule, stream is still active. * Hopefully there are no gaps from the host falling behind - * (irq delays etc), but if there are we'll take the next - * slot in the schedule, implicitly assuming URB_ISO_ASAP. + * (irq delays etc). If there are, the behavior depends on + * whether URB_ISO_ASAP is set. */ if (likely (!list_empty (&stream->td_list))) { - u32 excess; - /* For high speed devices, allow scheduling within the - * isochronous scheduling threshold. For full speed devices - * and Intel PCI-based controllers, don't (work around for - * Intel ICH9 bug). - */ - if (!stream->highspeed && ehci->fs_i_thresh) - next = now + ehci->i_thresh; + /* Take the isochronous scheduling threshold into account */ + if (ehci->i_thresh) + next = now + ehci->i_thresh; /* uframe cache */ else - next = now; + next = (now + 2 + 7) & ~0x07; /* full frame cache */ - /* Fell behind (by up to twice the slop amount)? - * We decide based on the time of the last currently-scheduled - * slot, not the time of the next available slot. + /* + * Use ehci->last_iso_frame as the base. There can't be any + * TDs scheduled for earlier than that. */ - excess = (stream->next_uframe - period - next) & (mod - 1); - if (excess >= mod - 2 * SCHEDULE_SLOP) - start = next + excess - mod + period * - DIV_ROUND_UP(mod - excess, period); - else - start = next + excess + period; - if (start - now >= mod) { - ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", - urb, start - now - period, period, - mod); - status = -EFBIG; + base = ehci->last_iso_frame << 3; + next = (next - base) & (mod - 1); + start = (stream->next_uframe - base) & (mod - 1); + + /* Is the schedule already full? */ + if (unlikely(start < period)) { + ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n", + urb, stream->next_uframe, base, + period, mod); + status = -ENOSPC; goto fail; } + + /* Behind the scheduling threshold? */ + if (unlikely(start < next)) { + + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + start += (next - start + period - 1) & -period; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. + */ + else if (start + span - period < next) { + ehci_dbg(ehci, "iso urb late %p (%u+%u < %u)\n", + urb, start + base, + span - period, next + base); + status = -EXDEV; + goto fail; + } + } + + start += base; } /* need to schedule; when's the next (u)frame we could start? * this is bigger than ehci->i_thresh allows; scheduling itself - * isn't free, the slop should handle reasonably slow cpus. it + * isn't free, the delay should handle reasonably slow cpus. it * can also help high bandwidth if the dma and irq loads don't * jump until after the queue is primed. */ else { int done = 0; - start = SCHEDULE_SLOP + (now & ~0x07); - /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ + base = now & ~0x07; + start = base + SCHEDULING_DELAY; /* find a uframe slot with enough bandwidth. * Early uframes are more precious because full-speed @@ -1464,19 +1451,16 @@ iso_stream_schedule ( /* no room in the schedule */ if (!done) { - ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", - urb, now, now + mod); + ehci_dbg(ehci, "iso sched full %p", urb); status = -ENOSPC; goto fail; } } /* Tried to schedule too far into the future? */ - if (unlikely(start - now + span - period - >= mod - 2 * SCHEDULE_SLOP)) { - ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", - urb, start - now, span - period, - mod - 2 * SCHEDULE_SLOP); + if (unlikely(start - base + span - period >= mod)) { + ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n", + urb, start - base, span - period, mod); status = -EFBIG; goto fail; } @@ -1490,7 +1474,7 @@ iso_stream_schedule ( /* Make sure scan_isoc() sees these */ if (ehci->isoc_count == 0) - ehci->next_frame = now >> 3; + ehci->last_iso_frame = now >> 3; return 0; fail: @@ -1708,7 +1692,7 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd) urb->actual_length += desc->actual_length; } else { /* URB was too late */ - desc->status = -EXDEV; + urb->error_count++; } } @@ -2081,7 +2065,7 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) t = hc32_to_cpup(ehci, &sitd->hw_results); /* report transfer status */ - if (t & SITD_ERRS) { + if (unlikely(t & SITD_ERRS)) { urb->error_count++; if (t & SITD_STS_DBE) desc->status = usb_pipein (urb->pipe) @@ -2091,6 +2075,9 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) desc->status = -EOVERFLOW; else /* XACT, MMF, etc */ desc->status = -EPROTO; + } else if (unlikely(t & SITD_STS_ACTIVE)) { + /* URB was too late */ + urb->error_count++; } else { desc->status = 0; desc->actual_length = desc->length - SITD_LENGTH(t); @@ -2220,16 +2207,16 @@ static void scan_isoc(struct ehci_hcd *ehci) now_frame = (uf >> 3) & fmask; live = true; } else { - now_frame = (ehci->next_frame - 1) & fmask; + now_frame = (ehci->last_iso_frame - 1) & fmask; live = false; } ehci->now_frame = now_frame; - frame = ehci->next_frame; for (;;) { union ehci_shadow q, *q_p; __hc32 type, *hw_p; + frame = ehci->last_iso_frame; restart: /* scan each element in frame's queue for completions */ q_p = &ehci->pshadow [frame]; @@ -2334,7 +2321,6 @@ restart: /* Stop when we have reached the current frame */ if (frame == now_frame) break; - frame = (frame + 1) & fmask; + ehci->last_iso_frame = (frame + 1) & fmask; } - ehci->next_frame = now_frame; } diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index 6081e1e..0c90a24 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -21,17 +21,10 @@ struct ehci_sh_priv { static int ehci_sh_reset(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; ehci->caps = hcd->regs; - ret = ehci_setup(hcd); - if (unlikely(ret)) - return ret; - - ehci_port_power(ehci, 0); - - return ret; + return ehci_setup(hcd); } static const struct hc_driver ehci_sh_hc_driver = { diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index c718a06..719ca48 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -37,18 +37,11 @@ static void spear_stop_ehci(struct spear_ehci *ehci) static int ehci_spear_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval = 0; /* registers start at offset 0x0 */ ehci->caps = hcd->regs; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; + return ehci_setup(hcd); } static const struct hc_driver ehci_spear_hc_driver = { diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 6223d175..94ee321 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -28,7 +28,10 @@ #include <linux/pm_runtime.h> #include <linux/usb/tegra_usb_phy.h> -#include <mach/iomap.h> + +#define TEGRA_USB_BASE 0xC5000000 +#define TEGRA_USB2_BASE 0xC5004000 +#define TEGRA_USB3_BASE 0xC5008000 #define TEGRA_USB_DMA_ALIGN 32 @@ -277,7 +280,6 @@ static void tegra_ehci_shutdown(struct usb_hcd *hcd) static int tegra_ehci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; @@ -285,12 +287,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) /* switch to host mode */ hcd->has_tt = 1; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 1); - return retval; + return ehci_setup(hcd); } struct dma_aligned_buffer { diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c index 96722bf..11695d5 100644 --- a/drivers/usb/host/ehci-vt8500.c +++ b/drivers/usb/host/ehci-vt8500.c @@ -19,22 +19,6 @@ #include <linux/of.h> #include <linux/platform_device.h> -static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int rc = 0; - - if (!udev->parent) /* udev is root hub itself, impossible */ - rc = -1; - /* we only support lpm device connected to root hub yet */ - if (ehci->has_lpm && !udev->parent->parent) { - rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); - if (!rc) - rc = ehci_lpm_check(ehci, udev->portnum); - } - return rc; -} - static const struct hc_driver vt8500_ehci_hc_driver = { .description = hcd_name, .product_desc = "VT8500 EHCI", @@ -77,14 +61,11 @@ static const struct hc_driver vt8500_ehci_hc_driver = { .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, - /* - * call back when device connected and addressed - */ - .update_device = ehci_update_device, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; +static u64 vt8500_ehci_dma_mask = DMA_BIT_MASK(32); + static int vt8500_ehci_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd; @@ -95,6 +76,14 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &vt8500_ehci_dma_mask; + if (pdev->resource[1].flags != IORESOURCE_IRQ) { pr_debug("resource[1] is not IORESOURCE_IRQ"); return -ENOMEM; diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index ec59808..fdd7c48 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -13,7 +13,7 @@ #include <linux/platform_device.h> -/*ebable phy0 and phy1 for w90p910*/ +/* enable phy0 and phy1 for w90p910 */ #define ENPHY (0x01<<8) #define PHY0_CTR (0xA4) #define PHY1_CTR (0xA8) diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c deleted file mode 100644 index 8dc6a22..0000000 --- a/drivers/usb/host/ehci-xls.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * EHCI HCD for Netlogic XLS processors. - * - * (C) Copyright 2011 Netlogic Microsystems Inc. - * - * Based on various ehci-*.c drivers - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/platform_device.h> - -static int ehci_xls_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci->caps = hcd->regs; - - return ehci_setup(hcd); -} - -int ehci_xls_probe_internal(const struct hc_driver *driver, - struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int retval, irq; - - /* Get our IRQ from an earlier registered Platform Resource */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - - /* Get our Memory Handle */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Error: MMIO Handle %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto err2; - } - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval != 0) - goto err4; - return retval; - -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), - retval); - return retval; -} - -static struct hc_driver ehci_xls_hc_driver = { - .description = hcd_name, - .product_desc = "XLS EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - .reset = ehci_xls_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - .get_frame_number = ehci_get_frame, - - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_xls_probe(struct platform_device *pdev) -{ - if (usb_disabled()) - return -ENODEV; - - return ehci_xls_probe_internal(&ehci_xls_hc_driver, pdev); -} - -static int ehci_xls_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - return 0; -} - -MODULE_ALIAS("ehci-xls"); - -static struct platform_driver ehci_xls_driver = { - .probe = ehci_xls_probe, - .remove = ehci_xls_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ehci-xls", - }, -}; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index da07d98..24a8ada 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -143,7 +143,7 @@ struct ehci_hcd { /* one per controller */ struct ehci_qh *intr_unlink_last; unsigned intr_unlink_cycle; unsigned now_frame; /* frame from HC hardware */ - unsigned next_frame; /* scan periodic, start here */ + unsigned last_iso_frame; /* last frame scanned for iso */ unsigned intr_count; /* intr activity count */ unsigned isoc_count; /* isoc activity count */ unsigned periodic_count; /* periodic activity count */ @@ -193,7 +193,6 @@ struct ehci_hcd { /* one per controller */ unsigned has_amcc_usb23:1; unsigned need_io_watchdog:1; unsigned amd_pll_fix:1; - unsigned fs_i_thresh:1; /* Intel iso scheduling */ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ @@ -207,7 +206,6 @@ struct ehci_hcd { /* one per controller */ #define OHCI_HCCTRL_LEN 0x4 __hc32 *ohci_hcctrl_reg; unsigned has_hostpc:1; - unsigned has_lpm:1; /* support link power management */ unsigned has_ppcd:1; /* support per-port change bits */ u8 sbrn; /* packed release number */ @@ -762,26 +760,42 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_PCI - -/* For working around the MosChip frame-index-register bug */ -static unsigned ehci_read_frame_index(struct ehci_hcd *ehci); - +#define ehci_dbg(ehci, fmt, args...) \ + dev_dbg(ehci_to_hcd(ehci)->self.controller , fmt , ## args) +#define ehci_err(ehci, fmt, args...) \ + dev_err(ehci_to_hcd(ehci)->self.controller , fmt , ## args) +#define ehci_info(ehci, fmt, args...) \ + dev_info(ehci_to_hcd(ehci)->self.controller , fmt , ## args) +#define ehci_warn(ehci, fmt, args...) \ + dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args) + +#ifdef VERBOSE_DEBUG +# define ehci_vdbg ehci_dbg #else - -static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) -{ - return ehci_readl(ehci, &ehci->regs->frame_index); -} - + static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {} #endif -/*-------------------------------------------------------------------------*/ - #ifndef DEBUG #define STUB_DEBUG_FILES #endif /* DEBUG */ /*-------------------------------------------------------------------------*/ +/* Declarations of things exported for use by ehci platform drivers */ + +struct ehci_driver_overrides { + const char *product_desc; + size_t extra_priv_size; + int (*reset)(struct usb_hcd *hcd); +}; + +extern void ehci_init_driver(struct hc_driver *drv, + const struct ehci_driver_overrides *over); +extern int ehci_setup(struct usb_hcd *hcd); + +#ifdef CONFIG_PM +extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup); +extern int ehci_resume(struct usb_hcd *hcd, bool hibernated); +#endif /* CONFIG_PM */ + #endif /* __LINUX_EHCI_HCD_H */ diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index fff114f..958379f 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -43,7 +43,6 @@ static int of_isp1760_probe(struct platform_device *dev) struct device_node *dp = dev->dev.of_node; struct resource *res; struct resource memory; - struct of_irq oirq; int virq; resource_size_t res_len; int ret; @@ -69,14 +68,12 @@ static int of_isp1760_probe(struct platform_device *dev) goto free_data; } - if (of_irq_map_one(dp, 0, &oirq)) { + virq = irq_of_parse_and_map(dp, 0); + if (!virq) { ret = -ENODEV; goto release_reg; } - virq = irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); - if (of_device_is_compatible(dp, "nxp,usb-isp1761")) devflags |= ISP1760_FLAG_ISP1761; diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 0bf72f9..908d84a 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -705,7 +705,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) if (!clocked) at91_start_clock(); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #else diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c deleted file mode 100644 index c611699..0000000 --- a/drivers/usb/host/ohci-au1xxx.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * - * Bus Glue for AMD Alchemy Au1xxx - * - * Written by Christopher Hoover <ch@hpl.hp.com> - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta <pattamattad@sharpsec.com> - * Modified for AMD Alchemy Au1xxx - * by Matt Porter <mporter@kernel.crashing.org> - * - * This file is licenced under the GPL. - */ - -#include <linux/platform_device.h> -#include <linux/signal.h> - -#include <asm/mach-au1x00/au1000.h> - - -extern int usb_disabled(void); - -static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ohci_dbg(ohci, "ohci_au1xxx_start, ohci:%p", ohci); - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - dev_err(hcd->self.controller, "can't start %s", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_au1xxx_hc_driver = { - .description = hcd_name, - .product_desc = "Au1xxx OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_au1xxx_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) -{ - int ret, unit; - struct usb_hcd *hcd; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd(&ohci_au1xxx_hc_driver, &pdev->dev, "au1xxx"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed\n"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed\n"); - ret = -ENOMEM; - goto err2; - } - - unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? - ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; - if (alchemy_usb_control(unit, 1)) { - printk(KERN_INFO "%s: controller init failed!\n", pdev->name); - ret = -ENODEV; - goto err3; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - - alchemy_usb_control(unit, 0); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - int unit; - - unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? - ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; - usb_remove_hcd(hcd); - alchemy_usb_control(unit, 0); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_au1xxx_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - unsigned long flags; - int rc; - - rc = 0; - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave(&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED) { - rc = -EINVAL; - goto bail; - } - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - (void)ohci_readl(ohci, &ohci->regs->intrdisable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); -bail: - spin_unlock_irqrestore(&ohci->lock, flags); - - return rc; -} - -static int ohci_hcd_au1xxx_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - alchemy_usb_control(ALCHEMY_USB_OHCI0, 1); - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - ohci_finish_controller_resume(hcd); - - return 0; -} - -static const struct dev_pm_ops au1xxx_ohci_pmops = { - .suspend = ohci_hcd_au1xxx_drv_suspend, - .resume = ohci_hcd_au1xxx_drv_resume, -}; - -#define AU1XXX_OHCI_PMOPS &au1xxx_ohci_pmops - -#else -#define AU1XXX_OHCI_PMOPS NULL -#endif - -static struct platform_driver ohci_hcd_au1xxx_driver = { - .probe = ohci_hcd_au1xxx_drv_probe, - .remove = ohci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "au1xxx-ohci", - .owner = THIS_MODULE, - .pm = AU1XXX_OHCI_PMOPS, - }, -}; - -MODULE_ALIAS("platform:au1xxx-ohci"); diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c deleted file mode 100644 index 2c9f233..0000000 --- a/drivers/usb/host/ohci-cns3xxx.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - */ - -#include <linux/platform_device.h> -#include <linux/atomic.h> -#include <mach/cns3xxx.h> -#include <mach/pm.h> - -static int __devinit -cns3xxx_ohci_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - * - * Set USB AHB INCR length to 16 - */ - if (atomic_inc_return(&usb_pwr_ref) == 1) { - cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); - cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); - __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), - MISC_CHIP_CONFIG_REG); - } - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ohci->num_ports = 1; - - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "can't start %s\n", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static const struct hc_driver cns3xxx_ohci_hc_driver = { - .description = hcd_name, - .product_desc = "CNS3XXX OHCI Host controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - .start = cns3xxx_ohci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int cns3xxx_ohci_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; - const struct hc_driver *driver = &cns3xxx_ohci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Found HC with no IRQ.\n"); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, dev, dev_name(dev)); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr.\n"); - retval = -ENODEV; - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(dev, "controller already in use\n"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_dbg(dev, "error mapping memory\n"); - retval = -EFAULT; - goto err2; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval == 0) - return retval; - - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return retval; -} - -static int cns3xxx_ohci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - */ - if (atomic_dec_return(&usb_pwr_ref) == 0) - cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -MODULE_ALIAS("platform:cns3xxx-ohci"); - -static struct platform_driver ohci_hcd_cns3xxx_driver = { - .probe = cns3xxx_ohci_probe, - .remove = cns3xxx_ohci_remove, - .driver = { - .name = "cns3xxx-ohci", - }, -}; diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index dbfbd1d..a982f04 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -194,7 +194,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) ep93xx_start_hc(&pdev->dev); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #endif diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 20a5008..6a30fc5 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -23,6 +23,11 @@ struct exynos_ohci_hcd { struct clk *clk; }; +static int ohci_exynos_reset(struct usb_hcd *hcd) +{ + return ohci_init(hcd_to_ohci(hcd)); +} + static int ohci_exynos_start(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); @@ -30,10 +35,6 @@ static int ohci_exynos_start(struct usb_hcd *hcd) ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); - ret = ohci_init(ohci); - if (ret < 0) - return ret; - ret = ohci_run(ohci); if (ret < 0) { dev_err(hcd->self.controller, "can't start %s\n", @@ -53,6 +54,7 @@ static const struct hc_driver exynos_ohci_hc_driver = { .irq = ohci_irq, .flags = HCD_MEMORY|HCD_USB11, + .reset = ohci_exynos_reset, .start = ohci_exynos_start, .stop = ohci_stop, .shutdown = ohci_shutdown, @@ -115,7 +117,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev) } exynos_ohci->hcd = hcd; - exynos_ohci->clk = clk_get(&pdev->dev, "usbhost"); + exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ohci->clk)) { dev_err(&pdev->dev, "Failed to get usbhost clock\n"); @@ -123,9 +125,9 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev) goto fail_clk; } - err = clk_enable(exynos_ohci->clk); + err = clk_prepare_enable(exynos_ohci->clk); if (err) - goto fail_clken; + goto fail_clk; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -167,9 +169,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev) return 0; fail_io: - clk_disable(exynos_ohci->clk); -fail_clken: - clk_put(exynos_ohci->clk); + clk_disable_unprepare(exynos_ohci->clk); fail_clk: usb_put_hcd(hcd); return err; @@ -186,8 +186,7 @@ static int __devexit exynos_ohci_remove(struct platform_device *pdev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(exynos_ohci->clk); - clk_put(exynos_ohci->clk); + clk_disable_unprepare(exynos_ohci->clk); usb_put_hcd(hcd); @@ -232,7 +231,7 @@ static int exynos_ohci_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(exynos_ohci->clk); + clk_disable_unprepare(exynos_ohci->clk); fail: spin_unlock_irqrestore(&ohci->lock, flags); @@ -247,15 +246,12 @@ static int exynos_ohci_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; - clk_enable(exynos_ohci->clk); + clk_prepare_enable(exynos_ohci->clk); if (pdata && pdata->phy_init) pdata->phy_init(pdev, S5P_USB_PHY_HOST); - /* Mark hardware accessible again as we are out of D3 state by now */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 4a1d64d..180a2b0 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -231,13 +231,41 @@ static int ohci_urb_enqueue ( frame &= ~(ed->interval - 1); frame |= ed->branch; urb->start_frame = frame; + } + } else if (ed->type == PIPE_ISOCHRONOUS) { + u16 next = ohci_frame_no(ohci) + 2; + u16 frame = ed->last_iso + ed->interval; + + /* Behind the scheduling threshold? */ + if (unlikely(tick_before(frame, next))) { - /* yes, only URB_ISO_ASAP is supported, and - * urb->start_frame is never used as input. + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + frame += (next - frame + ed->interval - 1) & + -ed->interval; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. */ + else if (tick_before(frame + ed->interval * + (urb->number_of_packets - 1), next)) { + retval = -EXDEV; + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } + + /* + * Some OHCI hardware doesn't handle late TDs + * correctly. After retiring them it proceeds to + * the next ED instead of the next TD. Therefore + * we have to omit the late TDs entirely. + */ + urb_priv->td_cnt = DIV_ROUND_UP(next - frame, + ed->interval); } - } else if (ed->type == PIPE_ISOCHRONOUS) - urb->start_frame = ed->last_iso + ed->interval; + urb->start_frame = frame; + } /* fill the TDs and link them to the ed; and * enable that part of the schedule, if needed @@ -983,6 +1011,79 @@ static int ohci_restart (struct ohci_hcd *ohci) #endif +#ifdef CONFIG_PM + +static int __maybe_unused ohci_suspend(struct usb_hcd *hcd, bool do_wakeup) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + unsigned long flags; + + /* Disable irq emission and mark HW unaccessible. Use + * the spinlock to properly synchronize with possible pending + * RH suspend or resume activity. + */ + spin_lock_irqsave (&ohci->lock, flags); + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + (void)ohci_readl(ohci, &ohci->regs->intrdisable); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore (&ohci->lock, flags); + + return 0; +} + + +static int __maybe_unused ohci_resume(struct usb_hcd *hcd, bool hibernated) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int port; + bool need_reinit = false; + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + /* Make sure resume from hibernation re-enumerates everything */ + if (hibernated) + ohci_usb_reset(ohci); + + /* See if the controller is already running or has been reset */ + ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { + need_reinit = true; + } else { + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + case OHCI_USB_RESET: + need_reinit = true; + } + } + + /* If needed, reinitialize and suspend the root hub */ + if (need_reinit) { + spin_lock_irq(&ohci->lock); + ohci_rh_resume(ohci); + ohci_rh_suspend(ohci, 0); + spin_unlock_irq(&ohci->lock); + } + + /* Normally just turn on port power and enable interrupts */ + else { + ohci_dbg(ohci, "powerup ports\n"); + for (port = 0; port < ohci->num_ports; port++) + ohci_writel(ohci, RH_PS_PPS, + &ohci->regs->roothub.portstatus[port]); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable); + ohci_readl(ohci, &ohci->regs->intrenable); + msleep(20); + } + + usb_hcd_resume_root_hub(hcd); + + return 0; +} + +#endif + /*-------------------------------------------------------------------------*/ MODULE_AUTHOR (DRIVER_AUTHOR); @@ -1029,21 +1130,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_ep93xx_driver #endif -#ifdef CONFIG_MIPS_ALCHEMY -#include "ohci-au1xxx.c" -#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver -#endif - -#ifdef CONFIG_PNX8550 -#include "ohci-pnx8550.c" -#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC -#include "ohci-ppc-soc.c" -#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver -#endif - #ifdef CONFIG_ARCH_AT91 #include "ohci-at91.c" #define PLATFORM_DRIVER ohci_hcd_at91_driver @@ -1059,11 +1145,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_da8xx_driver #endif -#ifdef CONFIG_USB_OHCI_SH -#include "ohci-sh.c" -#define PLATFORM_DRIVER ohci_hcd_sh_driver -#endif - #ifdef CONFIG_USB_OHCI_HCD_PPC_OF #include "ohci-ppc-of.c" @@ -1105,16 +1186,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_tilegx_driver #endif -#ifdef CONFIG_USB_CNS3XXX_OHCI -#include "ohci-cns3xxx.c" -#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver -#endif - -#ifdef CONFIG_CPU_XLR -#include "ohci-xls.c" -#define PLATFORM_DRIVER ohci_xls_driver -#endif - #ifdef CONFIG_USB_OHCI_HCD_PLATFORM #include "ohci-platform.c" #define PLATFORM_DRIVER ohci_platform_driver diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 2f3619e..db09dae 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -316,48 +316,6 @@ static int ohci_bus_resume (struct usb_hcd *hcd) return rc; } -/* Carry out the final steps of resuming the controller device */ -static void __maybe_unused ohci_finish_controller_resume(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int port; - bool need_reinit = false; - - /* See if the controller is already running or has been reset */ - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); - if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { - need_reinit = true; - } else { - switch (ohci->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - case OHCI_USB_RESET: - need_reinit = true; - } - } - - /* If needed, reinitialize and suspend the root hub */ - if (need_reinit) { - spin_lock_irq(&ohci->lock); - ohci_rh_resume(ohci); - ohci_rh_suspend(ohci, 0); - spin_unlock_irq(&ohci->lock); - } - - /* Normally just turn on port power and enable interrupts */ - else { - ohci_dbg(ohci, "powerup ports\n"); - for (port = 0; port < ohci->num_ports; port++) - ohci_writel(ohci, RH_PS_PPS, - &ohci->regs->roothub.portstatus[port]); - - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable); - ohci_readl(ohci, &ohci->regs->intrenable); - msleep(20); - } - - usb_hcd_resume_root_hub(hcd); -} - /* Carry out polling-, autostop-, and autoresume-related state changes */ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, int any_connected, int rhsc_status) diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 4531d03..733c77c 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -530,7 +530,7 @@ static int ohci_omap_resume(struct platform_device *dev) ohci->next_statechange = jiffies; omap_ohci_clock_power(1); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 1843bb6..6afa7dc 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -296,49 +296,6 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd) return ret; } -#ifdef CONFIG_PM - -static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - unsigned long flags; - int rc = 0; - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave (&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED) { - rc = -EINVAL; - goto bail; - } - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - (void)ohci_readl(ohci, &ohci->regs->intrdisable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - bail: - spin_unlock_irqrestore (&ohci->lock, flags); - - return rc; -} - - -static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated) -{ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - /* Make sure resume from hibernation re-enumerates everything */ - if (hibernated) - ohci_usb_reset(hcd_to_ohci(hcd)); - - ohci_finish_controller_resume(hcd); - return 0; -} - -#endif /* CONFIG_PM */ - /*-------------------------------------------------------------------------*/ @@ -362,8 +319,8 @@ static const struct hc_driver ohci_pci_hc_driver = { .shutdown = ohci_shutdown, #ifdef CONFIG_PM - .pci_suspend = ohci_pci_suspend, - .pci_resume = ohci_pci_resume, + .pci_suspend = ohci_suspend, + .pci_resume = ohci_resume, #endif /* diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index e24ec9f..bda4e0b 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -31,6 +31,10 @@ static int ohci_platform_reset(struct usb_hcd *hcd) ohci->flags |= OHCI_QUIRK_FRAME_NO; ohci_hcd_init(ohci); + + if (pdata->num_ports) + ohci->num_ports = pdata->num_ports; + err = ohci_init(ohci); return err; @@ -97,13 +101,13 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provided"); + dev_err(&dev->dev, "no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provided"); + dev_err(&dev->dev, "no memory resource provided"); return -ENXIO; } @@ -123,29 +127,19 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_err("controller already in use"); - err = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&dev->dev, res_mem); if (!hcd->regs) { err = -ENOMEM; - goto err_release_region; + goto err_put_hcd; } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_iounmap; + goto err_put_hcd; platform_set_drvdata(dev, hcd); return err; -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put_hcd: usb_put_hcd(hcd); err_power: @@ -161,8 +155,6 @@ static int __devexit ohci_platform_remove(struct platform_device *dev) struct usb_ohci_pdata *pdata = dev->dev.platform_data; usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(dev, NULL); @@ -199,7 +191,7 @@ static int ohci_platform_resume(struct device *dev) return err; } - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c deleted file mode 100644 index 148d27d..0000000 --- a/drivers/usb/host/ohci-pnx8550.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2005 Embedded Alley Solutions, Inc. - * - * Bus Glue for PNX8550 - * - * Written by Christopher Hoover <ch@hpl.hp.com> - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta <pattamattad@sharpsec.com> - * - * Modified for PNX8550 from ohci-sa1111.c and sa-omap.c - * by Vitaly Wool <vitalywool@gmail.com> - * - * This file is licenced under the GPL. - */ - -#include <linux/device.h> -#include <linux/platform_device.h> -#include <asm/mach-pnx8550/usb.h> -#include <asm/mach-pnx8550/int.h> -#include <asm/mach-pnx8550/pci.h> - -#ifndef CONFIG_PNX8550 -#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined." -#endif - -extern int usb_disabled(void); - -/*-------------------------------------------------------------------------*/ - -static void pnx8550_start_hc(struct platform_device *dev) -{ - /* - * Set register CLK48CTL to enable and 48MHz - */ - outl(0x00000003, PCI_BASE | 0x0004770c); - - /* - * Set register CLK12CTL to enable and 48MHz - */ - outl(0x00000003, PCI_BASE | 0x00047710); - - udelay(100); -} - -static void pnx8550_stop_hc(struct platform_device *dev) -{ - udelay(10); -} - - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - - -/** - * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - */ -int usb_hcd_pnx8550_probe (const struct hc_driver *driver, - struct platform_device *dev) -{ - int retval; - struct usb_hcd *hcd; - - if (dev->resource[0].flags != IORESOURCE_MEM || - dev->resource[1].flags != IORESOURCE_IRQ) { - dev_err (&dev->dev,"invalid resource type\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd (driver, &dev->dev, "pnx8550"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = dev->resource[0].start; - hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_err(&dev->dev, "request_mem_region [0x%08llx, 0x%08llx] " - "failed\n", hcd->rsrc_start, hcd->rsrc_len); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&dev->dev, "ioremap [[0x%08llx, 0x%08llx] failed\n", - hcd->rsrc_start, hcd->rsrc_len); - retval = -ENOMEM; - goto err2; - } - - pnx8550_start_hc(dev); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, dev->resource[1].start, 0); - if (retval == 0) - return retval; - - pnx8550_stop_hc(dev); - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_pnx8550_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev) -{ - usb_remove_hcd(hcd); - pnx8550_stop_hc(dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit -ohci_pnx8550_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci); - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run (ohci)) < 0) { - dev_err(hcd->self.controller, "can't start %s", - hcd->self.bus_name); - ohci_stop (hcd); - return ret; - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_pnx8550_hc_driver = { - .description = hcd_name, - .product_desc = "PNX8550 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_pnx8550_start, - .stop = ohci_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_pnx8550_drv_probe(struct platform_device *pdev) -{ - int ret; - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev); - return ret; -} - -static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_pnx8550_remove(hcd, pdev); - return 0; -} - -MODULE_ALIAS("platform:pnx8550-ohci"); - -static struct platform_driver ohci_hcd_pnx8550_driver = { - .driver = { - .name = "pnx8550-ohci", - .owner = THIS_MODULE, - }, - .probe = ohci_hcd_pnx8550_drv_probe, - .remove = ohci_hcd_pnx8550_drv_remove, -}; - diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c deleted file mode 100644 index 185c39e..0000000 --- a/drivers/usb/host/ohci-ppc-soc.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2003-2005 MontaVista Software Inc. - * - * Bus Glue for PPC On-Chip OHCI driver - * Tested on Freescale MPC5200 and IBM STB04xxx - * - * Modified by Dale Farnsworth <dale@farnsworth.org> from ohci-sa1111.c - * - * This file is licenced under the GPL. - */ - -#include <linux/platform_device.h> -#include <linux/signal.h> - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller. - * - * Store this function in the HCD's struct pci_driver as probe(). - */ -static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval; - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - struct resource *res; - int irq; - - pr_debug("initializing PPC-SOC USB Controller\n"); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - pr_debug("%s: no irq\n", __FILE__); - return -ENODEV; - } - irq = res->start; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - pr_debug("%s: no reg addr\n", __FILE__); - return -ENODEV; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "PPC-SOC USB"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("%s: request_mem_region failed\n", __FILE__); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("%s: ioremap failed\n", __FILE__); - retval = -ENOMEM; - goto err2; - } - - ohci = hcd_to_ohci(hcd); - ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; - -#ifdef CONFIG_PPC_MPC52xx - /* MPC52xx doesn't need frame_no shift */ - ohci->flags |= OHCI_QUIRK_FRAME_NO; -#endif - ohci_hcd_init(ohci); - - retval = usb_add_hcd(hcd, irq, 0); - if (retval == 0) - return retval; - - pr_debug("Removing PPC-SOC USB Controller\n"); - - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_ppc_soc_remove - shutdown processing for On-Chip HCDs - * @pdev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_ppc_soc_probe(). - * It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - - pr_debug("stopping PPC-SOC USB Controller\n"); - - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -static int __devinit -ohci_ppc_soc_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - dev_err(hcd->self.controller, "can't start %s\n", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_ppc_soc_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_ppc_soc_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) -{ - int ret; - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_ppc_soc_probe(&ohci_ppc_soc_hc_driver, pdev); - return ret; -} - -static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_ppc_soc_remove(hcd, pdev); - return 0; -} - -static struct platform_driver ohci_hcd_ppc_soc_driver = { - .probe = ohci_hcd_ppc_soc_drv_probe, - .remove = ohci_hcd_ppc_soc_drv_remove, - .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM - /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ - /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ -#endif - .driver = { - .name = "ppc-soc-ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:ppc-soc-ohci"); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 2bf1144..156d289 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -591,7 +591,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct device *dev) /* Select Power Management Mode */ pxa27x_ohci_select_pmm(ohci, inf->port_mode); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index c5a1ea9..177a213 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -596,7 +596,6 @@ static void td_submit_urb ( urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C); } - urb_priv->td_cnt = 0; list_add (&urb_priv->pending, &ohci->pending); if (data_len) @@ -672,7 +671,8 @@ static void td_submit_urb ( * we could often reduce the number of TDs here. */ case PIPE_ISOCHRONOUS: - for (cnt = 0; cnt < urb->number_of_packets; cnt++) { + for (cnt = urb_priv->td_cnt; cnt < urb->number_of_packets; + cnt++) { int frame = urb->start_frame; // FIXME scheduling should handle frame counter diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 0d2309c..e84190f 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -323,8 +323,6 @@ usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev) { usb_remove_hcd(hcd); s3c2410_stop_hc(dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); } @@ -353,35 +351,29 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, hcd->rsrc_start = dev->resource[0].start; hcd->rsrc_len = resource_size(&dev->resource[0]); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_err(&dev->dev, "request_mem_region failed\n"); - retval = -EBUSY; + hcd->regs = devm_request_and_ioremap(&dev->dev, &dev->resource[0]); + if (!hcd->regs) { + dev_err(&dev->dev, "devm_request_and_ioremap failed\n"); + retval = -ENOMEM; goto err_put; } - clk = clk_get(&dev->dev, "usb-host"); + clk = devm_clk_get(&dev->dev, "usb-host"); if (IS_ERR(clk)) { dev_err(&dev->dev, "cannot get usb-host clock\n"); retval = PTR_ERR(clk); - goto err_mem; + goto err_put; } - usb_clk = clk_get(&dev->dev, "usb-bus-host"); + usb_clk = devm_clk_get(&dev->dev, "usb-bus-host"); if (IS_ERR(usb_clk)) { dev_err(&dev->dev, "cannot get usb-bus-host clock\n"); retval = PTR_ERR(usb_clk); - goto err_clk; + goto err_put; } s3c2410_start_hc(dev, hcd); - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&dev->dev, "ioremap failed\n"); - retval = -ENOMEM; - goto err_ioremap; - } - ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, dev->resource[1].start, 0); @@ -392,14 +384,6 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, err_ioremap: s3c2410_stop_hc(dev); - iounmap(hcd->regs); - clk_put(usb_clk); - - err_clk: - clk_put(clk); - - err_mem: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put: usb_put_hcd(hcd); @@ -524,8 +508,7 @@ static int ohci_hcd_s3c2410_drv_resume(struct device *dev) s3c2410_start_hc(pdev, hcd); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c deleted file mode 100644 index 76a20c2..0000000 --- a/drivers/usb/host/ohci-sh.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * Copyright (C) 2008 Renesas Solutions Corp. - * - * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include <linux/platform_device.h> - -static int ohci_sh_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci_hcd_init(ohci); - ohci_init(ohci); - ohci_run(ohci); - return 0; -} - -static const struct hc_driver ohci_sh_hc_driver = { - .description = hcd_name, - .product_desc = "SuperH OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_sh_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_sh_probe(struct platform_device *pdev) -{ - struct resource *res = NULL; - struct usb_hcd *hcd = NULL; - int irq = -1; - int ret; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "platform_get_resource error.\n"); - return -ENODEV; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "platform_get_irq error.\n"); - return -ENODEV; - } - - /* initialize hcd */ - hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name); - if (!hcd) { - dev_err(&pdev->dev, "Failed to create hcd\n"); - return -ENOMEM; - } - - hcd->regs = (void __iomem *)res->start; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to add hcd\n"); - usb_put_hcd(hcd); - return ret; - } - - return ret; -} - -static int ohci_hcd_sh_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ohci_hcd_sh_driver = { - .probe = ohci_hcd_sh_probe, - .remove = ohci_hcd_sh_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "sh_ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:sh_ohci"); diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 5596ac2..3b5b908 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -238,7 +238,7 @@ static int ohci_sm501_resume(struct platform_device *pdev) ohci->next_statechange = jiffies; sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #else diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index fc7305e..d607be3 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -231,7 +231,7 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev) ohci->next_statechange = jiffies; spear_start_ohci(ohci_p); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #endif diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index 60c2b07..2c9ab8f 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -352,7 +352,7 @@ static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) spin_unlock_irqrestore(&tmio->lock, flags); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c deleted file mode 100644 index 84201cd..0000000 --- a/drivers/usb/host/ohci-xls.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * OHCI HCD for Netlogic XLS processors. - * - * (C) Copyright 2011 Netlogic Microsystems Inc. - * - * Based on ohci-au1xxx.c, and other Linux OHCI drivers. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/platform_device.h> -#include <linux/signal.h> - -static int ohci_xls_probe_internal(const struct hc_driver *driver, - struct platform_device *dev) -{ - struct resource *res; - struct usb_hcd *hcd; - int retval, irq; - - /* Get our IRQ from an earlier registered Platform Resource */ - irq = platform_get_irq(dev, 0); - if (irq < 0) { - dev_err(&dev->dev, "Found HC with no IRQ\n"); - return -ENODEV; - } - - /* Get our Memory Handle */ - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&dev->dev, "MMIO Handle incorrect!\n"); - return -ENODEV; - } - - hcd = usb_create_hcd(driver, &dev->dev, "XLS"); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&dev->dev, "Controller already in use\n"); - retval = -EBUSY; - goto err2; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&dev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval != 0) - goto err4; - return retval; - -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - dev_err(&dev->dev, "init fail, %d\n", retval); - return retval; -} - -static int ohci_xls_reset(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci_hcd_init(ohci); - return ohci_init(ohci); -} - -static int __devinit ohci_xls_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci; - int ret; - - ohci = hcd_to_ohci(hcd); - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "can't start %s\n", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static struct hc_driver ohci_xls_hc_driver = { - .description = hcd_name, - .product_desc = "XLS OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - .reset = ohci_xls_reset, - .start = ohci_xls_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_xls_probe(struct platform_device *dev) -{ - int ret; - - pr_debug("In ohci_xls_probe"); - if (usb_disabled()) - return -ENODEV; - ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev); - return ret; -} - -static int ohci_xls_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - return 0; -} - -static struct platform_driver ohci_xls_driver = { - .probe = ohci_xls_probe, - .remove = ohci_xls_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ohci-xls-0", - .owner = THIS_MODULE, - }, -}; diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 966d148..39f9e4a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -545,7 +545,14 @@ static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = { /* Pegatron Lucid (Ordissimo AIRIS) */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "M11JB"), - DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"), + DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), + }, + }, + { + /* Pegatron Lucid (Ordissimo) */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "Ordissimo"), + DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), }, }, { } diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fcc09e5..b3eea0b 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2036,10 +2036,8 @@ static void collect_usb_address_map(struct usb_device *udev, unsigned long *map) udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB) map[udev->devnum/32] |= (1 << (udev->devnum % 32)); - usb_hub_for_each_child(udev, chix, childdev) { - if (childdev) - collect_usb_address_map(childdev, map); - } + usb_hub_for_each_child(udev, chix, childdev) + collect_usb_address_map(childdev, map); } /* this function must be called with interrupt disabled */ diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index e478049..68ebf20 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -60,6 +60,7 @@ static const struct hc_driver uhci_platform_hc_driver = { .hub_control = uhci_hub_control, }; +static u64 platform_uhci_dma_mask = DMA_BIT_MASK(32); static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev) { @@ -71,6 +72,14 @@ static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &platform_uhci_dma_mask; + hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, pdev->name); if (!hcd) diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index d2c6f5a..15921fd 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1256,7 +1256,8 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, struct uhci_qh *qh) { struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ - int i, frame; + int i; + unsigned frame, next; unsigned long destination, status; struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; @@ -1265,37 +1266,29 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, urb->number_of_packets >= UHCI_NUMFRAMES) return -EFBIG; + uhci_get_current_frame_number(uhci); + /* Check the period and figure out the starting frame number */ if (!qh->bandwidth_reserved) { qh->period = urb->interval; - if (urb->transfer_flags & URB_ISO_ASAP) { - qh->phase = -1; /* Find the best phase */ - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - - /* Allow a little time to allocate the TDs */ - uhci_get_current_frame_number(uhci); - frame = uhci->frame_number + 10; - - /* Move forward to the first frame having the - * correct phase */ - urb->start_frame = frame + ((qh->phase - frame) & - (qh->period - 1)); - } else { - i = urb->start_frame - uhci->last_iso_frame; - if (i <= 0 || i >= UHCI_NUMFRAMES) - return -EINVAL; - qh->phase = urb->start_frame & (qh->period - 1); - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - } + qh->phase = -1; /* Find the best phase */ + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; + + /* Allow a little time to allocate the TDs */ + next = uhci->frame_number + 10; + frame = qh->phase; + + /* Round up to the first available slot */ + frame += (next - frame + qh->period - 1) & -qh->period; } else if (qh->period != urb->interval) { return -EINVAL; /* Can't change the period */ } else { + next = uhci->frame_number + 2; + /* Find the next unused frame */ if (list_empty(&qh->queue)) { frame = qh->iso_frame; @@ -1308,25 +1301,31 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, lurb->number_of_packets * lurb->interval; } - if (urb->transfer_flags & URB_ISO_ASAP) { - /* Skip some frames if necessary to insure - * the start frame is in the future. + + /* Fell behind? */ + if (uhci_frame_before_eq(frame, next)) { + + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + frame += (next - frame + qh->period - 1) & + -qh->period; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. */ - uhci_get_current_frame_number(uhci); - if (uhci_frame_before_eq(frame, uhci->frame_number)) { - frame = uhci->frame_number + 1; - frame += ((qh->phase - frame) & - (qh->period - 1)); - } - } /* Otherwise pick up where the last URB leaves off */ - urb->start_frame = frame; + else if (!uhci_frame_before_eq(next, + frame + (urb->number_of_packets - 1) * + qh->period)) + return -EXDEV; + } } /* Make sure we won't have to go too far into the future */ if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES, - urb->start_frame + urb->number_of_packets * - urb->interval)) + frame + urb->number_of_packets * urb->interval)) return -EFBIG; + urb->start_frame = frame; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 4b436f5..5f3a7c7 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -544,7 +544,6 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, int i; /* Fields are 32 bits wide, DMA addresses are in bytes */ int field_size = 32 / 8; - struct xhci_slot_ctx *slot_ctx; dma_addr_t dma = ctx->dma; int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); @@ -570,7 +569,6 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma); } - slot_ctx = xhci_get_slot_ctx(xhci, ctx); xhci_dbg_slot_ctx(xhci, ctx); xhci_dbg_ep_ctx(xhci, ctx, last_ep); } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index aa90ad4..a686cf4 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -151,9 +151,8 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, if (portsc & PORT_DEV_REMOVE) port_removable |= 1 << (i + 1); } - memset(&desc->u.ss.DeviceRemovable, - (__force __u16) cpu_to_le16(port_removable), - sizeof(__u16)); + + desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable); } static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, @@ -809,11 +808,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); + spin_unlock_irqrestore(&xhci->lock, flags); temp = usb_acpi_power_manageable(hcd->self.root_hub, wIndex); if (temp) usb_acpi_set_power_state(hcd->self.root_hub, wIndex, true); + spin_lock_irqsave(&xhci->lock, flags); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); @@ -917,11 +918,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_writel(xhci, temp & ~PORT_POWER, port_array[wIndex]); + spin_unlock_irqrestore(&xhci->lock, flags); temp = usb_acpi_power_manageable(hcd->self.root_hub, wIndex); if (temp) usb_acpi_set_power_state(hcd->self.root_hub, wIndex, false); + spin_lock_irqsave(&xhci->lock, flags); break; default: goto error; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c6ebb17..4e1a894 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1228,6 +1228,17 @@ static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd) cur_seg = find_trb_seg(xhci->cmd_ring->first_seg, xhci->cmd_ring->dequeue, &cycle_state); + if (!cur_seg) { + xhci_warn(xhci, "Command ring mismatch, dequeue = %p %llx (dma)\n", + xhci->cmd_ring->dequeue, + (unsigned long long) + xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, + xhci->cmd_ring->dequeue)); + xhci_debug_ring(xhci, xhci->cmd_ring); + xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); + return; + } + /* find the command trb matched by cd from command ring */ for (cmd_trb = xhci->cmd_ring->dequeue; cmd_trb != xhci->cmd_ring->enqueue; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8d7fcbb..c9e419f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -479,7 +479,8 @@ static bool compliance_mode_recovery_timer_quirk_check(void) if (strstr(dmi_product_name, "Z420") || strstr(dmi_product_name, "Z620") || - strstr(dmi_product_name, "Z820")) + strstr(dmi_product_name, "Z820") || + strstr(dmi_product_name, "Z1")) return true; return false; @@ -1626,7 +1627,6 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct xhci_hcd *xhci; struct xhci_container_ctx *in_ctx, *out_ctx; unsigned int ep_index; - struct xhci_ep_ctx *ep_ctx; struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; u32 added_ctxs; @@ -1662,7 +1662,6 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, out_ctx = virt_dev->out_ctx; ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); /* If this endpoint is already in use, and the upper layers are trying * to add it again without dropping it, reject the addition. @@ -1816,6 +1815,8 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, case COMP_EBADSLT: dev_warn(&udev->dev, "WARN: slot not enabled for" "evaluate context command.\n"); + ret = -EINVAL; + break; case COMP_CTX_STATE: dev_warn(&udev->dev, "WARN: invalid context state for " "evaluate context command.\n"); @@ -4020,7 +4021,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) static unsigned long long xhci_service_interval_to_ns( struct usb_endpoint_descriptor *desc) { - return (1 << (desc->bInterval - 1)) * 125 * 1000; + return (1ULL << (desc->bInterval - 1)) * 125 * 1000; } static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, @@ -4141,7 +4142,7 @@ static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev, (xhci_service_interval_to_ns(desc) > timeout_ns)) timeout_ns = xhci_service_interval_to_ns(desc); - u2_del_ns = udev->bos->ss_cap->bU2DevExitLat * 1000; + u2_del_ns = le16_to_cpu(udev->bos->ss_cap->bU2DevExitLat) * 1000ULL; if (u2_del_ns > timeout_ns) timeout_ns = u2_del_ns; |