diff options
Diffstat (limited to 'drivers/usb/host')
111 files changed, 22241 insertions, 6069 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 344d5e2f87d..03314f861be 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -17,7 +17,6 @@ config USB_C67X00_HCD config USB_XHCI_HCD tristate "xHCI HCD (USB 3.0) support" - depends on USB_ARCH_HAS_XHCI ---help--- The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 "SuperSpeed" host controller hardware. @@ -30,20 +29,18 @@ if USB_XHCI_HCD config USB_XHCI_PLATFORM tristate -config USB_XHCI_HCD_DEBUGGING - bool "Debugging for the xHCI host controller" +config USB_XHCI_MVEBU + tristate "xHCI support for Marvell Armada 375/38x" + select USB_XHCI_PLATFORM + depends on ARCH_MVEBU || COMPILE_TEST ---help--- - Say 'Y' to turn on debugging for the xHCI host controller driver. - This will spew debugging output, even in interrupt context. - This should only be used for debugging xHCI driver bugs. - - If unsure, say N. + Say 'Y' to enable the support for the xHCI host controller + found in Marvell Armada 375/38x ARM SOCs. endif # USB_XHCI_HCD config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" - depends on USB_ARCH_HAS_EHCI ---help--- The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. @@ -65,7 +62,7 @@ config USB_EHCI_HCD config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators" - depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST + depends on USB_EHCI_HCD ---help--- Some EHCI chips have vendor-specific extensions to integrate transaction translators, so that no OHCI or UHCI companion @@ -77,7 +74,7 @@ config USB_EHCI_ROOT_HUB_TT config USB_EHCI_TT_NEWSCHED bool "Improved Transaction Translator scheduling" - depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST + depends on USB_EHCI_HCD default y ---help--- This changes the periodic scheduling code to fill more of the low @@ -115,12 +112,6 @@ config USB_EHCI_HCD_PMC_MSP Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's. If unsure, say N. -config USB_EHCI_BIG_ENDIAN_MMIO - bool - -config USB_EHCI_BIG_ENDIAN_DESC - bool - config XPS_USB_HCD_XILINX bool "Use Xilinx usb host EHCI controller core" depends on (PPC32 || MICROBLAZE) @@ -150,13 +141,11 @@ config USB_EHCI_MXC config USB_EHCI_HCD_OMAP tristate "EHCI support for OMAP3 and later chips" depends on ARCH_OMAP + select NOP_USB_XCEIV default y ---help--- Enables support for the on-chip EHCI controller on OMAP3 and later chips. - If your system uses a PHY on the USB port, you will need to - enable USB_PHY and the appropriate PHY driver as well. Most - boards need the NOP_USB_XCEIV PHY driver. config USB_EHCI_HCD_ORION tristate "Support for Marvell EBU on-chip EHCI USB controller" @@ -187,10 +176,8 @@ config USB_EHCI_HCD_AT91 config USB_EHCI_MSM tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" - depends on ARCH_MSM - depends on USB_PHY + depends on ARCH_MSM || ARCH_QCOM select USB_EHCI_ROOT_HUB_TT - select USB_MSM_OTG ---help--- Enables support for the USB Host controller present on the Qualcomm chipsets. Root Hub has inbuilt TT. @@ -200,7 +187,7 @@ config USB_EHCI_MSM has an external PHY. config USB_EHCI_TEGRA - boolean "NVIDIA Tegra HCD support" + tristate "NVIDIA Tegra HCD support" depends on ARCH_TEGRA select USB_EHCI_ROOT_HUB_TT select USB_PHY @@ -223,12 +210,11 @@ config USB_EHCI_SH Enables support for the on-chip EHCI controller on the SuperH. If you use the PCI EHCI controller, this option is not necessary. -config USB_EHCI_S5P +config USB_EHCI_EXYNOS tristate "EHCI support for Samsung S5P/EXYNOS SoC Series" - depends on PLAT_S5P + depends on PLAT_S5P || ARCH_EXYNOS help - Enable support for the Samsung S5Pxxxx and Exynos3/4/5 SOC's - on-chip EHCI controller. + Enable support for the Samsung Exynos SOC's on-chip EHCI controller. config USB_EHCI_MV bool "EHCI support for Marvell PXA/MMP USB controller" @@ -244,7 +230,7 @@ config USB_EHCI_MV on-chip EHCI USB controller" for those. config USB_W90X900_EHCI - bool "W90X900(W90P910) EHCI support" + tristate "W90X900(W90P910) EHCI support" depends on ARCH_W90X900 ---help--- Enables support for the W90X900 USB controller @@ -285,7 +271,7 @@ config USB_EHCI_HCD_PLATFORM config USB_OCTEON_EHCI bool "Octeon on-chip EHCI support" - depends on CPU_CAVIUM_OCTEON + depends on CAVIUM_OCTEON_SOC default n select USB_EHCI_BIG_ENDIAN_MMIO help @@ -298,7 +284,6 @@ endif # USB_EHCI_HCD config USB_OXU210HP_HCD tristate "OXU210HP HCD support" - depends on GENERIC_HARDIRQS ---help--- The OXU210HP is an USB host/OTG/device controller. Enable this option if your board has this chip. If unsure, say N. @@ -336,7 +321,6 @@ config USB_ISP1760_HCD config USB_ISP1362_HCD tristate "ISP1362 HCD support" - default N ---help--- Supports the Philips ISP1362 chip as a host controller @@ -345,11 +329,40 @@ config USB_ISP1362_HCD To compile this driver as a module, choose M here: the module will be called isp1362-hcd. +config USB_FUSBH200_HCD + tristate "FUSBH200 HCD support" + depends on USB + ---help--- + Faraday FUSBH200 is designed to meet USB2.0 EHCI specification + with minor modification. + + To compile this driver as a module, choose M here: the + module will be called fusbh200-hcd. + +config USB_FOTG210_HCD + tristate "FOTG210 HCD support" + depends on USB + ---help--- + Faraday FOTG210 is an OTG controller which can be configured as + an USB2.0 host. It is designed to meet USB2.0 EHCI specification + with minor modification. + + To compile this driver as a module, choose M here: the + module will be called fotg210-hcd. + +config USB_MAX3421_HCD + tristate "MAX3421 HCD (USB-over-SPI) support" + depends on USB && SPI + ---help--- + The Maxim MAX3421E chip supports standard USB 2.0-compliant + full-speed devices either in host or peripheral mode. This + driver supports the host-mode of the MAX3421E only. + + To compile this driver as a module, choose M here: the module will + be called max3421-hcd. + config USB_OHCI_HCD - tristate "OHCI HCD support" - depends on USB_ARCH_HAS_OHCI - select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 - depends on USB_ISP1301 || !ARCH_LPC32XX + tristate "OHCI HCD (USB 1.1) support" ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's @@ -366,20 +379,72 @@ config USB_OHCI_HCD if USB_OHCI_HCD config USB_OHCI_HCD_OMAP1 - bool "OHCI support for OMAP1/2 chips" + tristate "OHCI support for OMAP1/2 chips" depends on ARCH_OMAP1 + depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) default y ---help--- Enables support for the OHCI controller on OMAP1/2 chips. +config USB_OHCI_HCD_SPEAR + tristate "Support for ST SPEAr on-chip OHCI USB controller" + depends on USB_OHCI_HCD && PLAT_SPEAR + default y + ---help--- + Enables support for the on-chip OHCI controller on + ST SPEAr chips. + +config USB_OHCI_HCD_S3C2410 + tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" + depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX) + default y + ---help--- + Enables support for the on-chip OHCI controller on + S3C24xx/S3C64xx chips. + +config USB_OHCI_HCD_LPC32XX + tristate "Support for LPC on-chip OHCI USB controller" + depends on USB_OHCI_HCD && ARCH_LPC32XX + depends on USB_ISP1301 + default y + ---help--- + Enables support for the on-chip OHCI controller on + NXP chips. + +config USB_OHCI_HCD_PXA27X + tristate "Support for PXA27X/PXA3XX on-chip OHCI USB controller" + depends on USB_OHCI_HCD && (PXA27x || PXA3xx) + default y + ---help--- + Enables support for the on-chip OHCI controller on + PXA27x/PXA3xx chips. + +config USB_OHCI_HCD_AT91 + tristate "Support for Atmel on-chip OHCI USB controller" + depends on USB_OHCI_HCD && ARCH_AT91 + default y + ---help--- + Enables support for the on-chip OHCI controller on + Atmel chips. + config USB_OHCI_HCD_OMAP3 - bool "OHCI support for OMAP3 and later chips" + tristate "OHCI support for OMAP3 and later chips" depends on (ARCH_OMAP3 || ARCH_OMAP4) default y ---help--- Enables support for the on-chip OHCI controller on OMAP3 and later chips. +config USB_OHCI_HCD_DAVINCI + bool "OHCI support for TI DaVinci DA8xx" + depends on ARCH_DAVINCI_DA8XX + depends on USB_OHCI_HCD=y + default y + help + Enables support for the DaVinci DA8xx integrated OHCI + controller. This driver cannot currently be a loadable + module because it lacks a proper PHY abstraction. + config USB_OHCI_ATH79 bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)" depends on (SOC_AR71XX || SOC_AR724X) @@ -415,8 +480,8 @@ config USB_OHCI_HCD_PPC_OF default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE config USB_OHCI_HCD_PCI - bool "OHCI support for PCI-bus USB controllers" - depends on PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) + tristate "OHCI support for PCI-bus USB controllers" + depends on PCI default y select USB_OHCI_LITTLE_ENDIAN ---help--- @@ -453,8 +518,8 @@ config USB_OHCI_SH If you use the PCI OHCI controller, this option is not necessary. config USB_OHCI_EXYNOS - boolean "OHCI support for Samsung EXYNOS SoC Series" - depends on ARCH_EXYNOS + tristate "OHCI support for Samsung S5P/EXYNOS SoC Series" + depends on PLAT_S5P || ARCH_EXYNOS help Enable support for the Samsung Exynos SOC's on-chip OHCI controller. @@ -470,7 +535,7 @@ config USB_CNS3XXX_OHCI It is needed for low-speed USB 1.0 device support. config USB_OHCI_HCD_PLATFORM - bool "Generic OHCI driver for a platform device" + tristate "Generic OHCI driver for a platform device" default n ---help--- Adds an OHCI host driver for a generic platform device, which @@ -480,7 +545,7 @@ config USB_OHCI_HCD_PLATFORM config USB_OCTEON_OHCI bool "Octeon on-chip OHCI support" - depends on CPU_CAVIUM_OCTEON + depends on CAVIUM_OCTEON_SOC default USB_OCTEON_EHCI select USB_OHCI_BIG_ENDIAN_MMIO select USB_OHCI_LITTLE_ENDIAN @@ -489,20 +554,6 @@ config USB_OCTEON_OHCI controller. It is needed for low-speed USB 1.0 device support. All CN6XXX based chips with USB are supported. - -config USB_OHCI_BIG_ENDIAN_DESC - bool - default n - -config USB_OHCI_BIG_ENDIAN_MMIO - bool - default n - -config USB_OHCI_LITTLE_ENDIAN - bool - default n if STB03xxx || PPC_MPC52xx - default y - endif # USB_OHCI_HCD config USB_UHCI_HCD @@ -558,7 +609,6 @@ config FHCI_DEBUG config USB_U132_HCD tristate "Elan U132 Adapter Host Controller" depends on USB_FTDI_ELAN - default M help The U132 adapter is a USB to CardBus adapter specifically designed for PC cards that contain an OHCI host controller. Typical PC cards @@ -702,3 +752,20 @@ config USB_HCD_SSB for ehci and ohci. If unsure, say N. + +config USB_HCD_TEST_MODE + bool "HCD test mode support" + ---help--- + Say 'Y' to enable additional software test modes that may be + supported by the host controller drivers. + + One such test mode is the Embedded High-speed Host Electrical Test + (EHSET) for EHCI host controller hardware, specifically the "Single + Step Set Feature" test. Typically this will be enabled for On-the-Go + or embedded hosts that need to undergo USB-IF compliance testing with + the aid of special testing hardware. In the future, this may expand + to include other tests that require support from a HCD driver. + + This option is of interest only to developers who need to validate + their USB hardware designs. It is not needed for normal use. If + unsure, say N. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 4fb73c156d7..af89a903d97 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -2,7 +2,8 @@ # Makefile for USB Host Controller Drivers # -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG +# tell define_trace.h where to find the xhci trace header +CFLAGS_xhci-trace.o := -I$(src) isp1760-y := isp1760-hcd.o isp1760-if.o @@ -13,10 +14,14 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o xhci-hcd-y := xhci.o xhci-mem.o xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o +xhci-hcd-y += xhci-trace.o xhci-hcd-$(CONFIG_PCI) += xhci-pci.o ifneq ($(CONFIG_USB_XHCI_PLATFORM), ) xhci-hcd-y += xhci-plat.o +ifneq ($(CONFIG_USB_XHCI_MVEBU), ) + xhci-hcd-y += xhci-mvebu.o +endif endif obj-$(CONFIG_USB_WHCI_HCD) += whci/ @@ -30,14 +35,28 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o -obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o +obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o +obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o +obj-$(CONFIG_USB_W90X900_EHCI) += ehci-w90x900.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 + obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o +obj-$(CONFIG_USB_OHCI_HCD_PCI) += ohci-pci.o +obj-$(CONFIG_USB_OHCI_HCD_PLATFORM) += ohci-platform.o +obj-$(CONFIG_USB_OHCI_EXYNOS) += ohci-exynos.o +obj-$(CONFIG_USB_OHCI_HCD_OMAP1) += ohci-omap.o +obj-$(CONFIG_USB_OHCI_HCD_OMAP3) += ohci-omap3.o +obj-$(CONFIG_USB_OHCI_HCD_SPEAR) += ohci-spear.o +obj-$(CONFIG_USB_OHCI_HCD_AT91) += ohci-at91.o +obj-$(CONFIG_USB_OHCI_HCD_S3C2410) += ohci-s3c2410.o +obj-$(CONFIG_USB_OHCI_HCD_LPC32XX) += ohci-nxp.o +obj-$(CONFIG_USB_OHCI_HCD_PXA27X) += ohci-pxa27x.o + obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o @@ -52,3 +71,6 @@ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o +obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o +obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o +obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index df13d425e9c..205f4a33658 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -227,8 +227,7 @@ static int bcma_hcd_probe(struct bcma_device *dev) /* TODO: Probably need checks here; is the core connected? */ - if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || - dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) + if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL); diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 02f4611faa6..ec9f7b75d49 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -30,22 +30,28 @@ static const char hcd_name[] = "ehci-atmel"; static struct hc_driver __read_mostly ehci_atmel_hc_driver; /* interface and function clocks */ -static struct clk *iclk, *fclk; +static struct clk *iclk, *fclk, *uclk; static int clocked; /*-------------------------------------------------------------------------*/ static void atmel_start_clock(void) { - clk_enable(iclk); - clk_enable(fclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + clk_set_rate(uclk, 48000000); + clk_prepare_enable(uclk); + } + clk_prepare_enable(iclk); + clk_prepare_enable(fclk); clocked = 1; } static void atmel_stop_clock(void) { - clk_disable(fclk); - clk_disable(iclk); + clk_disable_unprepare(fclk); + clk_disable_unprepare(iclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_disable_unprepare(uclk); clocked = 0; } @@ -90,10 +96,9 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) * 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (retval) + goto fail_create_hcd; hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { @@ -130,6 +135,14 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) retval = -ENOENT; goto fail_request_resource; } + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + uclk = devm_clk_get(&pdev->dev, "usb_clk"); + if (IS_ERR(uclk)) { + dev_err(&pdev->dev, "failed to get uclk\n"); + retval = PTR_ERR(uclk); + goto fail_request_resource; + } + } ehci = hcd_to_ehci(hcd); /* registers start at offset 0x0 */ @@ -140,6 +153,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) goto fail_add_hcd; + device_wakeup_enable(hcd->self.controller); return retval; diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 5429d2645bb..524cbf26d99 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -18,7 +18,7 @@ /* this file is part of ehci-hcd.c */ -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG /* check the values in the HCSPARAMS register * (host controller _Structural_ parameters) @@ -62,7 +62,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} #endif -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG /* check the values in the HCCPARAMS register * (host controller _Capability_ parameters) @@ -101,7 +101,7 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {} #endif -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG static void __maybe_unused dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) @@ -301,7 +301,7 @@ static inline int __maybe_unused dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status) { return 0; } -#endif /* DEBUG */ +#endif /* CONFIG_DYNAMIC_DEBUG */ /* functions have the "wrong" filename when they're output... */ #define dbg_status(ehci, label, status) { \ @@ -334,9 +334,9 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } /* troubleshooting help: expose state in debugfs */ static int debug_async_open(struct inode *, struct file *); +static int debug_bandwidth_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_output(struct file*, char __user*, size_t, loff_t*); static int debug_close(struct inode *, struct file *); @@ -348,6 +348,13 @@ static const struct file_operations debug_async_fops = { .release = debug_close, .llseek = default_llseek, }; +static const struct file_operations debug_bandwidth_fops = { + .owner = THIS_MODULE, + .open = debug_bandwidth_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; static const struct file_operations debug_periodic_fops = { .owner = THIS_MODULE, .open = debug_periodic_open, @@ -380,7 +387,7 @@ struct debug_buffer { case QH_LOW_SPEED: tmp = 'l'; break; \ case QH_HIGH_SPEED: tmp = 'h'; break; \ default: tmp = '?'; break; \ - }; tmp; }) + } tmp; }) static inline char token_mark(struct ehci_hcd *ehci, __hc32 token) { @@ -526,6 +533,89 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf) return strlen(buf->output_buf); } +static ssize_t fill_bandwidth_buffer(struct debug_buffer *buf) +{ + struct ehci_hcd *ehci; + struct ehci_tt *tt; + struct ehci_per_sched *ps; + unsigned temp, size; + char *next; + unsigned i; + u8 *bw; + u16 *bf; + u8 budget[EHCI_BANDWIDTH_SIZE]; + + ehci = hcd_to_ehci(bus_to_hcd(buf->bus)); + next = buf->output_buf; + size = buf->alloc_size; + + *next = 0; + + spin_lock_irq(&ehci->lock); + + /* Dump the HS bandwidth table */ + temp = scnprintf(next, size, + "HS bandwidth allocation (us per microframe)\n"); + size -= temp; + next += temp; + for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) { + bw = &ehci->bandwidth[i]; + temp = scnprintf(next, size, + "%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n", + i, bw[0], bw[1], bw[2], bw[3], + bw[4], bw[5], bw[6], bw[7]); + size -= temp; + next += temp; + } + + /* Dump all the FS/LS tables */ + list_for_each_entry(tt, &ehci->tt_list, tt_list) { + temp = scnprintf(next, size, + "\nTT %s port %d FS/LS bandwidth allocation (us per frame)\n", + dev_name(&tt->usb_tt->hub->dev), + tt->tt_port + !!tt->usb_tt->multi); + size -= temp; + next += temp; + + bf = tt->bandwidth; + temp = scnprintf(next, size, + " %5u%5u%5u%5u%5u%5u%5u%5u\n", + bf[0], bf[1], bf[2], bf[3], + bf[4], bf[5], bf[6], bf[7]); + size -= temp; + next += temp; + + temp = scnprintf(next, size, + "FS/LS budget (us per microframe)\n"); + size -= temp; + next += temp; + compute_tt_budget(budget, tt); + for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) { + bw = &budget[i]; + temp = scnprintf(next, size, + "%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n", + i, bw[0], bw[1], bw[2], bw[3], + bw[4], bw[5], bw[6], bw[7]); + size -= temp; + next += temp; + } + list_for_each_entry(ps, &tt->ps_list, ps_list) { + temp = scnprintf(next, size, + "%s ep %02x: %4u @ %2u.%u+%u mask %04x\n", + dev_name(&ps->udev->dev), + ps->ep->desc.bEndpointAddress, + ps->tt_usecs, + ps->bw_phase, ps->phase_uf, + ps->bw_period, ps->cs_mask); + size -= temp; + next += temp; + } + } + spin_unlock_irq(&ehci->lock); + + return next - buf->output_buf; +} + #define DBG_SCHED_LIMIT 64 static ssize_t fill_periodic_buffer(struct debug_buffer *buf) { @@ -572,7 +662,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) case Q_TYPE_QH: hw = p.qh->hw; temp = scnprintf (next, size, " qh%d-%04x/%p", - p.qh->period, + p.qh->ps.period, hc32_to_cpup(ehci, &hw->hw_info2) /* uframe masks */ @@ -619,7 +709,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) speed_char (scratch), scratch & 0x007f, (scratch >> 8) & 0x000f, type, - p.qh->usecs, p.qh->c_usecs, + p.qh->ps.usecs, + p.qh->ps.c_usecs, temp, 0x7ff & (scratch >> 16)); @@ -646,7 +737,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) case Q_TYPE_SITD: temp = scnprintf (next, size, " sitd%d-%04x/%p", - p.sitd->stream->interval, + p.sitd->stream->ps.period, hc32_to_cpup(ehci, &p.sitd->hw_uframe) & 0x0000ffff, p.sitd); @@ -727,7 +818,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) #ifdef CONFIG_PCI /* EHCI 0.96 and later may have "extended capabilities" */ - if (hcd->self.controller->bus == &pci_bus_type) { + if (dev_is_pci(hcd->self.controller)) { struct pci_dev *pdev; u32 offset, cap, cap2; unsigned count = 256/4; @@ -919,6 +1010,7 @@ static int debug_close(struct inode *inode, struct file *file) return 0; } + static int debug_async_open(struct inode *inode, struct file *file) { file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); @@ -926,6 +1018,14 @@ static int debug_async_open(struct inode *inode, struct file *file) return file->private_data ? 0 : -ENOMEM; } +static int debug_bandwidth_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_bandwidth_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + static int debug_periodic_open(struct inode *inode, struct file *file) { struct debug_buffer *buf; @@ -958,6 +1058,10 @@ static inline void create_debug_files (struct ehci_hcd *ehci) &debug_async_fops)) goto file_error; + if (!debugfs_create_file("bandwidth", S_IRUGO, ehci->debug_dir, bus, + &debug_bandwidth_fops)) + goto file_error; + if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus, &debug_periodic_fops)) goto file_error; diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c new file mode 100644 index 00000000000..d1c76216350 --- /dev/null +++ b/drivers/usb/host/ehci-exynos.c @@ -0,0 +1,390 @@ +/* + * SAMSUNG EXYNOS USB HOST EHCI Controller + * + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Jingoo Han <jg1.han@samsung.com> + * Author: Joonyoung Shim <jy0922.shim@samsung.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; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/usb/phy.h> +#include <linux/usb/samsung_usb_phy.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include "ehci.h" + +#define DRIVER_DESC "EHCI EXYNOS driver" + +#define EHCI_INSNREG00(base) (base + 0x90) +#define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25) +#define EHCI_INSNREG00_ENA_INCR8 (0x1 << 24) +#define EHCI_INSNREG00_ENA_INCR4 (0x1 << 23) +#define EHCI_INSNREG00_ENA_INCRX_ALIGN (0x1 << 22) +#define EHCI_INSNREG00_ENABLE_DMA_BURST \ + (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \ + EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) + +static const char hcd_name[] = "ehci-exynos"; +static struct hc_driver __read_mostly exynos_ehci_hc_driver; + +#define PHY_NUMBER 3 + +struct exynos_ehci_hcd { + struct clk *clk; + struct usb_phy *phy; + struct usb_otg *otg; + struct phy *phy_g[PHY_NUMBER]; +}; + +#define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv) + +static int exynos_ehci_get_phy(struct device *dev, + struct exynos_ehci_hcd *exynos_ehci) +{ + struct device_node *child; + struct phy *phy; + int phy_number; + int ret = 0; + + exynos_ehci->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR(exynos_ehci->phy)) { + ret = PTR_ERR(exynos_ehci->phy); + if (ret != -ENXIO && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } else { + exynos_ehci->otg = exynos_ehci->phy->otg; + } + + for_each_available_child_of_node(dev->of_node, child) { + ret = of_property_read_u32(child, "reg", &phy_number); + if (ret) { + dev_err(dev, "Failed to parse device tree\n"); + of_node_put(child); + return ret; + } + + if (phy_number >= PHY_NUMBER) { + dev_err(dev, "Invalid number of PHYs\n"); + of_node_put(child); + return -EINVAL; + } + + phy = devm_of_phy_get(dev, child, 0); + of_node_put(child); + if (IS_ERR(phy)) { + ret = PTR_ERR(phy); + if (ret != -ENOSYS && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } + exynos_ehci->phy_g[phy_number] = phy; + } + + return ret; +} + +static int exynos_ehci_phy_enable(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + int i; + int ret = 0; + + if (!IS_ERR(exynos_ehci->phy)) + return usb_phy_init(exynos_ehci->phy); + + for (i = 0; ret == 0 && i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ehci->phy_g[i])) + ret = phy_power_on(exynos_ehci->phy_g[i]); + if (ret) + for (i--; i >= 0; i--) + if (!IS_ERR(exynos_ehci->phy_g[i])) + phy_power_off(exynos_ehci->phy_g[i]); + + return ret; +} + +static void exynos_ehci_phy_disable(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + int i; + + if (!IS_ERR(exynos_ehci->phy)) { + usb_phy_shutdown(exynos_ehci->phy); + return; + } + + for (i = 0; i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ehci->phy_g[i])) + phy_power_off(exynos_ehci->phy_g[i]); +} + +static void exynos_setup_vbus_gpio(struct device *dev) +{ + int err; + int gpio; + + if (!dev->of_node) + return; + + gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0); + if (!gpio_is_valid(gpio)) + return; + + err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, + "ehci_vbus_gpio"); + if (err) + dev_err(dev, "can't request ehci vbus gpio %d", gpio); +} + +static int exynos_ehci_probe(struct platform_device *pdev) +{ + struct exynos_ehci_hcd *exynos_ehci; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct resource *res; + int irq; + int err; + + /* + * 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 move to full device tree support this will vanish off. + */ + err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + return err; + + exynos_setup_vbus_gpio(&pdev->dev); + + hcd = usb_create_hcd(&exynos_ehci_hc_driver, + &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "Unable to create HCD\n"); + return -ENOMEM; + } + exynos_ehci = to_exynos_ehci(hcd); + + if (of_device_is_compatible(pdev->dev.of_node, + "samsung,exynos5440-ehci")) + goto skip_phy; + + err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci); + if (err) + goto fail_clk; + +skip_phy: + + exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); + + if (IS_ERR(exynos_ehci->clk)) { + dev_err(&pdev->dev, "Failed to get usbhost clock\n"); + err = PTR_ERR(exynos_ehci->clk); + goto fail_clk; + } + + err = clk_prepare_enable(exynos_ehci->clk); + if (err) + goto fail_clk; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get I/O memory\n"); + err = -ENXIO; + goto fail_io; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + err = PTR_ERR(hcd->regs); + goto fail_io; + } + + irq = platform_get_irq(pdev, 0); + if (!irq) { + dev_err(&pdev->dev, "Failed to get IRQ\n"); + err = -ENODEV; + goto fail_io; + } + + if (exynos_ehci->otg) + exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + + err = exynos_ehci_phy_enable(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "Failed to enable USB phy\n"); + goto fail_io; + } + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs; + + /* DMA burst Enable */ + writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); + + err = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (err) { + dev_err(&pdev->dev, "Failed to add USB HCD\n"); + goto fail_add_hcd; + } + device_wakeup_enable(hcd->self.controller); + + platform_set_drvdata(pdev, hcd); + + return 0; + +fail_add_hcd: + exynos_ehci_phy_disable(&pdev->dev); +fail_io: + clk_disable_unprepare(exynos_ehci->clk); +fail_clk: + usb_put_hcd(hcd); + return err; +} + +static int exynos_ehci_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + + usb_remove_hcd(hcd); + + if (exynos_ehci->otg) + exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + + exynos_ehci_phy_disable(&pdev->dev); + + clk_disable_unprepare(exynos_ehci->clk); + + usb_put_hcd(hcd); + + return 0; +} + +#ifdef CONFIG_PM +static int exynos_ehci_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + + bool do_wakeup = device_may_wakeup(dev); + int rc; + + rc = ehci_suspend(hcd, do_wakeup); + if (rc) + return rc; + + if (exynos_ehci->otg) + exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + + exynos_ehci_phy_disable(dev); + + clk_disable_unprepare(exynos_ehci->clk); + + return rc; +} + +static int exynos_ehci_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + int ret; + + clk_prepare_enable(exynos_ehci->clk); + + if (exynos_ehci->otg) + exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + + ret = exynos_ehci_phy_enable(dev); + if (ret) { + dev_err(dev, "Failed to enable USB phy\n"); + clk_disable_unprepare(exynos_ehci->clk); + return ret; + } + + /* DMA burst Enable */ + writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); + + ehci_resume(hcd, false); + return 0; +} +#else +#define exynos_ehci_suspend NULL +#define exynos_ehci_resume NULL +#endif + +static const struct dev_pm_ops exynos_ehci_pm_ops = { + .suspend = exynos_ehci_suspend, + .resume = exynos_ehci_resume, +}; + +#ifdef CONFIG_OF +static const struct of_device_id exynos_ehci_match[] = { + { .compatible = "samsung,exynos4210-ehci" }, + { .compatible = "samsung,exynos5440-ehci" }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_ehci_match); +#endif + +static struct platform_driver exynos_ehci_driver = { + .probe = exynos_ehci_probe, + .remove = exynos_ehci_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "exynos-ehci", + .owner = THIS_MODULE, + .pm = &exynos_ehci_pm_ops, + .of_match_table = of_match_ptr(exynos_ehci_match), + } +}; +static const struct ehci_driver_overrides exynos_overrides __initdata = { + .extra_priv_size = sizeof(struct exynos_ehci_hcd), +}; + +static int __init ehci_exynos_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ehci_init_driver(&exynos_ehci_hc_driver, &exynos_overrides); + return platform_driver_register(&exynos_ehci_driver); +} +module_init(ehci_exynos_init); + +static void __exit ehci_exynos_cleanup(void) +{ + platform_driver_unregister(&exynos_ehci_driver); +} +module_exit(ehci_exynos_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_ALIAS("platform:exynos-ehci"); +MODULE_AUTHOR("Jingoo Han"); +MODULE_AUTHOR("Joonyoung Shim"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 3be3df233a0..cf2734b532a 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -57,7 +57,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, pr_debug("initializing FSL-SOC USB Controller\n"); /* Need platform data for setup */ - pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data for %s.\n", dev_name(&pdev->dev)); @@ -102,19 +102,11 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, } 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; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); goto err2; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } pdata->regs = hcd->regs; @@ -126,18 +118,19 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, */ if (pdata->init && pdata->init(pdev)) { retval = -ENODEV; - goto err4; + goto err2; } /* Enable USB controller, 83xx or 8536 */ - if (pdata->have_sysif_regs) + if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); /* Don't need to set host mode here. It will be done by tdi_reset() */ retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval != 0) - goto err4; + goto err2; + device_wakeup_enable(hcd->self.controller); #ifdef CONFIG_USB_OTG if (pdata->operating_mode == FSL_USB2_DR_OTG) { @@ -152,21 +145,17 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, &ehci_to_hcd(ehci)->self); if (retval) { usb_put_phy(hcd->phy); - goto err4; + goto err2; } } else { dev_err(&pdev->dev, "can't find phy\n"); retval = -ENODEV; - goto err4; + goto err2; } } #endif return retval; - err4: - iounmap(hcd->regs); - err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err2: usb_put_hcd(hcd); err1: @@ -190,7 +179,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, static void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); if (!IS_ERR_OR_NULL(hcd->phy)) { otg_set_host(hcd->phy->otg, NULL); @@ -205,8 +194,6 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, */ if (pdata->exit) pdata->exit(pdev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); } @@ -218,7 +205,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; struct device *dev = hcd->self.controller; - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); if (pdata->controller_ver < 0) { dev_warn(hcd->self.controller, "Could not get controller version\n"); @@ -232,15 +219,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ + clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); setbits32(non_ehci + FSL_SOC_USB_CTRL, - ULPI_PHY_CLK_SEL); - /* - * Due to controller issue of PHY_CLK_VALID in ULPI - * mode, we set USB_CTRL_USB_EN before checking - * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work. - */ - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - UTMI_PHY_EN, USB_CTRL_USB_EN); + ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); } portsc |= PORT_PTS_ULPI; break; @@ -267,12 +248,14 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, break; } - if (pdata->have_sysif_regs && pdata->controller_ver && + if (pdata->have_sysif_regs && + pdata->controller_ver > FSL_USB_VER_1_6 && (phy_mode == FSL_USB2_PHY_ULPI)) { /* check PHY_CLK_VALID to get phy clk valid */ - if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & - PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { - printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n"); + if (!(spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & + PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0) || + in_be32(non_ehci + FSL_SOC_USB_PRICTRL))) { + dev_warn(hcd->self.controller, "USB PHY clock invalid\n"); return -EINVAL; } } @@ -291,7 +274,7 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) struct fsl_usb2_platform_data *pdata; void __iomem *non_ehci = hcd->regs; - pdata = hcd->self.controller->platform_data; + pdata = dev_get_platdata(hcd->self.controller); if (pdata->have_sysif_regs) { /* @@ -363,7 +346,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) struct device *dev; dev = hcd->self.controller; - pdata = hcd->self.controller->platform_data; + pdata = dev_get_platdata(hcd->self.controller); ehci->big_endian_desc = pdata->big_endian_desc; ehci->big_endian_mmio = pdata->big_endian_mmio; @@ -415,10 +398,10 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); u32 tmp; -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE); mode &= USBMODE_CM_MASK; tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */ @@ -484,7 +467,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); u32 tmp; dev_dbg(dev, "suspend=%d already_suspended=%d\n", @@ -669,7 +652,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, + .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, /* * basic lifecycle operations @@ -732,6 +715,7 @@ static struct platform_driver ehci_fsl_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "fsl-ehci", + .owner = THIS_MODULE, .pm = EHCI_FSL_PM_OPS, }, }; diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index 5d75de9729b..495b6fbcbcd 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -43,7 +43,7 @@ static const struct hc_driver ehci_grlib_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -113,7 +113,8 @@ static int ehci_hcd_grlib_probe(struct platform_device *op) irq = irq_of_parse_and_map(dn, 0); if (irq == NO_IRQ) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); + dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", + __FILE__); rv = -EBUSY; goto err_irq; } @@ -140,6 +141,7 @@ static int ehci_hcd_grlib_probe(struct platform_device *op) if (rv) goto err_ioremap; + device_wakeup_enable(hcd->self.controller); return 0; err_ioremap: @@ -153,9 +155,7 @@ err_irq: static int ehci_hcd_grlib_remove(struct platform_device *op) { - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - dev_set_drvdata(&op->dev, NULL); + struct usb_hcd *hcd = platform_get_drvdata(op); dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n"); @@ -169,15 +169,6 @@ static int ehci_hcd_grlib_remove(struct platform_device *op) } -static void ehci_hcd_grlib_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ehci_hcd_grlib_of_match[] = { { .name = "GAISLER_EHCI", @@ -193,7 +184,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match); static struct platform_driver ehci_grlib_driver = { .probe = ehci_hcd_grlib_probe, .remove = ehci_hcd_grlib_remove, - .shutdown = ehci_hcd_grlib_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "grlib-ehci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 246e124e6ac..81cda09b47e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -71,7 +71,6 @@ static const char hcd_name [] = "ehci_hcd"; -#undef VERBOSE_DEBUG #undef EHCI_URB_TRACE /* magic numbers that can affect system performance */ @@ -110,6 +109,9 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); #include "ehci.h" #include "pci-quirks.h" +static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE], + struct ehci_tt *tt); + /* * The MosChip MCS9990 controller updates its microframe counter * a little before the frame counter, and occasionally we will read @@ -139,7 +141,7 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ /* - * handshake - spin reading hc until handshake completes or fails + * ehci_handshake - spin reading hc until handshake completes or fails * @ptr: address of hc register to be read * @mask: bits to look at in result of read * @done: value of those bits when handshake succeeds @@ -155,8 +157,8 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, - u32 mask, u32 done, int usec) +int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec) { u32 result; @@ -172,6 +174,7 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, } while (usec > 0); return -ETIMEDOUT; } +EXPORT_SYMBOL_GPL(ehci_handshake); /* check TDI/ARC silicon is in host mode */ static int tdi_in_host_mode (struct ehci_hcd *ehci) @@ -212,7 +215,7 @@ static int ehci_halt (struct ehci_hcd *ehci) spin_unlock_irq(&ehci->lock); synchronize_irq(ehci_to_hcd(ehci)->irq); - return handshake(ehci, &ehci->regs->status, + return ehci_handshake(ehci, &ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); } @@ -251,7 +254,7 @@ static int ehci_reset (struct ehci_hcd *ehci) ehci_writel(ehci, command, &ehci->regs->command); ehci->rh_state = EHCI_RH_HALTED; ehci->next_statechange = jiffies; - retval = handshake (ehci, &ehci->regs->command, + retval = ehci_handshake(ehci, &ehci->regs->command, CMD_RESET, 0, 250 * 1000); if (ehci->has_hostpc) { @@ -286,7 +289,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /* wait for any schedule enables/disables to take effect */ temp = (ehci->command << 10) & (STS_ASS | STS_PSS); - handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125); + ehci_handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, + 16 * 125); /* then disable anything that's still active */ spin_lock_irq(&ehci->lock); @@ -295,7 +299,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci) spin_unlock_irq(&ehci->lock); /* hardware can take 16 microframes to turn off ... */ - handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125); + ehci_handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, + 16 * 125); } /*-------------------------------------------------------------------------*/ @@ -437,14 +442,6 @@ static void ehci_stop (struct usb_hcd *hcd) if (ehci->amd_pll_fix == 1) usb_amd_dev_put(); -#ifdef EHCI_STATS - ehci_dbg(ehci, "irq normal %ld err %ld iaa %ld (lost %ld)\n", - ehci->stats.normal, ehci->stats.error, ehci->stats.iaa, - ehci->stats.lost_iaa); - ehci_dbg (ehci, "complete %ld unlink %ld\n", - ehci->stats.complete, ehci->stats.unlink); -#endif - dbg_status (ehci, "ehci_stop completed", ehci_readl(ehci, &ehci->regs->status)); } @@ -484,10 +481,12 @@ static int ehci_init(struct usb_hcd *hcd) ehci->periodic_size = DEFAULT_I_TDPS; INIT_LIST_HEAD(&ehci->async_unlink); INIT_LIST_HEAD(&ehci->async_idle); + INIT_LIST_HEAD(&ehci->intr_unlink_wait); INIT_LIST_HEAD(&ehci->intr_unlink); INIT_LIST_HEAD(&ehci->intr_qh_list); INIT_LIST_HEAD(&ehci->cached_itd_list); INIT_LIST_HEAD(&ehci->cached_sitd_list); + INIT_LIST_HEAD(&ehci->tt_list); if (HCC_PGM_FRAMELISTLEN(hcc_params)) { /* periodic schedule size can be smaller than default */ @@ -686,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status, masked_status, pcd_status = 0, cmd; int bh; + unsigned long flags; - spin_lock (&ehci->lock); + /* + * For threadirqs option we use spin_lock_irqsave() variant to prevent + * deadlock with ehci hrtimer callback, because hrtimer callbacks run + * in interrupt context even when threadirqs is specified. We can go + * back to spin_lock() variant when hrtimer callbacks become threaded. + */ + spin_lock_irqsave(&ehci->lock, flags); status = ehci_readl(ehci, &ehci->regs->status); @@ -705,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* Shared IRQ? */ if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { - spin_unlock(&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); return IRQ_NONE; } @@ -714,13 +720,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) cmd = ehci_readl(ehci, &ehci->regs->command); bh = 0; -#ifdef VERBOSE_DEBUG - /* unrequested/ignored: Frame List Rollover */ - dbg_status (ehci, "irq", status); -#endif - - /* INT, ERR, and IAA interrupt rates can be throttled */ - /* normal [4.15.1.2] or error [4.15.1.1] completion */ if (likely ((status & (STS_INT|STS_ERR)) != 0)) { if (likely ((status & STS_ERR) == 0)) @@ -823,7 +822,7 @@ dead: if (bh) ehci_work (ehci); - spin_unlock (&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); if (pcd_status) usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; @@ -939,7 +938,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); unsigned long flags; - struct ehci_qh *qh, *tmp; + struct ehci_qh *qh; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ @@ -960,6 +959,7 @@ rescan: goto idle_timeout; /* BUG_ON(!list_empty(&stream->free_list)); */ + reserve_release_iso_bandwidth(ehci, stream, -1); kfree(stream); goto done; } @@ -969,17 +969,13 @@ rescan: qh->qh_state = QH_STATE_IDLE; switch (qh->qh_state) { case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - for (tmp = ehci->async->qh_next.qh; - tmp && tmp != qh; - tmp = tmp->qh_next.qh) - continue; - /* periodic qh self-unlinks on empty, and a COMPLETING qh - * may already be unlinked. - */ - if (tmp) + WARN_ON(!list_empty(&qh->qtd_list)); + if (usb_endpoint_type(&ep->desc) != USB_ENDPOINT_XFER_INT) start_unlink_async(ehci, qh); + else + start_unlink_intr(ehci, qh); /* FALL THROUGH */ + case QH_STATE_COMPLETING: /* already in unlinking */ case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: idle_timeout: @@ -990,6 +986,8 @@ idle_timeout: if (qh->clearing_tt) goto idle_timeout; if (list_empty (&qh->qtd_list)) { + if (qh->ps.bw_uperiod) + reserve_release_intr_bandwidth(ehci, qh, -1); qh_destroy(ehci, qh); break; } @@ -1030,7 +1028,6 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) * the toggle bit in the QH. */ if (qh) { - usb_settoggle(qh->dev, epnum, is_out, 0); if (!list_empty(&qh->qtd_list)) { WARN_ONCE(1, "clear_halt for a busy endpoint\n"); } else { @@ -1038,6 +1035,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) * while the QH is active. Unlink it now; * re-linking will call qh_refresh(). */ + usb_settoggle(qh->ps.udev, epnum, is_out, 0); qh->exception = 1; if (eptype == USB_ENDPOINT_XFER_BULK) start_unlink_async(ehci, qh); @@ -1056,6 +1054,19 @@ static int ehci_get_frame (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ +/* Device addition and removal */ + +static void ehci_remove_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + spin_lock_irq(&ehci->lock); + drop_tt(udev); + spin_unlock_irq(&ehci->lock); +} + +/*-------------------------------------------------------------------------*/ + #ifdef CONFIG_PM /* suspend/resume, section 4.3 */ @@ -1083,6 +1094,14 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irq(&ehci->lock); + synchronize_irq(hcd->irq); + + /* Check for race with a wakeup request */ + if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { + ehci_resume(hcd, false); + return -EBUSY; + } + return 0; } EXPORT_SYMBOL_GPL(ehci_suspend); @@ -1166,7 +1185,7 @@ static const struct hc_driver ehci_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -1199,6 +1218,11 @@ static const struct hc_driver ehci_hc_driver = { .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + /* + * device support + */ + .free_dev = ehci_remove_device, }; void ehci_init_driver(struct hc_driver *drv, @@ -1246,11 +1270,6 @@ MODULE_LICENSE ("GPL"); #define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver #endif -#ifdef CONFIG_USB_W90X900_EHCI -#include "ehci-w90x900.c" -#define PLATFORM_DRIVER ehci_hcd_w90x900_driver -#endif - #ifdef CONFIG_USB_OCTEON_EHCI #include "ehci-octeon.c" #define PLATFORM_DRIVER ehci_octeon_driver @@ -1266,11 +1285,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_msp_driver #endif -#ifdef CONFIG_USB_EHCI_TEGRA -#include "ehci-tegra.c" -#define PLATFORM_DRIVER tegra_ehci_driver -#endif - #ifdef CONFIG_SPARC_LEON #include "ehci-grlib.c" #define PLATFORM_DRIVER ehci_grlib_driver @@ -1305,7 +1319,7 @@ static int __init ehci_hcd_init(void) sizeof(struct ehci_qh), sizeof(struct ehci_qtd), sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root); if (!ehci_debug_root) { retval = -ENOENT; @@ -1354,7 +1368,7 @@ clean2: platform_driver_unregister(&PLATFORM_DRIVER); clean0: #endif -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG debugfs_remove(ehci_debug_root); ehci_debug_root = NULL; err_debug: @@ -1378,7 +1392,7 @@ static void __exit ehci_hcd_cleanup(void) #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG debugfs_remove(ehci_debug_root); #endif clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 9ab4a4d9768..cc305c71ac3 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -33,14 +33,11 @@ #ifdef CONFIG_PM -static int ehci_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -); +static int persist_enabled_on_companion(struct usb_device *udev, void *unused) +{ + return !udev->maxchild && udev->persist_enabled && + udev->bus->root_hub->speed < USB_SPEED_HIGH; +} /* After a power loss, ports that were owned by the companion must be * reset so that the companion can still own them. @@ -56,6 +53,16 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) if (!ehci->owned_ports) return; + /* + * USB 1.1 devices are mostly HIDs, which don't need to persist across + * suspends. If we ensure that none of our companion's devices have + * persist_enabled (by looking through all USB 1.1 buses in the system), + * we can skip this and avoid slowing resume down. Devices without + * persist will just get reenumerated shortly after resume anyway. + */ + if (!usb_for_each_dev(NULL, persist_enabled_on_companion)) + return; + /* Make sure the ports are powered */ port = HCS_N_PORTS(ehci->hcs_params); while (port--) { @@ -167,7 +174,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, spin_lock_irq(&ehci->lock); /* clear phy low-power mode before changing wakeup flags */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -195,13 +202,11 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, else t2 |= PORT_WKOC_E | PORT_WKCONN_E; } - ehci_vdbg(ehci, "port %d, %08x -> %08x\n", - port + 1, t1, t2); ehci_writel(ehci, t2, reg); } /* enter phy low-power mode again */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -224,6 +229,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) int port; int mask; int changed; + bool fs_idle_delay; ehci_dbg(ehci, "suspend root hub\n"); @@ -258,6 +264,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci->bus_suspended = 0; ehci->owned_ports = 0; changed = 0; + fs_idle_delay = false; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; @@ -286,18 +293,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } if (t1 != t2) { - ehci_vdbg (ehci, "port %d, %08x -> %08x\n", - port + 1, t1, t2); + /* + * On some controllers, Wake-On-Disconnect will + * generate false wakeup signals until the bus + * switches over to full-speed idle. For their + * sake, add a delay if we need one. + */ + if ((t2 & PORT_WKDISC_E) && + ehci_port_speed(ehci, t2) == + USB_PORT_STAT_HIGH_SPEED) + fs_idle_delay = true; ehci_writel(ehci, t2, reg); changed = 1; } } + spin_unlock_irq(&ehci->lock); - if (changed && ehci->has_hostpc) { - spin_unlock_irq(&ehci->lock); - msleep(5); /* 5 ms for HCD to enter low-power mode */ - spin_lock_irq(&ehci->lock); + if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) { + /* + * Wait for HCD to enter low-power mode or for the bus + * to switch to full-speed idle. + */ + usleep_range(5000, 5500); + } + if (changed && ehci->has_tdi_phy_lpm) { + spin_lock_irq(&ehci->lock); port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -310,8 +331,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) port, (t3 & HOSTPC_PHCD) ? "succeeded" : "failed"); } + spin_unlock_irq(&ehci->lock); } - spin_unlock_irq(&ehci->lock); /* Apparently some devices need a >= 1-uframe delay here */ if (ehci->bus_suspended) @@ -329,6 +350,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) end_unlink_async(ehci); unlink_empty_async_suspended(ehci); + ehci_handle_start_intr_unlinks(ehci); ehci_handle_intr_unlinks(ehci); end_free_itds(ehci); @@ -419,7 +441,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) goto shutdown; /* clear phy low-power mode before resume */ - if (ehci->bus_suspended && ehci->has_hostpc) { + if (ehci->bus_suspended && ehci->has_tdi_phy_lpm) { i = HCS_N_PORTS(ehci->hcs_params); while (i--) { if (test_bit(i, &ehci->bus_suspended)) { @@ -466,7 +488,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd) if (test_bit(i, &resume_needed)) { temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME); ehci_writel(ehci, temp, &ehci->regs->port_status [i]); - ehci_vdbg (ehci, "resumed port %d\n", i + 1); } } @@ -695,8 +716,147 @@ ehci_hub_descriptor ( } /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_HCD_TEST_MODE -static int ehci_hub_control ( +#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06 + +static void usb_ehset_completion(struct urb *urb) +{ + struct completion *done = urb->context; + + complete(done); +} +static int submit_single_step_set_feature( + struct usb_hcd *hcd, + struct urb *urb, + int is_setup +); + +/* + * Allocate and initialize a control URB. This request will be used by the + * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages + * of the GetDescriptor request are sent 15 seconds after the SETUP stage. + * Return NULL if failed. + */ +static struct urb *request_single_step_set_feature_urb( + struct usb_device *udev, + void *dr, + void *buf, + struct completion *done +) { + struct urb *urb; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct usb_host_endpoint *ep; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return NULL; + + urb->pipe = usb_rcvctrlpipe(udev, 0); + ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) { + usb_free_urb(urb); + return NULL; + } + + urb->ep = ep; + urb->dev = udev; + urb->setup_packet = (void *)dr; + urb->transfer_buffer = buf; + urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; + urb->complete = usb_ehset_completion; + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urb->transfer_flags = URB_DIR_IN; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + urb->setup_dma = dma_map_single( + hcd->self.controller, + urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + urb->transfer_dma = dma_map_single( + hcd->self.controller, + urb->transfer_buffer, + urb->transfer_buffer_length, + DMA_FROM_DEVICE); + urb->context = done; + return urb; +} + +static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) +{ + int retval = -ENOMEM; + struct usb_ctrlrequest *dr; + struct urb *urb; + struct usb_device *udev; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct usb_device_descriptor *buf; + DECLARE_COMPLETION_ONSTACK(done); + + /* Obtain udev of the rhub's child port */ + udev = usb_hub_find_child(hcd->self.root_hub, port); + if (!udev) { + ehci_err(ehci, "No device attached to the RootHub\n"); + return -ENODEV; + } + buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) { + kfree(buf); + return -ENOMEM; + } + + /* Fill Setup packet for GetDescriptor */ + dr->bRequestType = USB_DIR_IN; + dr->bRequest = USB_REQ_GET_DESCRIPTOR; + dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8); + dr->wIndex = 0; + dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE); + urb = request_single_step_set_feature_urb(udev, dr, buf, &done); + if (!urb) + goto cleanup; + + /* Submit just the SETUP stage */ + retval = submit_single_step_set_feature(hcd, urb, 1); + if (retval) + goto out1; + if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__); + goto out1; + } + msleep(15 * 1000); + + /* Complete remaining DATA and STATUS stages using the same URB */ + urb->status = -EINPROGRESS; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + retval = submit_single_step_set_feature(hcd, urb, 0); + if (!retval && !wait_for_completion_timeout(&done, + msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__); + } +out1: + usb_free_urb(urb); +cleanup: + kfree(dr); + kfree(buf); + return retval; +} +#endif /* CONFIG_USB_HCD_TEST_MODE */ +/*-------------------------------------------------------------------------*/ + +int ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -772,7 +932,7 @@ static int ehci_hub_control ( goto error; /* clear phy low-power mode before resume */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { temp1 = ehci_readl(ehci, hostpc_reg); ehci_writel(ehci, temp1 & ~HOSTPC_PHCD, hostpc_reg); @@ -785,6 +945,8 @@ static int ehci_hub_control ( ehci_writel(ehci, temp | PORT_RESUME, status_reg); ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); + set_bit(wIndex, &ehci->resuming_ports); + usb_hcd_start_port_resume(&hcd->self, wIndex); break; case USB_PORT_FEAT_C_SUSPEND: clear_bit(wIndex, &ehci->port_c_suspend); @@ -849,52 +1011,49 @@ static int ehci_hub_control ( } } - /* whoever resumes must GetPortStatus to complete it!! */ - if (temp & PORT_RESUME) { + /* no reset or resume pending */ + if (!ehci->reset_done[wIndex]) { /* Remote Wakeup received? */ - if (!ehci->reset_done[wIndex]) { + if (temp & PORT_RESUME) { /* resume signaling for 20 msec */ ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); usb_hcd_start_port_resume(&hcd->self, wIndex); + set_bit(wIndex, &ehci->resuming_ports); /* check the port again */ mod_timer(&ehci_to_hcd(ehci)->rh_timer, ehci->reset_done[wIndex]); } - /* resume completed? */ - else if (time_after_eq(jiffies, - ehci->reset_done[wIndex])) { - clear_bit(wIndex, &ehci->suspended_ports); - set_bit(wIndex, &ehci->port_c_suspend); - ehci->reset_done[wIndex] = 0; - usb_hcd_end_port_resume(&hcd->self, wIndex); - - /* stop resume signaling */ - temp &= ~(PORT_RWC_BITS | - PORT_SUSPEND | PORT_RESUME); - ehci_writel(ehci, temp, status_reg); - clear_bit(wIndex, &ehci->resuming_ports); - retval = handshake(ehci, status_reg, - PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - ehci_err(ehci, - "port %d resume error %d\n", + /* reset or resume not yet complete */ + } else if (!time_after_eq(jiffies, ehci->reset_done[wIndex])) { + ; /* wait until it is complete */ + + /* resume completed */ + } else if (test_bit(wIndex, &ehci->resuming_ports)) { + clear_bit(wIndex, &ehci->suspended_ports); + set_bit(wIndex, &ehci->port_c_suspend); + ehci->reset_done[wIndex] = 0; + usb_hcd_end_port_resume(&hcd->self, wIndex); + + /* stop resume signaling */ + temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME); + ehci_writel(ehci, temp, status_reg); + clear_bit(wIndex, &ehci->resuming_ports); + retval = ehci_handshake(ehci, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + ehci_err(ehci, "port %d resume error %d\n", wIndex + 1, retval); - goto error; - } - temp = ehci_readl(ehci, status_reg); + goto error; } - } + temp = ehci_readl(ehci, status_reg); /* whoever resets must GetPortStatus to complete it!! */ - if ((temp & PORT_RESET) - && time_after_eq(jiffies, - ehci->reset_done[wIndex])) { + } else { status |= USB_PORT_STAT_C_RESET << 16; ehci->reset_done [wIndex] = 0; - clear_bit(wIndex, &ehci->resuming_ports); /* force reset to complete */ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), @@ -902,7 +1061,7 @@ static int ehci_hub_control ( /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake(ehci, status_reg, + retval = ehci_handshake(ehci, status_reg, PORT_RESET, 0, 1000); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", @@ -915,11 +1074,6 @@ static int ehci_hub_control ( ehci_readl(ehci, status_reg)); } - if (!(temp & (PORT_RESUME|PORT_RESET))) { - ehci->reset_done[wIndex] = 0; - clear_bit(wIndex, &ehci->resuming_ports); - } - /* transfer dedicated ports to the companion hc */ if ((temp & PORT_CONNECT) && test_bit(wIndex, &ehci->companion_ports)) { @@ -969,10 +1123,8 @@ static int ehci_hub_control ( if (test_bit(wIndex, &ehci->port_c_suspend)) status |= USB_PORT_STAT_C_SUSPEND << 16; -#ifndef VERBOSE_DEBUG - if (status & ~0xffff) /* only if wPortChange is interesting */ -#endif - dbg_port (ehci, "GetStatus", wIndex + 1, temp); + if (status & ~0xffff) /* only if wPortChange is interesting */ + dbg_port(ehci, "GetStatus", wIndex + 1, temp); put_unaligned_le32(status, buf); break; case SetHubFeature: @@ -1015,12 +1167,12 @@ static int ehci_hub_control ( /* After above check the port must be connected. * Set appropriate bit thus could put phy into low power - * mode if we have hostpc feature + * mode if we have tdi_phy_lpm feature */ temp &= ~PORT_WKCONN_E; temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { spin_unlock_irqrestore(&ehci->lock, flags); msleep(5);/* 5ms for HCD enter low pwr mode */ spin_lock_irqsave(&ehci->lock, flags); @@ -1040,7 +1192,7 @@ static int ehci_hub_control ( status_reg); break; case USB_PORT_FEAT_RESET: - if (temp & PORT_RESUME) + if (temp & (PORT_SUSPEND|PORT_RESUME)) goto error; /* line status bits may report this as low speed, * which can be fine if this root hub has a @@ -1054,7 +1206,6 @@ static int ehci_hub_control ( wIndex + 1); temp |= PORT_OWNER; } else { - ehci_vdbg (ehci, "port %d reset\n", wIndex + 1); temp |= PORT_RESET; temp &= ~PORT_PE; @@ -1075,6 +1226,15 @@ static int ehci_hub_control ( * about the EHCI-specific stuff. */ case USB_PORT_FEAT_TEST: +#ifdef CONFIG_USB_HCD_TEST_MODE + if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) { + spin_unlock_irqrestore(&ehci->lock, flags); + retval = ehset_single_step_set_feature(hcd, + wIndex); + spin_lock_irqsave(&ehci->lock, flags); + break; + } +#endif if (!selector || selector > 5) goto error; spin_unlock_irqrestore(&ehci->lock, flags); @@ -1116,6 +1276,7 @@ error_exit: spin_unlock_irqrestore (&ehci->lock, flags); return retval; } +EXPORT_SYMBOL_GPL(ehci_hub_control); static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) { diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index ef2c3a1eca4..c0fb6a8ae6a 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -93,6 +93,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); INIT_LIST_HEAD (&qh->qtd_list); + INIT_LIST_HEAD(&qh->unlink_node); /* dummy td enables safe urb queuing */ qh->dummy = ehci_qtd_alloc (ehci, flags); @@ -223,11 +224,11 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) hw->hw_next = EHCI_LIST_END(ehci); hw->hw_qtd_next = EHCI_LIST_END(ehci); hw->hw_alt_next = EHCI_LIST_END(ehci); - hw->hw_token &= ~QTD_STS_ACTIVE; ehci->dummy->hw = hw; for (i = 0; i < ehci->periodic_size; i++) - ehci->periodic[i] = ehci->dummy->qh_dma; + ehci->periodic[i] = cpu_to_hc32(ehci, + ehci->dummy->qh_dma); } else { for (i = 0; i < ehci->periodic_size; i++) ehci->periodic[i] = EHCI_LIST_END(ehci); diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 0f717dc688b..982c09bebe0 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -42,7 +42,6 @@ static const char hcd_name[] = "ehci-msm"; static struct hc_driver __read_mostly msm_hc_driver; -static struct usb_phy *phy; static int ehci_msm_reset(struct usb_hcd *hcd) { @@ -70,6 +69,7 @@ static int ehci_msm_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; + struct usb_phy *phy; int ret; dev_dbg(&pdev->dev, "ehci_msm proble\n"); @@ -96,10 +96,9 @@ static int ehci_msm_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); goto put_hcd; } @@ -108,10 +107,14 @@ static int ehci_msm_probe(struct platform_device *pdev) * powering up VBUS, mapping of registers address space and power * management. */ - phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); + if (pdev->dev.of_node) + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + else + phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); + if (IS_ERR(phy)) { dev_err(&pdev->dev, "unable to find transceiver\n"); - ret = -ENODEV; + ret = -EPROBE_DEFER; goto put_hcd; } @@ -121,6 +124,7 @@ static int ehci_msm_probe(struct platform_device *pdev) goto put_hcd; } + hcd->phy = phy; device_init_wakeup(&pdev->dev, 1); /* * OTG device parent of HCD takes care of putting @@ -147,7 +151,7 @@ static int ehci_msm_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - otg_set_host(phy->otg, NULL); + otg_set_host(hcd->phy->otg, NULL); /* FIXME: need to call usb_remove_hcd() here? */ @@ -186,12 +190,19 @@ static const struct dev_pm_ops ehci_msm_dev_pm_ops = { .resume = ehci_msm_pm_resume, }; +static struct of_device_id msm_ehci_dt_match[] = { + { .compatible = "qcom,ehci-host", }, + {} +}; +MODULE_DEVICE_TABLE(of, msm_ehci_dt_match); + static struct platform_driver ehci_msm_driver = { .probe = ehci_msm_probe, .remove = ehci_msm_remove, .driver = { .name = "msm_hsusb_host", .pm = &ehci_msm_dev_pm_ops, + .of_match_table = msm_ehci_dt_match, }, }; diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 402062973f0..08147c35f83 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -96,7 +96,7 @@ static const struct hc_driver mv_ehci_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -131,7 +131,7 @@ static const struct hc_driver mv_ehci_hc_driver = { static int mv_ehci_probe(struct platform_device *pdev) { - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd; struct ehci_hcd *ehci; struct ehci_hcd_mv *ehci_mv; @@ -166,43 +166,39 @@ static int mv_ehci_probe(struct platform_device *pdev) if (IS_ERR(ehci_mv->clk)) { dev_err(&pdev->dev, "error getting clock\n"); retval = PTR_ERR(ehci_mv->clk); - goto err_clear_drvdata; + goto err_put_hcd; } r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); if (r == NULL) { dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); retval = -ENODEV; - goto err_clear_drvdata; + goto err_put_hcd; } - ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start, - resource_size(r)); - if (ehci_mv->phy_regs == 0) { - dev_err(&pdev->dev, "failed to map phy I/O memory\n"); - retval = -EFAULT; - goto err_clear_drvdata; + ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(ehci_mv->phy_regs)) { + retval = PTR_ERR(ehci_mv->phy_regs); + goto err_put_hcd; } r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); if (!r) { dev_err(&pdev->dev, "no I/O memory resource defined\n"); retval = -ENODEV; - goto err_clear_drvdata; + goto err_put_hcd; } - ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start, - resource_size(r)); - if (ehci_mv->cap_regs == NULL) { - dev_err(&pdev->dev, "failed to map I/O memory\n"); - retval = -EFAULT; - goto err_clear_drvdata; + ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(ehci_mv->cap_regs)) { + retval = PTR_ERR(ehci_mv->cap_regs); + goto err_put_hcd; } retval = mv_ehci_enable(ehci_mv); if (retval) { dev_err(&pdev->dev, "init phy error %d\n", retval); - goto err_clear_drvdata; + goto err_put_hcd; } offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; @@ -257,6 +253,7 @@ static int mv_ehci_probe(struct platform_device *pdev) "failed to add hcd with err %d\n", retval); goto err_set_vbus; } + device_wakeup_enable(hcd->self.controller); } if (pdata->private_init) @@ -274,8 +271,6 @@ err_set_vbus: pdata->set_vbus(0); err_disable_clk: mv_ehci_disable(ehci_mv); -err_clear_drvdata: - platform_set_drvdata(pdev, NULL); err_put_hcd: usb_put_hcd(hcd); @@ -300,8 +295,6 @@ static int mv_ehci_remove(struct platform_device *pdev) mv_ehci_disable(ehci_mv); } - platform_set_drvdata(pdev, NULL); - usb_put_hcd(hcd); return 0; diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index c369767b00e..dbe5e4eea08 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -49,7 +49,7 @@ static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = { static int ehci_mxc_drv_probe(struct platform_device *pdev) { - struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; + struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd; struct resource *res; int irq, ret; @@ -155,6 +155,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) if (ret) goto err_add; + device_wakeup_enable(hcd->self.controller); return 0; err_add: @@ -174,7 +175,7 @@ err_alloc: static int ehci_mxc_drv_remove(struct platform_device *pdev) { - struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; + struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv; @@ -184,7 +185,7 @@ static int ehci_mxc_drv_remove(struct platform_device *pdev) if (pdata && pdata->exit) pdata->exit(pdev); - if (pdata->otg) + if (pdata && pdata->otg) usb_phy_shutdown(pdata->otg); clk_disable_unprepare(priv->usbclk); @@ -194,24 +195,15 @@ static int ehci_mxc_drv_remove(struct platform_device *pdev) clk_disable_unprepare(priv->phyclk); usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); return 0; } -static void ehci_mxc_drv_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - MODULE_ALIAS("platform:mxc-ehci"); static struct platform_driver ehci_mxc_driver = { .probe = ehci_mxc_drv_probe, .remove = ehci_mxc_drv_remove, - .shutdown = ehci_mxc_drv_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "mxc-ehci", }, diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index a89750fff4f..9051439039a 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -51,7 +51,7 @@ static const struct hc_driver ehci_octeon_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -116,8 +116,10 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) * We can DMA from anywhere. But the descriptors must be in * the lower 4GB. */ - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdev->dev.dma_mask = &ehci_octeon_dma_mask; + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon"); if (!hcd) @@ -126,20 +128,12 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - OCTEON_EHCI_HCD_NAME)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; + hcd->regs = devm_ioremap_resource(&pdev->dev, res_mem); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); goto err1; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err2; - } - ehci_octeon_start(); ehci = hcd_to_ehci(hcd); @@ -154,18 +148,16 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) { dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); - goto err3; + goto err2; } + device_wakeup_enable(hcd->self.controller); platform_set_drvdata(pdev, hcd); return 0; -err3: +err2: ehci_octeon_stop(); - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); return ret; @@ -178,12 +170,8 @@ static int ehci_octeon_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); ehci_octeon_stop(); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 16d7150e855..a24720beb39 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -100,11 +100,11 @@ static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { static int ehci_hcd_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct resource *res; struct usb_hcd *hcd; void __iomem *regs; - int ret = -ENODEV; + int ret; int irq; int i; struct omap_hcd *omap; @@ -119,7 +119,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) /* For DT boot, get platform data from parent. i.e. usbhshost */ if (dev->of_node) { - pdata = dev->parent->platform_data; + pdata = dev_get_platdata(dev->parent); dev->platform_data = pdata; } @@ -144,11 +144,11 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - if (!dev->dma_mask) - dev->dma_mask = &dev->coherent_dma_mask; - if (!dev->coherent_dma_mask) - dev->coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + ret = -ENODEV; hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, dev_name(dev)); if (!hcd) { @@ -187,6 +187,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) } omap->phy[i] = phy; + + if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY) { + usb_phy_init(omap->phy[i]); + /* bring PHY out of suspend */ + usb_phy_set_suspend(omap->phy[i], 0); + } } pm_runtime_enable(dev); @@ -209,15 +215,17 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) dev_err(dev, "failed to add hcd with err %d\n", ret); goto err_pm_runtime; } + device_wakeup_enable(hcd->self.controller); /* - * Bring PHYs out of reset. + * Bring PHYs out of reset for non PHY modes. * Even though HSIC mode is a PHY-less mode, the reset * line exists between the chips and can be modelled * as a PHY device for reset control. */ for (i = 0; i < omap->nports; i++) { - if (!omap->phy[i]) + if (!omap->phy[i] || + pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY) continue; usb_phy_init(omap->phy[i]); @@ -271,14 +279,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev) return 0; } -static void ehci_hcd_omap_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - static const struct of_device_id omap_ehci_dt_ids[] = { { .compatible = "ti,ehci-omap" }, { } @@ -289,12 +289,12 @@ MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids); static struct platform_driver ehci_hcd_omap_driver = { .probe = ehci_hcd_omap_probe, .remove = ehci_hcd_omap_remove, - .shutdown = ehci_hcd_omap_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ehci_hcd_omap_suspend, */ /*.resume = ehci_hcd_omap_resume, */ .driver = { .name = hcd_name, - .of_match_table = of_match_ptr(omap_ehci_dt_ids), + .of_match_table = omap_ehci_dt_ids, } }; diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index efbc588b48c..22e15cab8ea 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -15,6 +15,7 @@ #include <linux/clk.h> #include <linux/platform_data/usb-ehci-orion.h> #include <linux/of.h> +#include <linux/phy/phy.h> #include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/usb.h> @@ -42,6 +43,13 @@ #define DRIVER_DESC "EHCI orion driver" +#define hcd_to_orion_priv(h) ((struct orion_ehci_hcd *)hcd_to_ehci(h)->priv) + +struct orion_ehci_hcd { + struct clk *clk; + struct phy *phy; +}; + static const char hcd_name[] = "ehci-orion"; static struct hc_driver __read_mostly ehci_orion_hc_driver; @@ -137,33 +145,34 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, } } +static const struct ehci_driver_overrides orion_overrides __initconst = { + .extra_priv_size = sizeof(struct orion_ehci_hcd), +}; + static int ehci_orion_drv_probe(struct platform_device *pdev) { - struct orion_ehci_data *pd = pdev->dev.platform_data; + struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev); const struct mbus_dram_target_info *dram; struct resource *res; struct usb_hcd *hcd; struct ehci_hcd *ehci; - struct clk *clk; void __iomem *regs; int irq, err; enum orion_ehci_phy_ver phy_version; + struct orion_ehci_hcd *priv; if (usb_disabled()) return -ENODEV; pr_debug("Initializing Orion-SoC USB Host Controller\n"); - if (pdev->dev.of_node) - irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - else - irq = platform_get_irq(pdev, 0); + 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)); err = -ENODEV; - goto err1; + goto err; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -172,7 +181,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) "Found HC with no register addr. Check %s setup!\n", dev_name(&pdev->dev)); err = -ENODEV; - goto err1; + goto err; } /* @@ -180,38 +189,21 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) * 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - - if (!request_mem_region(res->start, resource_size(res), - ehci_orion_hc_driver.description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - err = -EBUSY; - goto err1; - } - - regs = ioremap(res->start, resource_size(res)); - if (regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - err = -EFAULT; - goto err2; - } + err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + goto err; - /* Not all platforms can gate the clock, so it is not - an error if the clock does not exists. */ - clk = clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) { - clk_prepare_enable(clk); - clk_put(clk); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) { + err = PTR_ERR(regs); + goto err; } hcd = usb_create_hcd(&ehci_orion_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { err = -ENOMEM; - goto err3; + goto err; } hcd->rsrc_start = res->start; @@ -222,6 +214,29 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) ehci->caps = hcd->regs + 0x100; hcd->has_tt = 1; + priv = hcd_to_orion_priv(hcd); + /* + * Not all platforms can gate the clock, so it is not an error if + * the clock does not exists. + */ + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(priv->clk)) + clk_prepare_enable(priv->clk); + + priv->phy = devm_phy_optional_get(&pdev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); + goto err_phy_get; + } else { + err = phy_init(priv->phy); + if (err) + goto err_phy_init; + + err = phy_power_on(priv->phy); + if (err) + goto err_phy_power_on; + } + /* * (Re-)program MBUS remapping windows if we are asked to. */ @@ -246,26 +261,28 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) case EHCI_PHY_DD: case EHCI_PHY_KW: default: - printk(KERN_WARNING "Orion ehci -USB phy version isn't supported.\n"); + dev_warn(&pdev->dev, "USB phy version isn't supported.\n"); } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err4; + goto err_add_hcd; + device_wakeup_enable(hcd->self.controller); return 0; -err4: +err_add_hcd: + if (!IS_ERR(priv->phy)) + phy_power_off(priv->phy); +err_phy_power_on: + if (!IS_ERR(priv->phy)) + phy_exit(priv->phy); +err_phy_init: +err_phy_get: + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); usb_put_hcd(hcd); -err3: - if (!IS_ERR(clk)) { - clk_disable_unprepare(clk); - clk_put(clk); - } - iounmap(regs); -err2: - release_mem_region(res->start, resource_size(res)); -err1: +err: dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), err); @@ -275,18 +292,20 @@ err1: static int ehci_orion_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct clk *clk; + struct orion_ehci_hcd *priv = hcd_to_orion_priv(hcd); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - clk = clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) { - clk_disable_unprepare(clk); - clk_put(clk); + if (!IS_ERR(priv->phy)) { + phy_power_off(priv->phy); + phy_exit(priv->phy); } + + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + + usb_put_hcd(hcd); + return 0; } @@ -303,7 +322,7 @@ static struct platform_driver ehci_orion_driver = { .driver = { .name = "orion-ehci", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(ehci_orion_dt_ids), + .of_match_table = ehci_orion_dt_ids, }, }; @@ -314,7 +333,7 @@ static int __init ehci_orion_init(void) pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_orion_hc_driver, NULL); + ehci_init_driver(&ehci_orion_hc_driver, &orion_overrides); return platform_driver_register(&ehci_orion_driver); } module_init(ehci_orion_init); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 595d210655b..3e86bf4371b 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,8 +58,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - struct pci_dev *p_smbus; - u8 rev; u32 temp; int retval; @@ -175,22 +173,12 @@ static int ehci_pci_setup(struct usb_hcd *hcd) /* SB600 and old version of SB700 have a bug in EHCI controller, * which causes usb devices lose response in some cases. */ - if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) { - p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, - PCI_DEVICE_ID_ATI_SBX00_SMBUS, - NULL); - if (!p_smbus) - break; - rev = p_smbus->revision; - if ((pdev->device == 0x4386) || (rev == 0x3a) - || (rev == 0x3b)) { - u8 tmp; - ehci_info(ehci, "applying AMD SB600/SB700 USB " - "freeze workaround\n"); - pci_read_config_byte(pdev, 0x53, &tmp); - pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); - } - pci_dev_put(p_smbus); + if ((pdev->device == 0x4386 || pdev->device == 0x4396) && + usb_amd_hang_symptom_quirk()) { + u8 tmp; + ehci_info(ehci, "applying AMD SB600/SB700 USB freeze workaround\n"); + pci_read_config_byte(pdev, 0x53, &tmp); + pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); } break; case PCI_VENDOR_ID_NETMOS: @@ -315,53 +303,11 @@ done: * Also they depend on separate root hub suspend/resume. */ -static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - (pdev->device == 0x1E26 || - pdev->device == 0x8C2D || - pdev->device == 0x8C26 || - pdev->device == 0x9C26); -} - -static void ehci_enable_xhci_companion(void) -{ - struct pci_dev *companion = NULL; - - /* The xHCI and EHCI controllers are not on the same PCI slot */ - for_each_pci_dev(companion) { - if (!usb_is_intel_switchable_xhci(companion)) - continue; - usb_enable_xhci_ports(companion); - return; - } -} - static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - /* The BIOS on systems with the Intel Panther Point chipset may or may - * not support xHCI natively. That means that during system resume, it - * may switch the ports back to EHCI so that users can use their - * keyboard to select a kernel from GRUB after resume from hibernate. - * - * The BIOS is supposed to remember whether the OS had xHCI ports - * enabled before resume, and switch the ports back to xHCI when the - * BIOS/OS semaphore is written, but we all know we can't trust BIOS - * writers. - * - * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. - */ - if (usb_is_intel_switchable_ehci(pdev)) - ehci_enable_xhci_companion(); - if (ehci_resume(hcd, hibernated) != 0) (void) ehci_pci_reinit(ehci, pdev); return 0; @@ -403,7 +349,7 @@ static struct pci_driver ehci_pci_driver = { .remove = usb_hcd_pci_remove, .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index f47f2594c9d..2f5b9ce3e04 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -3,6 +3,7 @@ * * Copyright 2007 Steven Brown <sbrown@cortland.com> * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright 2014 Hans de Goede <hdegoede@redhat.com> * * Derived from the ohci-ssb driver * Copyright 2007 Michael Buesch <m@bues.ch> @@ -18,6 +19,7 @@ * * Licensed under the GNU/GPL. See COPYING for details. */ +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/kernel.h> @@ -25,7 +27,9 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/phy/phy.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/usb.h> #include <linux/usb/hcd.h> #include <linux/usb/ehci_pdriver.h> @@ -33,20 +37,32 @@ #include "ehci.h" #define DRIVER_DESC "EHCI generic platform driver" +#define EHCI_MAX_CLKS 3 +#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) + +struct ehci_platform_priv { + struct clk *clks[EHCI_MAX_CLKS]; + struct reset_control *rst; + struct phy *phy; +}; 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); - struct usb_ehci_pdata *pdata = pdev->dev.platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; hcd->has_tt = pdata->has_tt; ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug; - ehci->big_endian_desc = pdata->big_endian_desc; - ehci->big_endian_mmio = pdata->big_endian_mmio; + + if (pdata->pre_setup) { + retval = pdata->pre_setup(hcd); + if (retval < 0) + return retval; + } ehci->caps = hcd->regs + pdata->caps_offset; retval = ehci_setup(hcd); @@ -58,37 +74,90 @@ static int ehci_platform_reset(struct usb_hcd *hcd) return 0; } +static int ehci_platform_power_on(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + int clk, ret; + + for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) { + ret = clk_prepare_enable(priv->clks[clk]); + if (ret) + goto err_disable_clks; + } + + if (priv->phy) { + ret = phy_init(priv->phy); + if (ret) + goto err_disable_clks; + + ret = phy_power_on(priv->phy); + if (ret) + goto err_exit_phy; + } + + return 0; + +err_exit_phy: + phy_exit(priv->phy); +err_disable_clks: + while (--clk >= 0) + clk_disable_unprepare(priv->clks[clk]); + + return ret; +} + +static void ehci_platform_power_off(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + int clk; + + if (priv->phy) { + phy_power_off(priv->phy); + phy_exit(priv->phy); + } + + for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--) + if (priv->clks[clk]) + clk_disable_unprepare(priv->clks[clk]); +} + static struct hc_driver __read_mostly ehci_platform_hc_driver; static const struct ehci_driver_overrides platform_overrides __initconst = { - .reset = ehci_platform_reset, + .reset = ehci_platform_reset, + .extra_priv_size = sizeof(struct ehci_platform_priv), }; -static struct usb_ehci_pdata ehci_platform_defaults; +static struct usb_ehci_pdata ehci_platform_defaults = { + .power_on = ehci_platform_power_on, + .power_suspend = ehci_platform_power_off, + .power_off = ehci_platform_power_off, +}; static int ehci_platform_probe(struct platform_device *dev) { struct usb_hcd *hcd; struct resource *res_mem; - struct usb_ehci_pdata *pdata; - int irq; - int err = -ENOMEM; + struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); + struct ehci_platform_priv *priv; + struct ehci_hcd *ehci; + int err, irq, clk = 0; if (usb_disabled()) return -ENODEV; /* - * use reasonable defaults so platforms don't have to provide these. - * with DT probing on ARM, none of these are set. + * Use reasonable defaults so platforms don't have to provide these + * with DT probing on ARM. */ - if (!dev->dev.platform_data) - dev->dev.platform_data = &ehci_platform_defaults; - if (!dev->dev.dma_mask) - dev->dev.dma_mask = &dev->dev.coherent_dma_mask; - if (!dev->dev.coherent_dma_mask) - dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + if (!pdata) + pdata = &ehci_platform_defaults; - pdata = dev->dev.platform_data; + err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); + if (err) + return err; irq = platform_get_irq(dev, 0); if (irq < 0) { @@ -101,17 +170,84 @@ static int ehci_platform_probe(struct platform_device *dev) return -ENXIO; } + hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, + dev_name(&dev->dev)); + if (!hcd) + return -ENOMEM; + + platform_set_drvdata(dev, hcd); + dev->dev.platform_data = pdata; + priv = hcd_to_ehci_priv(hcd); + ehci = hcd_to_ehci(hcd); + + if (pdata == &ehci_platform_defaults && dev->dev.of_node) { + if (of_property_read_bool(dev->dev.of_node, "big-endian-regs")) + ehci->big_endian_mmio = 1; + + if (of_property_read_bool(dev->dev.of_node, "big-endian-desc")) + ehci->big_endian_desc = 1; + + if (of_property_read_bool(dev->dev.of_node, "big-endian")) + ehci->big_endian_mmio = ehci->big_endian_desc = 1; + + priv->phy = devm_phy_get(&dev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); + if (err == -EPROBE_DEFER) + goto err_put_hcd; + priv->phy = NULL; + } + + for (clk = 0; clk < EHCI_MAX_CLKS; clk++) { + priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); + if (IS_ERR(priv->clks[clk])) { + err = PTR_ERR(priv->clks[clk]); + if (err == -EPROBE_DEFER) + goto err_put_clks; + priv->clks[clk] = NULL; + break; + } + } + } + + priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); + if (IS_ERR(priv->rst)) { + err = PTR_ERR(priv->rst); + if (err == -EPROBE_DEFER) + goto err_put_clks; + priv->rst = NULL; + } else { + err = reset_control_deassert(priv->rst); + if (err) + goto err_put_clks; + } + + if (pdata->big_endian_desc) + ehci->big_endian_desc = 1; + if (pdata->big_endian_mmio) + ehci->big_endian_mmio = 1; + +#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + if (ehci->big_endian_mmio) { + dev_err(&dev->dev, + "Error: CONFIG_USB_EHCI_BIG_ENDIAN_MMIO not set\n"); + err = -EINVAL; + goto err_reset; + } +#endif +#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC + if (ehci->big_endian_desc) { + dev_err(&dev->dev, + "Error: CONFIG_USB_EHCI_BIG_ENDIAN_DESC not set\n"); + err = -EINVAL; + goto err_reset; + } +#endif + if (pdata->power_on) { err = pdata->power_on(dev); if (err < 0) - return err; - } - - hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, - dev_name(&dev->dev)); - if (!hcd) { - err = -ENOMEM; - goto err_power; + goto err_reset; } hcd->rsrc_start = res_mem->start; @@ -120,21 +256,31 @@ static int ehci_platform_probe(struct platform_device *dev) hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); - goto err_put_hcd; + goto err_power; } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_put_hcd; + goto err_power; + device_wakeup_enable(hcd->self.controller); platform_set_drvdata(dev, hcd); return err; -err_put_hcd: - usb_put_hcd(hcd); err_power: if (pdata->power_off) pdata->power_off(dev); +err_reset: + if (priv->rst) + reset_control_assert(priv->rst); +err_put_clks: + while (--clk >= 0) + clk_put(priv->clks[clk]); +err_put_hcd: + if (pdata == &ehci_platform_defaults) + dev->dev.platform_data = NULL; + + usb_put_hcd(hcd); return err; } @@ -142,15 +288,23 @@ err_power: static int ehci_platform_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); - struct usb_ehci_pdata *pdata = dev->dev.platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); + struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + int clk; usb_remove_hcd(hcd); - usb_put_hcd(hcd); - platform_set_drvdata(dev, NULL); if (pdata->power_off) pdata->power_off(dev); + if (priv->rst) + reset_control_assert(priv->rst); + + for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) + clk_put(priv->clks[clk]); + + usb_put_hcd(hcd); + if (pdata == &ehci_platform_defaults) dev->dev.platform_data = NULL; @@ -162,13 +316,15 @@ static int ehci_platform_remove(struct platform_device *dev) static int ehci_platform_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ehci_pdata *pdata = dev->platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); bool do_wakeup = device_may_wakeup(dev); int ret; ret = ehci_suspend(hcd, do_wakeup); + if (ret) + return ret; if (pdata->power_suspend) pdata->power_suspend(pdev); @@ -179,7 +335,7 @@ static int ehci_platform_suspend(struct device *dev) static int ehci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ehci_pdata *pdata = dev->platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); @@ -201,8 +357,10 @@ static int ehci_platform_resume(struct device *dev) static const struct of_device_id vt8500_ehci_ids[] = { { .compatible = "via,vt8500-ehci", }, { .compatible = "wm,prizm-ehci", }, + { .compatible = "generic-ehci", }, {} }; +MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); static const struct platform_device_id ehci_platform_table[] = { { "ehci-platform", 0 }, @@ -224,7 +382,7 @@ static struct platform_driver ehci_platform_driver = { .owner = THIS_MODULE, .name = "ehci-platform", .pm = &ehci_platform_pm_ops, - .of_match_table = of_match_ptr(vt8500_ehci_ids), + .of_match_table = vt8500_ehci_ids, } }; diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index 363890ee41d..7d75465d97c 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c @@ -68,9 +68,6 @@ static void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci) /* set TWI GPIO USB_HOST_DEV pin high */ gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1); -#ifdef CONFIG_MSP_HAS_DUAL_USB - gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1); -#endif } /* called during probe() after chip reset completes */ @@ -210,8 +207,10 @@ int usb_hcd_msp_probe(const struct hc_driver *driver, retval = usb_add_hcd(hcd, res->start, IRQF_SHARED); - if (retval == 0) + if (retval == 0) { + device_wakeup_enable(hcd->self.controller); return 0; + } usb_remove_hcd(hcd); err3: @@ -246,33 +245,6 @@ void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev) usb_put_hcd(hcd); } -#ifdef CONFIG_MSP_HAS_DUAL_USB -/* - * Wrapper around the main ehci_irq. Since both USB host controllers are - * sharing the same IRQ, need to first determine whether we're the intended - * recipient of this interrupt. - */ -static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd) -{ - u32 int_src; - struct device *dev = hcd->self.controller; - struct platform_device *pdev; - struct mspusb_device *mdev; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - /* need to reverse-map a couple of containers to get our device */ - pdev = to_platform_device(dev); - mdev = to_mspusb_device(pdev); - - /* Check to see if this interrupt is for this host controller */ - int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat); - if (int_src & (1 << pdev->id)) - return ehci_irq(hcd); - - /* Not for this device */ - return IRQ_NONE; -} -#endif /* DUAL_USB */ - static const struct hc_driver ehci_msp_hc_driver = { .description = hcd_name, .product_desc = "PMC MSP EHCI", @@ -281,18 +253,13 @@ static const struct hc_driver ehci_msp_hc_driver = { /* * generic hardware linkage */ -#ifdef CONFIG_MSP_HAS_DUAL_USB - .irq = ehci_msp_irq, -#else .irq = ehci_irq, -#endif - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations */ - .reset = ehci_msp_setup, - .start = ehci_run, + .reset = ehci_msp_setup, .shutdown = ehci_shutdown, .start = ehci_run, .stop = ehci_stop, @@ -333,9 +300,6 @@ static int ehci_hcd_msp_drv_probe(struct platform_device *pdev) return -ENODEV; gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO"); -#ifdef CONFIG_MSP_HAS_DUAL_USB - gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO"); -#endif ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev); @@ -350,9 +314,6 @@ static int ehci_hcd_msp_drv_remove(struct platform_device *pdev) /* free TWI GPIO USB_HOST_DEV pin */ gpio_free(MSP_PIN_USB0_HOST_DEV); -#ifdef CONFIG_MSP_HAS_DUAL_USB - gpio_free(MSP_PIN_USB1_HOST_DEV); -#endif return 0; } diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 56dc732bf45..547924796d2 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -16,6 +16,8 @@ #include <linux/signal.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> @@ -28,7 +30,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -117,7 +119,8 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op) irq = irq_of_parse_and_map(dn, 0); if (irq == NO_IRQ) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); + dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", + __FILE__); rv = -EBUSY; goto err_irq; } @@ -167,6 +170,7 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op) if (rv) goto err_ioremap; + device_wakeup_enable(hcd->self.controller); return 0; err_ioremap: @@ -180,14 +184,12 @@ err_irq: static int ehci_hcd_ppc_of_remove(struct platform_device *op) { - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + struct usb_hcd *hcd = platform_get_drvdata(op); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct device_node *np; struct resource res; - dev_set_drvdata(&op->dev, NULL); - dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); usb_remove_hcd(hcd); @@ -217,15 +219,6 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op) } -static void ehci_hcd_ppc_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ehci_hcd_ppc_of_match[] = { { .compatible = "usb-ehci", @@ -238,7 +231,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match); static struct platform_driver ehci_hcd_ppc_of_driver = { .probe = ehci_hcd_ppc_of_probe, .remove = ehci_hcd_ppc_of_remove, - .shutdown = ehci_hcd_ppc_of_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ppc-of-ehci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index fd983771b02..7934ff9b35e 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -71,7 +71,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .product_desc = "PS3 EHCI Host Controller", .hcd_priv_size = sizeof(struct ehci_hcd), .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, .reset = ps3_ehci_hc_reset, .start = ehci_run, .stop = ehci_stop, @@ -189,6 +189,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) goto fail_add_hcd; } + device_wakeup_enable(hcd->self.controller); return result; fail_add_hcd: diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index d34b399b78e..54f5332f814 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -105,9 +105,9 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) is_out = qh->is_out; epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; - if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { + if (unlikely(!usb_gettoggle(qh->ps.udev, epnum, is_out))) { hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - usb_settoggle (qh->dev, epnum, is_out, 1); + usb_settoggle(qh->ps.udev, epnum, is_out, 1); } } @@ -168,13 +168,13 @@ static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh, * Note: this routine is never called for Isochronous transfers. */ if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG struct usb_device *tt = urb->dev->tt->hub; dev_dbg(&tt->dev, "clear tt buffer port %d, a%d ep%d t%08x\n", urb->dev->ttport, urb->dev->devnum, usb_pipeendpoint(urb->pipe), token); -#endif /* DEBUG */ +#endif /* CONFIG_DYNAMIC_DEBUG */ if (!ehci_is_TDI(ehci) || urb->dev->tt->hub != ehci_to_hcd(ehci)->self.root_hub) { @@ -240,13 +240,6 @@ static int qtd_copy_status ( } else { /* unknown */ status = -EPROTO; } - - ehci_vdbg (ehci, - "dev%d ep%d%s qtd token %08x --> status %d\n", - usb_pipedevice (urb->pipe), - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - token, status); } return status; @@ -254,8 +247,6 @@ static int qtd_copy_status ( static void ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) -__releases(ehci->lock) -__acquires(ehci->lock) { if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { /* ... update hc-wide periodic stats */ @@ -281,11 +272,8 @@ __acquires(ehci->lock) urb->actual_length, urb->transfer_buffer_length); #endif - /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); - spin_unlock (&ehci->lock); usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); - spin_lock (&ehci->lock); } static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -809,26 +797,35 @@ qh_make ( * For control/bulk requests, the HC or TT handles these. */ if (type == PIPE_INTERRUPT) { - qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + unsigned tmp; + + qh->ps.usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, is_input, 0, hb_mult(maxp) * max_packet(maxp))); - qh->start = NO_FRAME; + qh->ps.phase = NO_FRAME; if (urb->dev->speed == USB_SPEED_HIGH) { - qh->c_usecs = 0; + qh->ps.c_usecs = 0; qh->gap_uf = 0; - qh->period = urb->interval >> 3; - if (qh->period == 0 && urb->interval != 1) { + if (urb->interval > 1 && urb->interval < 8) { /* NOTE interval 2 or 4 uframes could work. * But interval 1 scheduling is simpler, and * includes high bandwidth. */ urb->interval = 1; - } else if (qh->period > ehci->periodic_size) { - qh->period = ehci->periodic_size; - urb->interval = qh->period << 3; + } else if (urb->interval > ehci->periodic_size << 3) { + urb->interval = ehci->periodic_size << 3; } + qh->ps.period = urb->interval >> 3; + + /* period for bandwidth allocation */ + tmp = min_t(unsigned, EHCI_BANDWIDTH_SIZE, + 1 << (urb->ep->desc.bInterval - 1)); + + /* Allow urb->interval to override */ + qh->ps.bw_uperiod = min_t(unsigned, tmp, urb->interval); + qh->ps.bw_period = qh->ps.bw_uperiod >> 3; } else { int think_time; @@ -838,27 +835,35 @@ qh_make ( /* FIXME this just approximates SPLIT/CSPLIT times */ if (is_input) { // SPLIT, gap, CSPLIT+DATA - qh->c_usecs = qh->usecs + HS_USECS (0); - qh->usecs = HS_USECS (1); + qh->ps.c_usecs = qh->ps.usecs + HS_USECS(0); + qh->ps.usecs = HS_USECS(1); } else { // SPLIT+DATA, gap, CSPLIT - qh->usecs += HS_USECS (1); - qh->c_usecs = HS_USECS (0); + qh->ps.usecs += HS_USECS(1); + qh->ps.c_usecs = HS_USECS(0); } think_time = tt ? tt->think_time : 0; - qh->tt_usecs = NS_TO_US (think_time + + qh->ps.tt_usecs = NS_TO_US(think_time + usb_calc_bus_time (urb->dev->speed, is_input, 0, max_packet (maxp))); - qh->period = urb->interval; - if (qh->period > ehci->periodic_size) { - qh->period = ehci->periodic_size; - urb->interval = qh->period; - } + if (urb->interval > ehci->periodic_size) + urb->interval = ehci->periodic_size; + qh->ps.period = urb->interval; + + /* period for bandwidth allocation */ + tmp = min_t(unsigned, EHCI_BANDWIDTH_FRAMES, + urb->ep->desc.bInterval); + tmp = rounddown_pow_of_two(tmp); + + /* Allow urb->interval to override */ + qh->ps.bw_period = min_t(unsigned, tmp, urb->interval); + qh->ps.bw_uperiod = qh->ps.bw_period << 3; } } /* support for tt scheduling, and access to toggles */ - qh->dev = urb->dev; + qh->ps.udev = urb->dev; + qh->ps.ep = urb->ep; /* using TT? */ switch (urb->dev->speed) { @@ -1144,6 +1149,109 @@ submit_async ( } /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_HCD_TEST_MODE +/* + * This function creates the qtds and submits them for the + * SINGLE_STEP_SET_FEATURE Test. + * This is done in two parts: first SETUP req for GetDesc is sent then + * 15 seconds later, the IN stage for GetDesc starts to req data from dev + * + * is_setup : i/p arguement decides which of the two stage needs to be + * performed; TRUE - SETUP and FALSE - IN+STATUS + * Returns 0 if success + */ +static int submit_single_step_set_feature( + struct usb_hcd *hcd, + struct urb *urb, + int is_setup +) { + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct list_head qtd_list; + struct list_head *head; + + struct ehci_qtd *qtd, *qtd_prev; + dma_addr_t buf; + int len, maxpacket; + u32 token; + + INIT_LIST_HEAD(&qtd_list); + head = &qtd_list; + + /* URBs map to sequences of QTDs: one logical transaction */ + qtd = ehci_qtd_alloc(ehci, GFP_KERNEL); + if (unlikely(!qtd)) + return -1; + list_add_tail(&qtd->qtd_list, head); + qtd->urb = urb; + + token = QTD_STS_ACTIVE; + token |= (EHCI_TUNE_CERR << 10); + + len = urb->transfer_buffer_length; + /* + * Check if the request is to perform just the SETUP stage (getDesc) + * as in SINGLE_STEP_SET_FEATURE test, DATA stage (IN) happens + * 15 secs after the setup + */ + if (is_setup) { + /* SETUP pid */ + qtd_fill(ehci, qtd, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + token | (2 /* "setup" */ << 8), 8); + + submit_async(ehci, urb, &qtd_list, GFP_ATOMIC); + return 0; /*Return now; we shall come back after 15 seconds*/ + } + + /* + * IN: data transfer stage: buffer setup : start the IN txn phase for + * the get_Desc SETUP which was sent 15seconds back + */ + token ^= QTD_TOGGLE; /*We need to start IN with DATA-1 Pid-sequence*/ + buf = urb->transfer_dma; + + token |= (1 /* "in" */ << 8); /*This is IN stage*/ + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, 0)); + + qtd_fill(ehci, qtd, buf, len, token, maxpacket); + + /* + * Our IN phase shall always be a short read; so keep the queue running + * and let it advance to the next qtd which zero length OUT status + */ + qtd->hw_alt_next = EHCI_LIST_END(ehci); + + /* STATUS stage for GetDesc control request */ + token ^= 0x0100; /* "in" <--> "out" */ + token |= QTD_TOGGLE; /* force DATA1 */ + + qtd_prev = qtd; + qtd = ehci_qtd_alloc(ehci, GFP_ATOMIC); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + + /* dont fill any data in such packets */ + qtd_fill(ehci, qtd, 0, 0, token, 0); + + /* by default, enable interrupt on urb completion */ + if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) + qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC); + + submit_async(ehci, urb, &qtd_list, GFP_KERNEL); + + return 0; + +cleanup: + qtd_list_free(ehci, urb, head); + return -1; +} +#endif /* CONFIG_USB_HCD_TEST_MODE */ + +/*-------------------------------------------------------------------------*/ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) { diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c deleted file mode 100644 index 379037f51a2..00000000000 --- a/drivers/usb/host/ehci-s5p.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * SAMSUNG S5P USB HOST EHCI Controller - * - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Author: Jingoo Han <jg1.han@samsung.com> - * Author: Joonyoung Shim <jy0922.shim@samsung.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; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> -#include <linux/platform_data/usb-ehci-s5p.h> -#include <linux/usb/phy.h> -#include <linux/usb/samsung_usb_phy.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> -#include <linux/usb/otg.h> - -#include "ehci.h" - -#define DRIVER_DESC "EHCI s5p driver" - -#define EHCI_INSNREG00(base) (base + 0x90) -#define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25) -#define EHCI_INSNREG00_ENA_INCR8 (0x1 << 24) -#define EHCI_INSNREG00_ENA_INCR4 (0x1 << 23) -#define EHCI_INSNREG00_ENA_INCRX_ALIGN (0x1 << 22) -#define EHCI_INSNREG00_ENABLE_DMA_BURST \ - (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \ - EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) - -static const char hcd_name[] = "ehci-s5p"; -static struct hc_driver __read_mostly s5p_ehci_hc_driver; - -struct s5p_ehci_hcd { - struct clk *clk; - struct usb_phy *phy; - struct usb_otg *otg; - struct s5p_ehci_platdata *pdata; -}; - -#define to_s5p_ehci(hcd) (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv) - -static void s5p_setup_vbus_gpio(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int err; - int gpio; - - if (!dev->of_node) - return; - - gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0); - if (!gpio_is_valid(gpio)) - return; - - err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, - "ehci_vbus_gpio"); - if (err) - dev_err(dev, "can't request ehci vbus gpio %d", gpio); -} - -static int s5p_ehci_probe(struct platform_device *pdev) -{ - struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; - struct s5p_ehci_hcd *s5p_ehci; - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res; - struct usb_phy *phy; - int irq; - int err; - - /* - * 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 move to full device tree support this will vanish off. - */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - - s5p_setup_vbus_gpio(pdev); - - hcd = usb_create_hcd(&s5p_ehci_hc_driver, - &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - return -ENOMEM; - } - s5p_ehci = to_s5p_ehci(hcd); - phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR(phy)) { - /* Fallback to pdata */ - if (!pdata) { - usb_put_hcd(hcd); - dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; - } else { - s5p_ehci->pdata = pdata; - } - } else { - s5p_ehci->phy = phy; - s5p_ehci->otg = phy->otg; - } - - s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); - - if (IS_ERR(s5p_ehci->clk)) { - dev_err(&pdev->dev, "Failed to get usbhost clock\n"); - err = PTR_ERR(s5p_ehci->clk); - goto fail_clk; - } - - err = clk_prepare_enable(s5p_ehci->clk); - if (err) - goto fail_clk; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get I/O memory\n"); - err = -ENXIO; - goto fail_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to remap I/O memory\n"); - err = -ENOMEM; - goto fail_io; - } - - irq = platform_get_irq(pdev, 0); - if (!irq) { - dev_err(&pdev->dev, "Failed to get IRQ\n"); - err = -ENODEV; - goto fail_io; - } - - if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - - if (s5p_ehci->phy) - usb_phy_init(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_init) - s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); - - ehci = hcd_to_ehci(hcd); - ehci->caps = hcd->regs; - - /* DMA burst Enable */ - writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); - - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) { - dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto fail_add_hcd; - } - - platform_set_drvdata(pdev, hcd); - - return 0; - -fail_add_hcd: - if (s5p_ehci->phy) - usb_phy_shutdown(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_exit) - s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); -fail_io: - clk_disable_unprepare(s5p_ehci->clk); -fail_clk: - usb_put_hcd(hcd); - return err; -} - -static int s5p_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); - - usb_remove_hcd(hcd); - - if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - - if (s5p_ehci->phy) - usb_phy_shutdown(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_exit) - s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); - - clk_disable_unprepare(s5p_ehci->clk); - - usb_put_hcd(hcd); - - return 0; -} - -static void s5p_ehci_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -#ifdef CONFIG_PM -static int s5p_ehci_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); - struct platform_device *pdev = to_platform_device(dev); - - bool do_wakeup = device_may_wakeup(dev); - int rc; - - rc = ehci_suspend(hcd, do_wakeup); - - if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - - if (s5p_ehci->phy) - usb_phy_shutdown(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_exit) - s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); - - clk_disable_unprepare(s5p_ehci->clk); - - return rc; -} - -static int s5p_ehci_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); - struct platform_device *pdev = to_platform_device(dev); - - clk_prepare_enable(s5p_ehci->clk); - - if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - - if (s5p_ehci->phy) - usb_phy_init(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_init) - s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); - - /* DMA burst Enable */ - writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); - - ehci_resume(hcd, false); - return 0; -} -#else -#define s5p_ehci_suspend NULL -#define s5p_ehci_resume NULL -#endif - -static const struct dev_pm_ops s5p_ehci_pm_ops = { - .suspend = s5p_ehci_suspend, - .resume = s5p_ehci_resume, -}; - -#ifdef CONFIG_OF -static const struct of_device_id exynos_ehci_match[] = { - { .compatible = "samsung,exynos4210-ehci" }, - {}, -}; -MODULE_DEVICE_TABLE(of, exynos_ehci_match); -#endif - -static struct platform_driver s5p_ehci_driver = { - .probe = s5p_ehci_probe, - .remove = s5p_ehci_remove, - .shutdown = s5p_ehci_shutdown, - .driver = { - .name = "s5p-ehci", - .owner = THIS_MODULE, - .pm = &s5p_ehci_pm_ops, - .of_match_table = of_match_ptr(exynos_ehci_match), - } -}; -static const struct ehci_driver_overrides s5p_overrides __initdata = { - .extra_priv_size = sizeof(struct s5p_ehci_hcd), -}; - -static int __init ehci_s5p_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&s5p_ehci_hc_driver, &s5p_overrides); - return platform_driver_register(&s5p_ehci_driver); -} -module_init(ehci_s5p_init); - -static void __exit ehci_s5p_cleanup(void) -{ - platform_driver_unregister(&s5p_ehci_driver); -} -module_exit(ehci_s5p_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_ALIAS("platform:s5p-ehci"); -MODULE_AUTHOR("Jingoo Han"); -MODULE_AUTHOR("Joonyoung Shim"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index f80d0330d54..e113fd73aea 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -103,83 +103,210 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); else - *hw_p = ehci->dummy->qh_dma; + *hw_p = cpu_to_hc32(ehci, ehci->dummy->qh_dma); } -/* how many of the uframe's 125 usecs are allocated? */ -static unsigned short -periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) +/*-------------------------------------------------------------------------*/ + +/* Bandwidth and TT management */ + +/* Find the TT data structure for this device; create it if necessary */ +static struct ehci_tt *find_tt(struct usb_device *udev) { - __hc32 *hw_p = &ehci->periodic [frame]; - union ehci_shadow *q = &ehci->pshadow [frame]; - unsigned usecs = 0; - struct ehci_qh_hw *hw; - - while (q->ptr) { - switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { - case Q_TYPE_QH: - hw = q->qh->hw; - /* is it in the S-mask? */ - if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) - usecs += q->qh->usecs; - /* ... or C-mask? */ - if (hw->hw_info2 & cpu_to_hc32(ehci, - 1 << (8 + uframe))) - usecs += q->qh->c_usecs; - hw_p = &hw->hw_next; - q = &q->qh->qh_next; - break; - // case Q_TYPE_FSTN: - default: - /* for "save place" FSTNs, count the relevant INTR - * bandwidth from the previous frame - */ - if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) { - ehci_dbg (ehci, "ignoring FSTN cost ...\n"); - } - hw_p = &q->fstn->hw_next; - q = &q->fstn->fstn_next; - break; - case Q_TYPE_ITD: - if (q->itd->hw_transaction[uframe]) - usecs += q->itd->stream->usecs; - hw_p = &q->itd->hw_next; - q = &q->itd->itd_next; - break; - case Q_TYPE_SITD: - /* is it in the S-mask? (count SPLIT, DATA) */ - if (q->sitd->hw_uframe & cpu_to_hc32(ehci, - 1 << uframe)) { - if (q->sitd->hw_fullspeed_ep & - cpu_to_hc32(ehci, 1<<31)) - usecs += q->sitd->stream->usecs; - else /* worst case for OUT start-split */ - usecs += HS_USECS_ISO (188); - } + struct usb_tt *utt = udev->tt; + struct ehci_tt *tt, **tt_index, **ptt; + unsigned port; + bool allocated_index = false; + + if (!utt) + return NULL; /* Not below a TT */ - /* ... C-mask? (count CSPLIT, DATA) */ - if (q->sitd->hw_uframe & - cpu_to_hc32(ehci, 1 << (8 + uframe))) { - /* worst case for IN complete-split */ - usecs += q->sitd->stream->c_usecs; + /* + * Find/create our data structure. + * For hubs with a single TT, we get it directly. + * For hubs with multiple TTs, there's an extra level of pointers. + */ + tt_index = NULL; + if (utt->multi) { + tt_index = utt->hcpriv; + if (!tt_index) { /* Create the index array */ + tt_index = kzalloc(utt->hub->maxchild * + sizeof(*tt_index), GFP_ATOMIC); + if (!tt_index) + return ERR_PTR(-ENOMEM); + utt->hcpriv = tt_index; + allocated_index = true; + } + port = udev->ttport - 1; + ptt = &tt_index[port]; + } else { + port = 0; + ptt = (struct ehci_tt **) &utt->hcpriv; + } + + tt = *ptt; + if (!tt) { /* Create the ehci_tt */ + struct ehci_hcd *ehci = + hcd_to_ehci(bus_to_hcd(udev->bus)); + + tt = kzalloc(sizeof(*tt), GFP_ATOMIC); + if (!tt) { + if (allocated_index) { + utt->hcpriv = NULL; + kfree(tt_index); } + return ERR_PTR(-ENOMEM); + } + list_add_tail(&tt->tt_list, &ehci->tt_list); + INIT_LIST_HEAD(&tt->ps_list); + tt->usb_tt = utt; + tt->tt_port = port; + *ptt = tt; + } - hw_p = &q->sitd->hw_next; - q = &q->sitd->sitd_next; - break; + return tt; +} + +/* Release the TT above udev, if it's not in use */ +static void drop_tt(struct usb_device *udev) +{ + struct usb_tt *utt = udev->tt; + struct ehci_tt *tt, **tt_index, **ptt; + int cnt, i; + + if (!utt || !utt->hcpriv) + return; /* Not below a TT, or never allocated */ + + cnt = 0; + if (utt->multi) { + tt_index = utt->hcpriv; + ptt = &tt_index[udev->ttport - 1]; + + /* How many entries are left in tt_index? */ + for (i = 0; i < utt->hub->maxchild; ++i) + cnt += !!tt_index[i]; + } else { + tt_index = NULL; + ptt = (struct ehci_tt **) &utt->hcpriv; + } + + tt = *ptt; + if (!tt || !list_empty(&tt->ps_list)) + return; /* never allocated, or still in use */ + + list_del(&tt->tt_list); + *ptt = NULL; + kfree(tt); + if (cnt == 1) { + utt->hcpriv = NULL; + kfree(tt_index); + } +} + +static void bandwidth_dbg(struct ehci_hcd *ehci, int sign, char *type, + struct ehci_per_sched *ps) +{ + dev_dbg(&ps->udev->dev, + "ep %02x: %s %s @ %u+%u (%u.%u+%u) [%u/%u us] mask %04x\n", + ps->ep->desc.bEndpointAddress, + (sign >= 0 ? "reserve" : "release"), type, + (ps->bw_phase << 3) + ps->phase_uf, ps->bw_uperiod, + ps->phase, ps->phase_uf, ps->period, + ps->usecs, ps->c_usecs, ps->cs_mask); +} + +static void reserve_release_intr_bandwidth(struct ehci_hcd *ehci, + struct ehci_qh *qh, int sign) +{ + unsigned start_uf; + unsigned i, j, m; + int usecs = qh->ps.usecs; + int c_usecs = qh->ps.c_usecs; + int tt_usecs = qh->ps.tt_usecs; + struct ehci_tt *tt; + + if (qh->ps.phase == NO_FRAME) /* Bandwidth wasn't reserved */ + return; + start_uf = qh->ps.bw_phase << 3; + + bandwidth_dbg(ehci, sign, "intr", &qh->ps); + + if (sign < 0) { /* Release bandwidth */ + usecs = -usecs; + c_usecs = -c_usecs; + tt_usecs = -tt_usecs; + } + + /* Entire transaction (high speed) or start-split (full/low speed) */ + for (i = start_uf + qh->ps.phase_uf; i < EHCI_BANDWIDTH_SIZE; + i += qh->ps.bw_uperiod) + ehci->bandwidth[i] += usecs; + + /* Complete-split (full/low speed) */ + if (qh->ps.c_usecs) { + /* NOTE: adjustments needed for FSTN */ + for (i = start_uf; i < EHCI_BANDWIDTH_SIZE; + i += qh->ps.bw_uperiod) { + for ((j = 2, m = 1 << (j+8)); j < 8; (++j, m <<= 1)) { + if (qh->ps.cs_mask & m) + ehci->bandwidth[i+j] += c_usecs; + } } } -#ifdef DEBUG - if (usecs > ehci->uframe_periodic_max) - ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", - frame * 8 + uframe, usecs); -#endif - return usecs; + + /* FS/LS bus bandwidth */ + if (tt_usecs) { + tt = find_tt(qh->ps.udev); + if (sign > 0) + list_add_tail(&qh->ps.ps_list, &tt->ps_list); + else + list_del(&qh->ps.ps_list); + + for (i = start_uf >> 3; i < EHCI_BANDWIDTH_FRAMES; + i += qh->ps.bw_period) + tt->bandwidth[i] += tt_usecs; + } } /*-------------------------------------------------------------------------*/ -static int same_tt (struct usb_device *dev1, struct usb_device *dev2) +static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE], + struct ehci_tt *tt) +{ + struct ehci_per_sched *ps; + unsigned uframe, uf, x; + u8 *budget_line; + + if (!tt) + return; + memset(budget_table, 0, EHCI_BANDWIDTH_SIZE); + + /* Add up the contributions from all the endpoints using this TT */ + list_for_each_entry(ps, &tt->ps_list, ps_list) { + for (uframe = ps->bw_phase << 3; uframe < EHCI_BANDWIDTH_SIZE; + uframe += ps->bw_uperiod) { + budget_line = &budget_table[uframe]; + x = ps->tt_usecs; + + /* propagate the time forward */ + for (uf = ps->phase_uf; uf < 8; ++uf) { + x += budget_line[uf]; + + /* Each microframe lasts 125 us */ + if (x <= 125) { + budget_line[uf] = x; + break; + } else { + budget_line[uf] = 125; + x -= 125; + } + } + } + } +} + +static int __maybe_unused same_tt(struct usb_device *dev1, + struct usb_device *dev2) { if (!dev1->tt || !dev2->tt) return 0; @@ -227,68 +354,6 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) } } -/* How many of the tt's periodic downstream 1000 usecs are allocated? - * - * While this measures the bandwidth in terms of usecs/uframe, - * the low/fullspeed bus has no notion of uframes, so any particular - * low/fullspeed transfer can "carry over" from one uframe to the next, - * since the TT just performs downstream transfers in sequence. - * - * For example two separate 100 usec transfers can start in the same uframe, - * and the second one would "carry over" 75 usecs into the next uframe. - */ -static void -periodic_tt_usecs ( - struct ehci_hcd *ehci, - struct usb_device *dev, - unsigned frame, - unsigned short tt_usecs[8] -) -{ - __hc32 *hw_p = &ehci->periodic [frame]; - union ehci_shadow *q = &ehci->pshadow [frame]; - unsigned char uf; - - memset(tt_usecs, 0, 16); - - while (q->ptr) { - switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { - case Q_TYPE_ITD: - hw_p = &q->itd->hw_next; - q = &q->itd->itd_next; - continue; - case Q_TYPE_QH: - if (same_tt(dev, q->qh->dev)) { - uf = tt_start_uframe(ehci, q->qh->hw->hw_info2); - tt_usecs[uf] += q->qh->tt_usecs; - } - hw_p = &q->qh->hw->hw_next; - q = &q->qh->qh_next; - continue; - case Q_TYPE_SITD: - if (same_tt(dev, q->sitd->urb->dev)) { - uf = tt_start_uframe(ehci, q->sitd->hw_uframe); - tt_usecs[uf] += q->sitd->stream->tt_usecs; - } - hw_p = &q->sitd->hw_next; - q = &q->sitd->sitd_next; - continue; - // case Q_TYPE_FSTN: - default: - ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n", - frame); - hw_p = &q->fstn->hw_next; - q = &q->fstn->fstn_next; - } - } - - carryover_tt_bandwidth(tt_usecs); - - if (max_tt_usecs[7] < tt_usecs[7]) - ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", - frame, tt_usecs[7] - max_tt_usecs[7]); -} - /* * Return true if the device's tt's downstream bus is available for a * periodic transfer of the specified length (usecs), starting at the @@ -312,32 +377,32 @@ periodic_tt_usecs ( */ static int tt_available ( struct ehci_hcd *ehci, - unsigned period, - struct usb_device *dev, + struct ehci_per_sched *ps, + struct ehci_tt *tt, unsigned frame, - unsigned uframe, - u16 usecs + unsigned uframe ) { + unsigned period = ps->bw_period; + unsigned usecs = ps->tt_usecs; + if ((period == 0) || (uframe >= 7)) /* error */ return 0; - for (; frame < ehci->periodic_size; frame += period) { - unsigned short tt_usecs[8]; + for (frame &= period - 1; frame < EHCI_BANDWIDTH_FRAMES; + frame += period) { + unsigned i, uf; + unsigned short tt_usecs[8]; - periodic_tt_usecs (ehci, dev, frame, tt_usecs); + if (tt->bandwidth[frame] + usecs > 900) + return 0; - ehci_vdbg(ehci, "tt frame %d check %d usecs start uframe %d in" - " schedule %d/%d/%d/%d/%d/%d/%d/%d\n", - frame, usecs, uframe, - tt_usecs[0], tt_usecs[1], tt_usecs[2], tt_usecs[3], - tt_usecs[4], tt_usecs[5], tt_usecs[6], tt_usecs[7]); + uf = frame << 3; + for (i = 0; i < 8; (++i, ++uf)) + tt_usecs[i] = ehci->tt_budget[uf]; - if (max_tt_usecs[uframe] <= tt_usecs[uframe]) { - ehci_vdbg(ehci, "frame %d uframe %d fully scheduled\n", - frame, uframe); + if (max_tt_usecs[uframe] <= tt_usecs[uframe]) return 0; - } /* special case for isoc transfers larger than 125us: * the first and each subsequent fully used uframe @@ -346,15 +411,10 @@ static int tt_available ( */ if (125 < usecs) { int ufs = (usecs / 125); - int i; + for (i = uframe; i < (uframe + ufs) && i < 8; i++) - if (0 < tt_usecs[i]) { - ehci_vdbg(ehci, - "multi-uframe xfer can't fit " - "in frame %d uframe %d\n", - frame, i); + if (0 < tt_usecs[i]) return 0; - } } tt_usecs[uframe] += usecs; @@ -362,12 +422,8 @@ static int tt_available ( carryover_tt_bandwidth(tt_usecs); /* fail if the carryover pushed bw past the last uframe's limit */ - if (max_tt_usecs[7] < tt_usecs[7]) { - ehci_vdbg(ehci, - "tt unavailable usecs %d frame %d uframe %d\n", - usecs, frame, uframe); + if (max_tt_usecs[7] < tt_usecs[7]) return 0; - } } return 1; @@ -409,7 +465,7 @@ static int tt_no_collision ( continue; case Q_TYPE_QH: hw = here.qh->hw; - if (same_tt (dev, here.qh->dev)) { + if (same_tt(dev, here.qh->ps.udev)) { u32 mask; mask = hc32_to_cpu(ehci, @@ -489,19 +545,19 @@ static void disable_periodic(struct ehci_hcd *ehci) static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) { unsigned i; - unsigned period = qh->period; + unsigned period = qh->ps.period; - dev_dbg (&qh->dev->dev, + dev_dbg(&qh->ps.udev->dev, "link qh%d-%04x/%p start %d [%d/%d us]\n", period, hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->start, qh->usecs, qh->c_usecs); + qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs); /* high bandwidth, or otherwise every microframe */ if (period == 0) period = 1; - for (i = qh->start; i < ehci->periodic_size; i += period) { + for (i = qh->ps.phase; i < ehci->periodic_size; i += period) { union ehci_shadow *prev = &ehci->pshadow[i]; __hc32 *hw_p = &ehci->periodic[i]; union ehci_shadow here = *prev; @@ -521,7 +577,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) * enables sharing interior tree nodes */ while (here.ptr && qh != here.qh) { - if (qh->period > here.qh->period) + if (qh->ps.period > here.qh->ps.period) break; prev = &here.qh->qh_next; hw_p = &here.qh->hw->hw_next; @@ -541,10 +597,10 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) qh->xacterrs = 0; qh->exception = 0; - /* update per-qh bandwidth for usbfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); + /* update per-qh bandwidth for debugfs */ + ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->ps.bw_period + ? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.bw_period) + : (qh->ps.usecs * 8); list_add(&qh->intr_node, &ehci->intr_qh_list); @@ -574,22 +630,21 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) */ /* high bandwidth, or otherwise part of every microframe */ - if ((period = qh->period) == 0) - period = 1; + period = qh->ps.period ? : 1; - for (i = qh->start; i < ehci->periodic_size; i += period) + for (i = qh->ps.phase; i < ehci->periodic_size; i += period) periodic_unlink (ehci, i, qh); - /* update per-qh bandwidth for usbfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); + /* update per-qh bandwidth for debugfs */ + ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->ps.bw_period + ? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.bw_period) + : (qh->ps.usecs * 8); - dev_dbg (&qh->dev->dev, + dev_dbg(&qh->ps.udev->dev, "unlink qh%d-%04x/%p start %d [%d/%d us]\n", - qh->period, + qh->ps.period, hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->start, qh->usecs, qh->c_usecs); + qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs); /* qh->qh_next still "live" to HC */ qh->qh_state = QH_STATE_UNLINK; @@ -601,12 +656,29 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) list_del(&qh->intr_node); } +static void cancel_unlink_wait_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + if (qh->qh_state != QH_STATE_LINKED || + list_empty(&qh->unlink_node)) + return; + + list_del_init(&qh->unlink_node); + + /* + * TODO: disable the event of EHCI_HRTIMER_START_UNLINK_INTR for + * avoiding unnecessary CPU wakeup + */ +} + static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) { /* If the QH isn't linked then there's nothing we can do. */ if (qh->qh_state != QH_STATE_LINKED) return; + /* if the qh is waiting for unlink, cancel it now */ + cancel_unlink_wait_intr(ehci, qh); + qh_unlink_periodic (ehci, qh); /* Make sure the unlinks are visible before starting the timer */ @@ -632,6 +704,27 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) } } +/* + * It is common only one intr URB is scheduled on one qh, and + * given complete() is run in tasklet context, introduce a bit + * delay to avoid unlink qh too early. + */ +static void start_unlink_intr_wait(struct ehci_hcd *ehci, + struct ehci_qh *qh) +{ + qh->unlink_cycle = ehci->intr_unlink_wait_cycle; + + /* New entries go at the end of the intr_unlink_wait list */ + list_add_tail(&qh->unlink_node, &ehci->intr_unlink_wait); + + if (ehci->rh_state < EHCI_RH_RUNNING) + ehci_handle_start_intr_unlinks(ehci); + else if (ehci->intr_unlink_wait.next == &qh->unlink_node) { + ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true); + ++ehci->intr_unlink_wait_cycle; + } +} + static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qh_hw *hw = qh->hw; @@ -674,11 +767,9 @@ static int check_period ( struct ehci_hcd *ehci, unsigned frame, unsigned uframe, - unsigned period, + unsigned uperiod, unsigned usecs ) { - int claimed; - /* complete split running into next frame? * given FSTN support, we could sometimes check... */ @@ -688,25 +779,10 @@ static int check_period ( /* convert "usecs we need" to "max already claimed" */ usecs = ehci->uframe_periodic_max - usecs; - /* we "know" 2 and 4 uframe intervals were rejected; so - * for period 0, check _every_ microframe in the schedule. - */ - if (unlikely (period == 0)) { - do { - for (uframe = 0; uframe < 7; uframe++) { - claimed = periodic_usecs (ehci, frame, uframe); - if (claimed > usecs) - return 0; - } - } while ((frame += 1) < ehci->periodic_size); - - /* just check the specified uframe, at that period */ - } else { - do { - claimed = periodic_usecs (ehci, frame, uframe); - if (claimed > usecs) - return 0; - } while ((frame += period) < ehci->periodic_size); + for (uframe += frame << 3; uframe < EHCI_BANDWIDTH_SIZE; + uframe += uperiod) { + if (ehci->bandwidth[uframe] > usecs) + return 0; } // success! @@ -717,40 +793,40 @@ static int check_intr_schedule ( struct ehci_hcd *ehci, unsigned frame, unsigned uframe, - const struct ehci_qh *qh, - __hc32 *c_maskp + struct ehci_qh *qh, + unsigned *c_maskp, + struct ehci_tt *tt ) { int retval = -ENOSPC; u8 mask = 0; - if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ + if (qh->ps.c_usecs && uframe >= 6) /* FSTN territory? */ goto done; - if (!check_period (ehci, frame, uframe, qh->period, qh->usecs)) + if (!check_period(ehci, frame, uframe, qh->ps.bw_uperiod, qh->ps.usecs)) goto done; - if (!qh->c_usecs) { + if (!qh->ps.c_usecs) { retval = 0; *c_maskp = 0; goto done; } #ifdef CONFIG_USB_EHCI_TT_NEWSCHED - if (tt_available (ehci, qh->period, qh->dev, frame, uframe, - qh->tt_usecs)) { + if (tt_available(ehci, &qh->ps, tt, frame, uframe)) { unsigned i; /* TODO : this may need FSTN for SSPLIT in uframe 5. */ - for (i=uframe+1; i<8 && i<uframe+4; i++) - if (!check_period (ehci, frame, i, - qh->period, qh->c_usecs)) + for (i = uframe+2; i < 8 && i <= uframe+4; i++) + if (!check_period(ehci, frame, i, + qh->ps.bw_uperiod, qh->ps.c_usecs)) goto done; else mask |= 1 << i; retval = 0; - *c_maskp = cpu_to_hc32(ehci, mask << 8); + *c_maskp = mask; } #else /* Make sure this tt's buffer is also available for CSPLITs. @@ -761,15 +837,15 @@ static int check_intr_schedule ( * one smart pass... */ mask = 0x03 << (uframe + qh->gap_uf); - *c_maskp = cpu_to_hc32(ehci, mask << 8); + *c_maskp = mask; mask |= 1 << uframe; - if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) { - if (!check_period (ehci, frame, uframe + qh->gap_uf + 1, - qh->period, qh->c_usecs)) + if (tt_no_collision(ehci, qh->ps.bw_period, qh->ps.udev, frame, mask)) { + if (!check_period(ehci, frame, uframe + qh->gap_uf + 1, + qh->ps.bw_uperiod, qh->ps.c_usecs)) goto done; - if (!check_period (ehci, frame, uframe + qh->gap_uf, - qh->period, qh->c_usecs)) + if (!check_period(ehci, frame, uframe + qh->gap_uf, + qh->ps.bw_uperiod, qh->ps.c_usecs)) goto done; retval = 0; } @@ -783,62 +859,67 @@ done: */ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) { - int status; + int status = 0; unsigned uframe; - __hc32 c_mask; - unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ + unsigned c_mask; struct ehci_qh_hw *hw = qh->hw; + struct ehci_tt *tt; hw->hw_next = EHCI_LIST_END(ehci); - frame = qh->start; /* reuse the previous schedule slots, if we can */ - if (frame < qh->period) { - uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK); - status = check_intr_schedule (ehci, frame, --uframe, - qh, &c_mask); - } else { - uframe = 0; - c_mask = 0; - status = -ENOSPC; + if (qh->ps.phase != NO_FRAME) { + ehci_dbg(ehci, "reused qh %p schedule\n", qh); + return 0; + } + + uframe = 0; + c_mask = 0; + tt = find_tt(qh->ps.udev); + if (IS_ERR(tt)) { + status = PTR_ERR(tt); + goto done; } + compute_tt_budget(ehci->tt_budget, tt); /* else scan the schedule to find a group of slots such that all * uframes have enough periodic bandwidth available. */ - if (status) { - /* "normal" case, uframing flexible except with splits */ - if (qh->period) { - int i; - - for (i = qh->period; status && i > 0; --i) { - frame = ++ehci->random_frame % qh->period; - for (uframe = 0; uframe < 8; uframe++) { - status = check_intr_schedule (ehci, - frame, uframe, qh, - &c_mask); - if (status == 0) - break; - } + /* "normal" case, uframing flexible except with splits */ + if (qh->ps.bw_period) { + int i; + unsigned frame; + + for (i = qh->ps.bw_period; i > 0; --i) { + frame = ++ehci->random_frame & (qh->ps.bw_period - 1); + for (uframe = 0; uframe < 8; uframe++) { + status = check_intr_schedule(ehci, + frame, uframe, qh, &c_mask, tt); + if (status == 0) + goto got_it; } - - /* qh->period == 0 means every uframe */ - } else { - frame = 0; - status = check_intr_schedule (ehci, 0, 0, qh, &c_mask); } - if (status) - goto done; - qh->start = frame; - /* reset S-frame and (maybe) C-frame masks */ - hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); - hw->hw_info2 |= qh->period - ? cpu_to_hc32(ehci, 1 << uframe) - : cpu_to_hc32(ehci, QH_SMASK); - hw->hw_info2 |= c_mask; - } else - ehci_dbg (ehci, "reused qh %p schedule\n", qh); + /* qh->ps.bw_period == 0 means every uframe */ + } else { + status = check_intr_schedule(ehci, 0, 0, qh, &c_mask, tt); + } + if (status) + goto done; + + got_it: + qh->ps.phase = (qh->ps.period ? ehci->random_frame & + (qh->ps.period - 1) : 0); + qh->ps.bw_phase = qh->ps.phase & (qh->ps.bw_period - 1); + qh->ps.phase_uf = uframe; + qh->ps.cs_mask = qh->ps.period ? + (c_mask << 8) | (1 << uframe) : + QH_SMASK; + + /* reset S-frame and (maybe) C-frame masks */ + hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); + hw->hw_info2 |= cpu_to_hc32(ehci, qh->ps.cs_mask); + reserve_release_intr_bandwidth(ehci, qh, 1); done: return status; @@ -889,6 +970,9 @@ static int intr_submit ( if (qh->qh_state == QH_STATE_IDLE) { qh_refresh(ehci, qh); qh_link_periodic(ehci, qh); + } else { + /* cancel unlink wait for the qh */ + cancel_unlink_wait_intr(ehci, qh); } /* ... update usbfs periodic stats */ @@ -924,9 +1008,11 @@ static void scan_intr(struct ehci_hcd *ehci) * in qh_unlink_periodic(). */ temp = qh_completions(ehci, qh); - if (unlikely(temp || (list_empty(&qh->qtd_list) && - qh->qh_state == QH_STATE_LINKED))) + if (unlikely(temp)) start_unlink_intr(ehci, qh); + else if (unlikely(list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED)) + start_unlink_intr_wait(ehci, qh); } } } @@ -944,7 +1030,8 @@ iso_stream_alloc (gfp_t mem_flags) if (likely (stream != NULL)) { INIT_LIST_HEAD(&stream->td_list); INIT_LIST_HEAD(&stream->free_list); - stream->next_uframe = -1; + stream->next_uframe = NO_FRAME; + stream->ps.phase = NO_FRAME; } return stream; } @@ -953,25 +1040,24 @@ static void iso_stream_init ( struct ehci_hcd *ehci, struct ehci_iso_stream *stream, - struct usb_device *dev, - int pipe, - unsigned interval + struct urb *urb ) { static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f }; + struct usb_device *dev = urb->dev; u32 buf1; unsigned epnum, maxp; int is_input; - long bandwidth; + unsigned tmp; /* * this might be a "high bandwidth" highspeed endpoint, * as encoded in the ep descriptor's wMaxPacket field */ - epnum = usb_pipeendpoint (pipe); - is_input = usb_pipein (pipe) ? USB_DIR_IN : 0; - maxp = usb_maxpacket(dev, pipe, !is_input); + epnum = usb_pipeendpoint(urb->pipe); + is_input = usb_pipein(urb->pipe) ? USB_DIR_IN : 0; + maxp = usb_endpoint_maxp(&urb->ep->desc); if (is_input) { buf1 = (1 << 11); } else { @@ -995,9 +1081,19 @@ iso_stream_init ( /* usbfs wants to report the average usecs per frame tied up * when transfers on this endpoint are scheduled ... */ - stream->usecs = HS_USECS_ISO (maxp); - bandwidth = stream->usecs * 8; - bandwidth /= interval; + stream->ps.usecs = HS_USECS_ISO(maxp); + + /* period for bandwidth allocation */ + tmp = min_t(unsigned, EHCI_BANDWIDTH_SIZE, + 1 << (urb->ep->desc.bInterval - 1)); + + /* Allow urb->interval to override */ + stream->ps.bw_uperiod = min_t(unsigned, tmp, urb->interval); + + stream->uperiod = urb->interval; + stream->ps.period = urb->interval >> 3; + stream->bandwidth = stream->ps.usecs * 8 / + stream->ps.bw_uperiod; } else { u32 addr; @@ -1011,36 +1107,46 @@ iso_stream_init ( addr |= dev->tt->hub->devnum << 16; addr |= epnum << 8; addr |= dev->devnum; - stream->usecs = HS_USECS_ISO (maxp); + stream->ps.usecs = HS_USECS_ISO(maxp); think_time = dev->tt ? dev->tt->think_time : 0; - stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time ( + stream->ps.tt_usecs = NS_TO_US(think_time + usb_calc_bus_time( dev->speed, is_input, 1, maxp)); hs_transfers = max (1u, (maxp + 187) / 188); if (is_input) { u32 tmp; addr |= 1 << 31; - stream->c_usecs = stream->usecs; - stream->usecs = HS_USECS_ISO (1); - stream->raw_mask = 1; + stream->ps.c_usecs = stream->ps.usecs; + stream->ps.usecs = HS_USECS_ISO(1); + stream->ps.cs_mask = 1; /* c-mask as specified in USB 2.0 11.18.4 3.c */ tmp = (1 << (hs_transfers + 2)) - 1; - stream->raw_mask |= tmp << (8 + 2); + stream->ps.cs_mask |= tmp << (8 + 2); } else - stream->raw_mask = smask_out [hs_transfers - 1]; - bandwidth = stream->usecs + stream->c_usecs; - bandwidth /= interval << 3; + stream->ps.cs_mask = smask_out[hs_transfers - 1]; - /* stream->splits gets created from raw_mask later */ + /* period for bandwidth allocation */ + tmp = min_t(unsigned, EHCI_BANDWIDTH_FRAMES, + 1 << (urb->ep->desc.bInterval - 1)); + + /* Allow urb->interval to override */ + stream->ps.bw_period = min_t(unsigned, tmp, urb->interval); + stream->ps.bw_uperiod = stream->ps.bw_period << 3; + + stream->ps.period = urb->interval; + stream->uperiod = urb->interval << 3; + stream->bandwidth = (stream->ps.usecs + stream->ps.c_usecs) / + stream->ps.bw_period; + + /* stream->splits gets created from cs_mask later */ stream->address = cpu_to_hc32(ehci, addr); } - stream->bandwidth = bandwidth; - stream->udev = dev; + stream->ps.udev = dev; + stream->ps.ep = urb->ep; stream->bEndpointAddress = is_input | epnum; - stream->interval = interval; stream->maxp = maxp; } @@ -1065,9 +1171,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) stream = iso_stream_alloc(GFP_ATOMIC); if (likely (stream != NULL)) { ep->hcpriv = stream; - stream->ep = ep; - iso_stream_init(ehci, stream, urb->dev, urb->pipe, - urb->interval); + iso_stream_init(ehci, stream, urb); } /* if dev->ep [epnum] is a QH, hw is set */ @@ -1112,7 +1216,7 @@ itd_sched_init( dma_addr_t dma = urb->transfer_dma; /* how many uframes are needed for these transfers */ - iso_sched->span = urb->number_of_packets * stream->interval; + iso_sched->span = urb->number_of_packets * stream->uperiod; /* figure out per-uframe itd fields that we'll need later * when we fit new itds into the schedule. @@ -1211,7 +1315,7 @@ itd_urb_transaction ( memset (itd, 0, sizeof *itd); itd->itd_dma = itd_dma; - itd->frame = 9999; /* an invalid value */ + itd->frame = NO_FRAME; list_add (&itd->itd_list, &sched->td_list); } spin_unlock_irqrestore (&ehci->lock, flags); @@ -1224,49 +1328,106 @@ itd_urb_transaction ( /*-------------------------------------------------------------------------*/ +static void reserve_release_iso_bandwidth(struct ehci_hcd *ehci, + struct ehci_iso_stream *stream, int sign) +{ + unsigned uframe; + unsigned i, j; + unsigned s_mask, c_mask, m; + int usecs = stream->ps.usecs; + int c_usecs = stream->ps.c_usecs; + int tt_usecs = stream->ps.tt_usecs; + struct ehci_tt *tt; + + if (stream->ps.phase == NO_FRAME) /* Bandwidth wasn't reserved */ + return; + uframe = stream->ps.bw_phase << 3; + + bandwidth_dbg(ehci, sign, "iso", &stream->ps); + + if (sign < 0) { /* Release bandwidth */ + usecs = -usecs; + c_usecs = -c_usecs; + tt_usecs = -tt_usecs; + } + + if (!stream->splits) { /* High speed */ + for (i = uframe + stream->ps.phase_uf; i < EHCI_BANDWIDTH_SIZE; + i += stream->ps.bw_uperiod) + ehci->bandwidth[i] += usecs; + + } else { /* Full speed */ + s_mask = stream->ps.cs_mask; + c_mask = s_mask >> 8; + + /* NOTE: adjustment needed for frame overflow */ + for (i = uframe; i < EHCI_BANDWIDTH_SIZE; + i += stream->ps.bw_uperiod) { + for ((j = stream->ps.phase_uf, m = 1 << j); j < 8; + (++j, m <<= 1)) { + if (s_mask & m) + ehci->bandwidth[i+j] += usecs; + else if (c_mask & m) + ehci->bandwidth[i+j] += c_usecs; + } + } + + tt = find_tt(stream->ps.udev); + if (sign > 0) + list_add_tail(&stream->ps.ps_list, &tt->ps_list); + else + list_del(&stream->ps.ps_list); + + for (i = uframe >> 3; i < EHCI_BANDWIDTH_FRAMES; + i += stream->ps.bw_period) + tt->bandwidth[i] += tt_usecs; + } +} + static inline int itd_slot_ok ( struct ehci_hcd *ehci, - u32 mod, - u32 uframe, - u8 usecs, - u32 period + struct ehci_iso_stream *stream, + unsigned uframe ) { - uframe %= period; - do { - /* can't commit more than uframe_periodic_max usec */ - if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) - > (ehci->uframe_periodic_max - usecs)) - return 0; + unsigned usecs; + + /* convert "usecs we need" to "max already claimed" */ + usecs = ehci->uframe_periodic_max - stream->ps.usecs; - /* we know urb->interval is 2^N uframes */ - uframe += period; - } while (uframe < mod); + for (uframe &= stream->ps.bw_uperiod - 1; uframe < EHCI_BANDWIDTH_SIZE; + uframe += stream->ps.bw_uperiod) { + if (ehci->bandwidth[uframe] > usecs) + return 0; + } return 1; } static inline int sitd_slot_ok ( struct ehci_hcd *ehci, - u32 mod, struct ehci_iso_stream *stream, - u32 uframe, + unsigned uframe, struct ehci_iso_sched *sched, - u32 period_uframes + struct ehci_tt *tt ) { - u32 mask, tmp; - u32 frame, uf; + unsigned mask, tmp; + unsigned frame, uf; - mask = stream->raw_mask << (uframe & 7); + mask = stream->ps.cs_mask << (uframe & 7); + + /* for OUT, don't wrap SSPLIT into H-microframe 7 */ + if (((stream->ps.cs_mask & 0xff) << (uframe & 7)) >= (1 << 7)) + return 0; /* for IN, don't wrap CSPLIT into the next frame */ if (mask & ~0xffff) return 0; /* check bandwidth */ - uframe %= period_uframes; + uframe &= stream->ps.bw_uperiod - 1; frame = uframe >> 3; #ifdef CONFIG_USB_EHCI_TT_NEWSCHED @@ -1274,54 +1435,48 @@ sitd_slot_ok ( * tt_available scheduling guarantees 10+% for control/bulk. */ uf = uframe & 7; - if (!tt_available(ehci, period_uframes >> 3, - stream->udev, frame, uf, stream->tt_usecs)) + if (!tt_available(ehci, &stream->ps, tt, frame, uf)) return 0; #else /* tt must be idle for start(s), any gap, and csplit. * assume scheduling slop leaves 10+% for control/bulk. */ - if (!tt_no_collision(ehci, period_uframes >> 3, - stream->udev, frame, mask)) + if (!tt_no_collision(ehci, stream->ps.bw_period, + stream->ps.udev, frame, mask)) return 0; #endif - /* this multi-pass logic is simple, but performance may - * suffer when the schedule data isn't cached. - */ do { - u32 max_used; - - frame = uframe >> 3; - uf = uframe & 7; + unsigned max_used; + unsigned i; /* check starts (OUT uses more than one) */ - max_used = ehci->uframe_periodic_max - stream->usecs; - for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { - if (periodic_usecs (ehci, frame, uf) > max_used) + uf = uframe; + max_used = ehci->uframe_periodic_max - stream->ps.usecs; + for (tmp = stream->ps.cs_mask & 0xff; tmp; tmp >>= 1, uf++) { + if (ehci->bandwidth[uf] > max_used) return 0; } /* for IN, check CSPLIT */ - if (stream->c_usecs) { - uf = uframe & 7; - max_used = ehci->uframe_periodic_max - stream->c_usecs; - do { - tmp = 1 << uf; - tmp <<= 8; - if ((stream->raw_mask & tmp) == 0) + if (stream->ps.c_usecs) { + max_used = ehci->uframe_periodic_max - + stream->ps.c_usecs; + uf = uframe & ~7; + tmp = 1 << (2+8); + for (i = (uframe & 7) + 2; i < 8; (++i, tmp <<= 1)) { + if ((stream->ps.cs_mask & tmp) == 0) continue; - if (periodic_usecs (ehci, frame, uf) - > max_used) + if (ehci->bandwidth[uf+i] > max_used) return 0; - } while (++uf < 8); + } } - /* we know urb->interval is 2^N uframes */ - uframe += period_uframes; - } while (uframe < mod); + uframe += stream->ps.bw_uperiod; + } while (uframe < EHCI_BANDWIDTH_SIZE); - stream->splits = cpu_to_hc32(ehci, stream->raw_mask << (uframe & 7)); + stream->ps.cs_mask <<= uframe & 7; + stream->splits = cpu_to_hc32(ehci, stream->ps.cs_mask); return 1; } @@ -1336,8 +1491,6 @@ sitd_slot_ok ( * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! */ -#define SCHEDULING_DELAY 40 /* microframes */ - static int iso_stream_schedule ( struct ehci_hcd *ehci, @@ -1345,135 +1498,184 @@ iso_stream_schedule ( struct ehci_iso_stream *stream ) { - u32 now, base, next, start, period, span; - int status; + u32 now, base, next, start, period, span, now2; + u32 wrap = 0, skip = 0; + int status = 0; unsigned mod = ehci->periodic_size << 3; struct ehci_iso_sched *sched = urb->hcpriv; + bool empty = list_empty(&stream->td_list); + bool new_stream = false; - period = urb->interval; + period = stream->uperiod; span = sched->span; - if (!stream->highspeed) { - period <<= 3; + if (!stream->highspeed) span <<= 3; - } - 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). If there are, the behavior depends on - * whether URB_ISO_ASAP is set. - */ - if (likely (!list_empty (&stream->td_list))) { + /* Start a new isochronous stream? */ + if (unlikely(empty && !hcd_periodic_completion_in_progress( + ehci_to_hcd(ehci), urb->ep))) { - /* Take the isochronous scheduling threshold into account */ - if (ehci->i_thresh) - next = now + ehci->i_thresh; /* uframe cache */ - else - next = (now + 2 + 7) & ~0x07; /* full frame cache */ + /* Schedule the endpoint */ + if (stream->ps.phase == NO_FRAME) { + int done = 0; + struct ehci_tt *tt = find_tt(stream->ps.udev); - /* - * Use ehci->last_iso_frame as the base. There can't be any - * TDs scheduled for earlier than that. - */ - 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)) { + if (IS_ERR(tt)) { + status = PTR_ERR(tt); + goto fail; + } + compute_tt_budget(ehci->tt_budget, tt); - /* USB_ISO_ASAP: Round up to the first available slot */ - if (urb->transfer_flags & URB_ISO_ASAP) - start += (next - start + period - 1) & -period; + start = ((-(++ehci->random_frame)) << 3) & (period - 1); - /* - * Not ASAP: Use the next slot in the stream. If - * the entire URB falls before the threshold, fail. + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. */ - 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; + next = start; + start += period; + do { + start--; + /* check schedule: enough space? */ + if (stream->highspeed) { + if (itd_slot_ok(ehci, stream, start)) + done = 1; + } else { + if ((start % 8) >= 6) + continue; + if (sitd_slot_ok(ehci, stream, start, + sched, tt)) + done = 1; + } + } while (start > next && !done); + + /* no room in the schedule */ + if (!done) { + ehci_dbg(ehci, "iso sched full %p", urb); + status = -ENOSPC; goto fail; } + stream->ps.phase = (start >> 3) & + (stream->ps.period - 1); + stream->ps.bw_phase = stream->ps.phase & + (stream->ps.bw_period - 1); + stream->ps.phase_uf = start & 7; + reserve_release_iso_bandwidth(ehci, stream, 1); } - start += base; + /* New stream is already scheduled; use the upcoming slot */ + else { + start = (stream->ps.phase << 3) + stream->ps.phase_uf; + } + + stream->next_uframe = start; + new_stream = true; } - /* 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 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. + now = ehci_read_frame_index(ehci) & (mod - 1); + + /* Take the isochronous scheduling threshold into account */ + if (ehci->i_thresh) + next = now + ehci->i_thresh; /* uframe cache */ + else + next = (now + 2 + 7) & ~0x07; /* full frame cache */ + + /* + * Use ehci->last_iso_frame as the base. There can't be any + * TDs scheduled for earlier than that. */ - else { - int done = 0; + base = ehci->last_iso_frame << 3; + next = (next - base) & (mod - 1); + start = (stream->next_uframe - base) & (mod - 1); - base = now & ~0x07; - start = base + SCHEDULING_DELAY; + if (unlikely(new_stream)) + goto do_ASAP; - /* find a uframe slot with enough bandwidth. - * Early uframes are more precious because full-speed - * iso IN transfers can't use late uframes, - * and therefore they should be allocated last. - */ - next = start; - start += period; - do { - start--; - /* check schedule: enough space? */ - if (stream->highspeed) { - if (itd_slot_ok(ehci, mod, start, - stream->usecs, period)) - done = 1; - } else { - if ((start % 8) >= 6) - continue; - if (sitd_slot_ok(ehci, mod, stream, - start, sched, period)) - done = 1; - } - } while (start > next && !done); + /* + * Typical case: reuse current schedule, stream may still be active. + * Hopefully there are no gaps from the host falling behind + * (irq delays etc). If there are, the behavior depends on + * whether URB_ISO_ASAP is set. + */ + now2 = (now - base) & (mod - 1); + + /* Is the schedule already full? */ + if (unlikely(!empty && 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; + } + + /* Is the next packet scheduled after the base time? */ + if (likely(!empty || start <= now2 + period)) { + + /* URB_ISO_ASAP: make sure that start >= next */ + if (unlikely(start < next && + (urb->transfer_flags & URB_ISO_ASAP))) + goto do_ASAP; + + /* Otherwise use start, if it's not in the past */ + if (likely(start >= now2)) + goto use_start; + + /* Otherwise we got an underrun while the queue was empty */ + } else { + if (urb->transfer_flags & URB_ISO_ASAP) + goto do_ASAP; + wrap = mod; + now2 += mod; + } - /* no room in the schedule */ - if (!done) { - ehci_dbg(ehci, "iso sched full %p", urb); - status = -ENOSPC; - goto fail; + /* How many uframes and packets do we need to skip? */ + skip = (now2 - start + period - 1) & -period; + if (skip >= span) { /* Entirely in the past? */ + ehci_dbg(ehci, "iso underrun %p (%u+%u < %u) [%u]\n", + urb, start + base, span - period, now2 + base, + base); + + /* Try to keep the last TD intact for scanning later */ + skip = span - period; + + /* Will it come before the current scan position? */ + if (empty) { + skip = span; /* Skip the entire URB */ + status = 1; /* and give it back immediately */ + iso_sched_free(stream, sched); + sched = NULL; } } + urb->error_count = skip / period; + if (sched) + sched->first_packet = urb->error_count; + goto use_start; + do_ASAP: + /* Use the first slot after "next" */ + start = next + ((start - next) & (period - 1)); + + use_start: /* Tried to schedule too far into the future? */ - if (unlikely(start - base + span - period >= mod)) { + if (unlikely(start + span - period >= mod + wrap)) { ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n", - urb, start - base, span - period, mod); + urb, start, span - period, mod + wrap); status = -EFBIG; goto fail; } - stream->next_uframe = start & (mod - 1); + start += base; + stream->next_uframe = (start + skip) & (mod - 1); /* report high speed start in uframes; full speed, in frames */ - urb->start_frame = stream->next_uframe; + urb->start_frame = start & (mod - 1); if (!stream->highspeed) urb->start_frame >>= 3; /* Make sure scan_isoc() sees these */ if (ehci->isoc_count == 0) ehci->last_iso_frame = now >> 3; - return 0; + return status; fail: iso_sched_free(stream, sched); @@ -1574,16 +1776,9 @@ static void itd_link_urb( next_uframe = stream->next_uframe & (mod - 1); - if (unlikely (list_empty(&stream->td_list))) { + if (unlikely (list_empty(&stream->td_list))) ehci_to_hcd(ehci)->self.bandwidth_allocated += stream->bandwidth; - ehci_vdbg (ehci, - "schedule devp %s ep%d%s-iso period %d start %d.%d\n", - urb->dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", - urb->interval, - next_uframe >> 3, next_uframe & 0x7); - } if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { if (ehci->amd_pll_fix == 1) @@ -1593,7 +1788,8 @@ static void itd_link_urb( ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; /* fill iTDs uframe by uframe */ - for (packet = 0, itd = NULL; packet < urb->number_of_packets; ) { + for (packet = iso_sched->first_packet, itd = NULL; + packet < urb->number_of_packets;) { if (itd == NULL) { /* ASSERT: we have all necessary itds */ // BUG_ON (list_empty (&iso_sched->td_list)); @@ -1613,7 +1809,7 @@ static void itd_link_urb( itd_patch(ehci, itd, iso_sched, packet, uframe); - next_uframe += stream->interval; + next_uframe += stream->uperiod; next_uframe &= mod - 1; packet++; @@ -1718,14 +1914,9 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd) usb_amd_quirk_pll_enable(); } - if (unlikely(list_is_singular(&stream->td_list))) { + if (unlikely(list_is_singular(&stream->td_list))) ehci_to_hcd(ehci)->self.bandwidth_allocated -= stream->bandwidth; - ehci_vdbg (ehci, - "deschedule devp %s ep%d%s-iso\n", - dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); - } done: itd->urb = NULL; @@ -1758,9 +1949,9 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, ehci_dbg (ehci, "can't get iso stream\n"); return -ENOMEM; } - if (unlikely (urb->interval != stream->interval)) { + if (unlikely(urb->interval != stream->uperiod)) { ehci_dbg (ehci, "can't change iso interval %d --> %d\n", - stream->interval, urb->interval); + stream->uperiod, urb->interval); goto done; } @@ -1792,10 +1983,14 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, if (unlikely(status)) goto done_not_linked; status = iso_stream_schedule(ehci, urb, stream); - if (likely (status == 0)) + if (likely(status == 0)) { itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); - else + } else if (status > 0) { + status = 0; + ehci_urb_done(ehci, urb, 0); + } else { usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); + } done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -1821,7 +2016,7 @@ sitd_sched_init( dma_addr_t dma = urb->transfer_dma; /* how many frames are needed for these transfers */ - iso_sched->span = urb->number_of_packets * stream->interval; + iso_sched->span = urb->number_of_packets * stream->ps.period; /* figure out per-frame sitd fields that we'll need later * when we fit new sitds into the schedule. @@ -1913,7 +2108,7 @@ sitd_urb_transaction ( memset (sitd, 0, sizeof *sitd); sitd->sitd_dma = sitd_dma; - sitd->frame = 9999; /* an invalid value */ + sitd->frame = NO_FRAME; list_add (&sitd->sitd_list, &iso_sched->td_list); } @@ -1983,17 +2178,10 @@ static void sitd_link_urb( next_uframe = stream->next_uframe; - if (list_empty(&stream->td_list)) { + if (list_empty(&stream->td_list)) /* usbfs ignores TT bandwidth */ ehci_to_hcd(ehci)->self.bandwidth_allocated += stream->bandwidth; - ehci_vdbg (ehci, - "sched devp %s ep%d%s-iso [%d] %dms/%04x\n", - urb->dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", - (next_uframe >> 3) & (ehci->periodic_size - 1), - stream->interval, hc32_to_cpu(ehci, stream->splits)); - } if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { if (ehci->amd_pll_fix == 1) @@ -2003,7 +2191,7 @@ static void sitd_link_urb( ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; /* fill sITDs frame by frame */ - for (packet = 0, sitd = NULL; + for (packet = sched->first_packet, sitd = NULL; packet < urb->number_of_packets; packet++) { @@ -2022,7 +2210,7 @@ static void sitd_link_urb( sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1), sitd); - next_uframe += stream->interval << 3; + next_uframe += stream->uperiod; } stream->next_uframe = next_uframe & (mod - 1); @@ -2107,14 +2295,9 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) usb_amd_quirk_pll_enable(); } - if (list_is_singular(&stream->td_list)) { + if (list_is_singular(&stream->td_list)) ehci_to_hcd(ehci)->self.bandwidth_allocated -= stream->bandwidth; - ehci_vdbg (ehci, - "deschedule devp %s ep%d%s-iso\n", - dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); - } done: sitd->urb = NULL; @@ -2146,9 +2329,9 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, ehci_dbg (ehci, "can't get iso stream\n"); return -ENOMEM; } - if (urb->interval != stream->interval) { + if (urb->interval != stream->ps.period) { ehci_dbg (ehci, "can't change iso interval %d --> %d\n", - stream->interval, urb->interval); + stream->ps.period, urb->interval); goto done; } @@ -2178,10 +2361,14 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, if (unlikely(status)) goto done_not_linked; status = iso_stream_schedule(ehci, urb, stream); - if (status == 0) + if (likely(status == 0)) { sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); - else + } else if (status > 0) { + status = 0; + ehci_urb_done(ehci, urb, 0); + } else { usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); + } done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -2259,7 +2446,8 @@ restart: q.itd->hw_next != EHCI_LIST_END(ehci)) *hw_p = q.itd->hw_next; else - *hw_p = ehci->dummy->qh_dma; + *hw_p = cpu_to_hc32(ehci, + ehci->dummy->qh_dma); type = Q_NEXT_TYPE(ehci, q.itd->hw_next); wmb(); modified = itd_complete (ehci, q.itd); @@ -2294,7 +2482,8 @@ restart: q.sitd->hw_next != EHCI_LIST_END(ehci)) *hw_p = q.sitd->hw_next; else - *hw_p = ehci->dummy->qh_dma; + *hw_p = cpu_to_hc32(ehci, + ehci->dummy->qh_dma); type = Q_NEXT_TYPE(ehci, q.sitd->hw_next); wmb(); modified = sitd_complete (ehci, q.sitd); diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c index f55477c5a1b..cf126767386 100644 --- a/drivers/usb/host/ehci-sead3.c +++ b/drivers/usb/host/ehci-sead3.c @@ -55,7 +55,7 @@ const struct hc_driver ehci_sead3_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -126,6 +126,7 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev) IRQF_SHARED); if (ret == 0) { platform_set_drvdata(pdev, hcd); + device_wakeup_enable(hcd->self.controller); return ret; } @@ -140,7 +141,6 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index b44d716ddc8..9b9b9f5b016 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -36,7 +36,7 @@ static const struct hc_driver ehci_sh_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, + .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, /* * basic lifecycle operations @@ -104,7 +104,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) goto fail_create_hcd; } - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); /* initialize hcd */ hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev, @@ -151,6 +151,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to add hcd"); goto fail_add_hcd; } + device_wakeup_enable(hcd->self.controller); priv->hcd = hcd; platform_set_drvdata(pdev, priv); @@ -176,7 +177,6 @@ static int ehci_hcd_sh_remove(struct platform_device *pdev) usb_remove_hcd(hcd); usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); clk_disable(priv->fclk); clk_disable(priv->iclk); diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index bd3e5cbc624..1d59958ad0c 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -81,10 +81,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) * 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (retval) + goto fail; usbh_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usbh_clk)) { @@ -107,16 +106,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!devm_request_mem_region(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - retval = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -ENOMEM; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); goto err_put_hcd; } @@ -131,6 +123,7 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) if (retval) goto err_stop_ehci; + device_wakeup_enable(hcd->self.controller); return retval; err_stop_ehci: @@ -148,10 +141,6 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); struct spear_ehci *sehci = to_spear_ehci(hcd); - if (!hcd) - return 0; - if (in_interrupt()) - BUG(); usb_remove_hcd(hcd); if (sehci->clk) @@ -174,7 +163,7 @@ static struct platform_driver spear_ehci_hcd_driver = { .name = "spear-ehci", .bus = &platform_bus_type, .pm = &ehci_spear_pm_ops, - .of_match_table = of_match_ptr(spear_ehci_id_table), + .of_match_table = spear_ehci_id_table, } }; diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c index 14ced00ba22..f6459dfb6f5 100644 --- a/drivers/usb/host/ehci-sysfs.c +++ b/drivers/usb/host/ehci-sysfs.c @@ -97,8 +97,7 @@ static ssize_t store_uframe_periodic_max(struct device *dev, { struct ehci_hcd *ehci; unsigned uframe_periodic_max; - unsigned frame, uframe; - unsigned short allocated_max; + unsigned uframe; unsigned long flags; ssize_t ret; @@ -122,16 +121,14 @@ static ssize_t store_uframe_periodic_max(struct device *dev, /* * for request to decrease max periodic bandwidth, we have to check - * every microframe in the schedule to see whether the decrease is - * possible. + * to see whether the decrease is possible. */ if (uframe_periodic_max < ehci->uframe_periodic_max) { - allocated_max = 0; + u8 allocated_max = 0; - for (frame = 0; frame < ehci->periodic_size; ++frame) - for (uframe = 0; uframe < 7; ++uframe) - allocated_max = max(allocated_max, - periodic_usecs (ehci, frame, uframe)); + for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe) + allocated_max = max(allocated_max, + ehci->bandwidth[uframe]); if (allocated_max > uframe_periodic_max) { ehci_info(ehci, diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 59d111bf44a..6fdcb8ad229 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -17,59 +17,49 @@ */ #include <linux/clk.h> +#include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/platform_data/tegra_usb.h> -#include <linux/irq.h> -#include <linux/usb/otg.h> #include <linux/gpio.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/slab.h> #include <linux/usb/ehci_def.h> #include <linux/usb/tegra_usb_phy.h> -#include <linux/clk/tegra.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> -#define TEGRA_USB_BASE 0xC5000000 -#define TEGRA_USB2_BASE 0xC5004000 -#define TEGRA_USB3_BASE 0xC5008000 +#include "ehci.h" -/* PORTSC registers */ -#define TEGRA_USB_PORTSC1 0x184 -#define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) -#define TEGRA_USB_PORTSC1_PHCD (1 << 23) +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) #define TEGRA_USB_DMA_ALIGN 32 +#define DRIVER_DESC "Tegra EHCI driver" +#define DRV_NAME "tegra-ehci" + +static struct hc_driver __read_mostly tegra_ehci_hc_driver; + +struct tegra_ehci_soc_config { + bool has_hostpc; +}; + struct tegra_ehci_hcd { - struct ehci_hcd *ehci; struct tegra_usb_phy *phy; struct clk *clk; - struct usb_phy *transceiver; - int host_resumed; + struct reset_control *rst; int port_resuming; bool needs_double_reset; enum tegra_usb_phy_port_speed port_speed; }; -static void tegra_ehci_power_up(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - clk_prepare_enable(tegra->clk); - usb_phy_set_suspend(hcd->phy, 0); - tegra->host_resumed = 1; -} - -static void tegra_ehci_power_down(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - tegra->host_resumed = 0; - usb_phy_set_suspend(hcd->phy, 1); - clk_disable_unprepare(tegra->clk); -} - static int tegra_ehci_internal_port_reset( struct ehci_hcd *ehci, u32 __iomem *portsc_reg @@ -144,8 +134,8 @@ static int tegra_ehci_hub_control( u16 wLength ) { - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd *)ehci->priv; u32 __iomem *status_reg; u32 temp; unsigned long flags; @@ -179,7 +169,7 @@ static int tegra_ehci_hub_control( * If a transaction is in progress, there may be a delay in * suspending the port. Poll until the port is suspended. */ - if (handshake(ehci, status_reg, PORT_SUSPEND, + if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, PORT_SUSPEND, 5000)) pr_err("%s: timeout waiting for SUSPEND\n", __func__); @@ -227,9 +217,9 @@ static int tegra_ehci_hub_control( spin_lock_irqsave(&ehci->lock, flags); /* Poll until the controller clears RESUME and SUSPEND */ - if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) + if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) pr_err("%s: timeout waiting for RESUME\n", __func__); - if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) + if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) pr_err("%s: timeout waiting for SUSPEND\n", __func__); ehci->reset_done[wIndex-1] = 0; @@ -243,57 +233,12 @@ static int tegra_ehci_hub_control( /* Handle the hub control events here */ return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + done: spin_unlock_irqrestore(&ehci->lock, flags); return retval; } -static void tegra_ehci_restart(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci_reset(ehci); - - /* setup the frame list and Async q heads */ - ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); - ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); - /* setup the command register and set the controller in RUN mode */ - ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); - ehci->command |= CMD_RUN; - ehci_writel(ehci, ehci->command, &ehci->regs->command); - - down_write(&ehci_cf_port_reset_rwsem); - ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); - /* flush posted writes */ - ehci_readl(ehci, &ehci->regs->command); - up_write(&ehci_cf_port_reset_rwsem); -} - -static void tegra_ehci_shutdown(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - /* ehci_shutdown touches the USB controller registers, make sure - * controller has clocks to it */ - if (!tegra->host_resumed) - tegra_ehci_power_up(hcd); - - ehci_shutdown(hcd); -} - -static int tegra_ehci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - /* EHCI registers start at offset 0x100 */ - ehci->caps = hcd->regs + 0x100; - - /* switch to host mode */ - hcd->has_tt = 1; - - return ehci_setup(hcd); -} - struct dma_aligned_buffer { void *kmalloc_ptr; void *old_xfer_buffer; @@ -373,302 +318,46 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) free_dma_aligned_buffer(urb); } -static const struct hc_driver tegra_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "Tegra EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .flags = HCD_USB2 | HCD_MEMORY, - - /* standard ehci functions */ - .irq = ehci_irq, - .start = ehci_run, - .stop = ehci_stop, - .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, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* modified ehci functions for tegra */ - .reset = tegra_ehci_setup, - .shutdown = tegra_ehci_shutdown, - .map_urb_for_dma = tegra_ehci_map_urb_for_dma, - .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, - .hub_control = tegra_ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif +static const struct tegra_ehci_soc_config tegra30_soc_config = { + .has_hostpc = true, }; -static int setup_vbus_gpio(struct platform_device *pdev, - struct tegra_ehci_platform_data *pdata) -{ - int err = 0; - int gpio; - - gpio = pdata->vbus_gpio; - if (!gpio_is_valid(gpio)) - gpio = of_get_named_gpio(pdev->dev.of_node, - "nvidia,vbus-gpio", 0); - if (!gpio_is_valid(gpio)) - return 0; - - err = gpio_request(gpio, "vbus_gpio"); - if (err) { - dev_err(&pdev->dev, "can't request vbus gpio %d", gpio); - return err; - } - err = gpio_direction_output(gpio, 1); - if (err) { - dev_err(&pdev->dev, "can't enable vbus\n"); - return err; - } - - return err; -} - -#ifdef CONFIG_PM - -static int controller_suspend(struct device *dev) -{ - struct tegra_ehci_hcd *tegra = - platform_get_drvdata(to_platform_device(dev)); - struct ehci_hcd *ehci = tegra->ehci; - struct usb_hcd *hcd = ehci_to_hcd(ehci); - struct ehci_regs __iomem *hw = ehci->regs; - unsigned long flags; - - if (time_before(jiffies, ehci->next_statechange)) - msleep(10); - - ehci_halt(ehci); - - spin_lock_irqsave(&ehci->lock, flags); - tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - spin_unlock_irqrestore(&ehci->lock, flags); - - tegra_ehci_power_down(hcd); - return 0; -} - -static int controller_resume(struct device *dev) -{ - struct tegra_ehci_hcd *tegra = - platform_get_drvdata(to_platform_device(dev)); - struct ehci_hcd *ehci = tegra->ehci; - struct usb_hcd *hcd = ehci_to_hcd(ehci); - struct ehci_regs __iomem *hw = ehci->regs; - unsigned long val; - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - tegra_ehci_power_up(hcd); - - if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) { - /* Wait for the phy to detect new devices - * before we restart the controller */ - msleep(10); - goto restart; - } - - /* Force the phy to keep data lines in suspend state */ - tegra_ehci_phy_restore_start(hcd->phy, tegra->port_speed); - - /* Enable host mode */ - tdi_reset(ehci); - - /* Enable Port Power */ - val = readl(&hw->port_status[0]); - val |= PORT_POWER; - writel(val, &hw->port_status[0]); - udelay(10); - - /* Check if the phy resume from LP0. When the phy resume from LP0 - * USB register will be reset. */ - if (!readl(&hw->async_next)) { - /* Program the field PTC based on the saved speed mode */ - val = readl(&hw->port_status[0]); - val &= ~PORT_TEST(~0); - if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH) - val |= PORT_TEST_FORCE; - else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) - val |= PORT_TEST(6); - else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= PORT_TEST(7); - writel(val, &hw->port_status[0]); - udelay(10); - - /* Disable test mode by setting PTC field to NORMAL_OP */ - val = readl(&hw->port_status[0]); - val &= ~PORT_TEST(~0); - writel(val, &hw->port_status[0]); - udelay(10); - } - - /* Poll until CCS is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_CONNECT, - PORT_CONNECT, 2000)) { - pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); - goto restart; - } - - /* Poll until PE is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_PE, - PORT_PE, 2000)) { - pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); - goto restart; - } - - /* Clear the PCI status, to avoid an interrupt taken upon resume */ - val = readl(&hw->status); - val |= STS_PCD; - writel(val, &hw->status); - - /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ - val = readl(&hw->port_status[0]); - if ((val & PORT_POWER) && (val & PORT_PE)) { - val |= PORT_SUSPEND; - writel(val, &hw->port_status[0]); - - /* Wait until port suspend completes */ - if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND, - PORT_SUSPEND, 1000)) { - pr_err("%s: timeout waiting for PORT_SUSPEND\n", - __func__); - goto restart; - } - } - - tegra_ehci_phy_restore_end(hcd->phy); - goto done; - - restart: - if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) - tegra_ehci_phy_restore_end(hcd->phy); - - tegra_ehci_restart(hcd); - - done: - tegra_usb_phy_preresume(hcd->phy); - tegra->port_resuming = 1; - return 0; -} - -static int tegra_ehci_suspend(struct device *dev) -{ - struct tegra_ehci_hcd *tegra = - platform_get_drvdata(to_platform_device(dev)); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - int rc = 0; - - /* - * When system sleep is supported and USB controller wakeup is - * implemented: If the controller is runtime-suspended and the - * wakeup setting needs to be changed, call pm_runtime_resume(). - */ - if (HCD_HW_ACCESSIBLE(hcd)) - rc = controller_suspend(dev); - return rc; -} - -static int tegra_ehci_resume(struct device *dev) -{ - int rc; - - rc = controller_resume(dev); - if (rc == 0) { - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } - return rc; -} - -static int tegra_ehci_runtime_suspend(struct device *dev) -{ - return controller_suspend(dev); -} - -static int tegra_ehci_runtime_resume(struct device *dev) -{ - return controller_resume(dev); -} - -static const struct dev_pm_ops tegra_ehci_pm_ops = { - .suspend = tegra_ehci_suspend, - .resume = tegra_ehci_resume, - .runtime_suspend = tegra_ehci_runtime_suspend, - .runtime_resume = tegra_ehci_runtime_resume, +static const struct tegra_ehci_soc_config tegra20_soc_config = { + .has_hostpc = false, }; -#endif - -/* Bits of PORTSC1, which will get cleared by writing 1 into them */ -#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) - -static void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val) -{ - unsigned long val; - struct usb_hcd *hcd = bus_to_hcd(x->otg->host); - void __iomem *base = hcd->regs; - - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - val &= ~TEGRA_USB_PORTSC1_PTS(3); - val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); - writel(val, base + TEGRA_USB_PORTSC1); -} - -static void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) -{ - unsigned long val; - struct usb_hcd *hcd = bus_to_hcd(x->otg->host); - void __iomem *base = hcd->regs; - - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - if (enable) - val |= TEGRA_USB_PORTSC1_PHCD; - else - val &= ~TEGRA_USB_PORTSC1_PHCD; - writel(val, base + TEGRA_USB_PORTSC1); -} +static struct of_device_id tegra_ehci_of_match[] = { + { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config }, + { .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config }, + { }, +}; static int tegra_ehci_probe(struct platform_device *pdev) { + const struct of_device_id *match; + const struct tegra_ehci_soc_config *soc_config; struct resource *res; struct usb_hcd *hcd; + struct ehci_hcd *ehci; struct tegra_ehci_hcd *tegra; - struct tegra_ehci_platform_data *pdata; int err = 0; int irq; - int instance = pdev->id; struct usb_phy *u_phy; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Platform data missing\n"); - return -EINVAL; + match = of_match_device(tegra_ehci_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; } + soc_config = match->data; /* 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - - setup_vbus_gpio(pdev, pdata); - - tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd), - GFP_KERNEL); - if (!tegra) - return -ENOMEM; + err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + return err; hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); @@ -676,23 +365,40 @@ static int tegra_ehci_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } + platform_set_drvdata(pdev, hcd); + ehci = hcd_to_ehci(hcd); + tegra = (struct tegra_ehci_hcd *)ehci->priv; - platform_set_drvdata(pdev, tegra); + hcd->has_tt = 1; tegra->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tegra->clk)) { dev_err(&pdev->dev, "Can't get ehci clock\n"); err = PTR_ERR(tegra->clk); - goto fail_clk; + goto cleanup_hcd_create; + } + + tegra->rst = devm_reset_control_get(&pdev->dev, "usb"); + if (IS_ERR(tegra->rst)) { + dev_err(&pdev->dev, "Can't get ehci reset\n"); + err = PTR_ERR(tegra->rst); + goto cleanup_hcd_create; } err = clk_prepare_enable(tegra->clk); if (err) - goto fail_clk; + goto cleanup_hcd_create; - tegra_periph_reset_assert(tegra->clk); + reset_control_assert(tegra->rst); udelay(1); - tegra_periph_reset_deassert(tegra->clk); + reset_control_deassert(tegra->rst); + + u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); + if (IS_ERR(u_phy)) { + err = PTR_ERR(u_phy); + goto cleanup_clk_en; + } + hcd->phy = u_phy; tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, "nvidia,needs-double-reset"); @@ -701,126 +407,75 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (!res) { dev_err(&pdev->dev, "Failed to get I/O memory\n"); err = -ENXIO; - goto fail_io; + goto cleanup_clk_en; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to remap I/O memory\n"); - err = -ENOMEM; - goto fail_io; - } - - /* This is pretty ugly and needs to be fixed when we do only - * device-tree probing. Old code relies on the platform_device - * numbering that we lack for device-tree-instantiated devices. - */ - if (instance < 0) { - switch (res->start) { - case TEGRA_USB_BASE: - instance = 0; - break; - case TEGRA_USB2_BASE: - instance = 1; - break; - case TEGRA_USB3_BASE: - instance = 2; - break; - default: - err = -ENODEV; - dev_err(&pdev->dev, "unknown usb instance\n"); - goto fail_io; - } + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + err = PTR_ERR(hcd->regs); + goto cleanup_clk_en; } + ehci->caps = hcd->regs + 0x100; + ehci->has_hostpc = soc_config->has_hostpc; - tegra->phy = tegra_usb_phy_open(&pdev->dev, instance, hcd->regs, - pdata->phy_config, - TEGRA_USB_PHY_MODE_HOST, - tegra_ehci_set_pts, - tegra_ehci_set_phcd); - if (IS_ERR(tegra->phy)) { - dev_err(&pdev->dev, "Failed to open USB phy\n"); - err = -ENXIO; - goto fail_io; + err = usb_phy_init(hcd->phy); + if (err) { + dev_err(&pdev->dev, "Failed to initialize phy\n"); + goto cleanup_clk_en; } - hcd->phy = u_phy = &tegra->phy->u_phy; - usb_phy_init(hcd->phy); - u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), GFP_KERNEL); if (!u_phy->otg) { dev_err(&pdev->dev, "Failed to alloc memory for otg\n"); err = -ENOMEM; - goto fail_io; + goto cleanup_phy; } u_phy->otg->host = hcd_to_bus(hcd); err = usb_phy_set_suspend(hcd->phy, 0); if (err) { dev_err(&pdev->dev, "Failed to power on the phy\n"); - goto fail_phy; + goto cleanup_phy; } - tegra->host_resumed = 1; - tegra->ehci = hcd_to_ehci(hcd); - irq = platform_get_irq(pdev, 0); if (!irq) { dev_err(&pdev->dev, "Failed to get IRQ\n"); err = -ENODEV; - goto fail_phy; + goto cleanup_phy; } - if (pdata->operating_mode == TEGRA_USB_OTG) { - tegra->transceiver = - devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, &hcd->self); - } else { - tegra->transceiver = ERR_PTR(-ENODEV); - } + otg_set_host(u_phy->otg, &hcd->self); err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto fail; + goto cleanup_otg_set_host; } + device_wakeup_enable(hcd->self.controller); - pm_runtime_set_active(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - - /* Don't skip the pm_runtime_forbid call if wakeup isn't working */ - /* if (!pdata->power_down_on_bus_suspend) */ - pm_runtime_forbid(&pdev->dev); - pm_runtime_enable(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); return err; -fail: - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, NULL); -fail_phy: +cleanup_otg_set_host: + otg_set_host(u_phy->otg, NULL); +cleanup_phy: usb_phy_shutdown(hcd->phy); -fail_io: +cleanup_clk_en: clk_disable_unprepare(tegra->clk); -fail_clk: +cleanup_hcd_create: usb_put_hcd(hcd); return err; } static int tegra_ehci_remove(struct platform_device *pdev) { - struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - - pm_runtime_get_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct tegra_ehci_hcd *tegra = + (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, NULL); + otg_set_host(hcd->phy->otg, NULL); usb_phy_shutdown(hcd->phy); usb_remove_hcd(hcd); @@ -833,27 +488,82 @@ static int tegra_ehci_remove(struct platform_device *pdev) static void tegra_ehci_hcd_shutdown(struct platform_device *pdev) { - struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); + struct usb_hcd *hcd = platform_get_drvdata(pdev); if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); } -static struct of_device_id tegra_ehci_of_match[] = { - { .compatible = "nvidia,tegra20-ehci", }, - { }, -}; - static struct platform_driver tegra_ehci_driver = { .probe = tegra_ehci_probe, .remove = tegra_ehci_remove, .shutdown = tegra_ehci_hcd_shutdown, .driver = { - .name = "tegra-ehci", + .name = DRV_NAME, .of_match_table = tegra_ehci_of_match, -#ifdef CONFIG_PM - .pm = &tegra_ehci_pm_ops, -#endif } }; + +static int tegra_ehci_reset(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + int txfifothresh; + + retval = ehci_setup(hcd); + if (retval) + return retval; + + /* + * We should really pull this value out of tegra_ehci_soc_config, but + * to avoid needing access to it, make use of the fact that Tegra20 is + * the only one so far that needs a value of 10, and Tegra20 is the + * only one which doesn't set has_hostpc. + */ + txfifothresh = ehci->has_hostpc ? 0x10 : 10; + ehci_writel(ehci, txfifothresh << 16, &ehci->regs->txfill_tuning); + + return 0; +} + +static const struct ehci_driver_overrides tegra_overrides __initconst = { + .extra_priv_size = sizeof(struct tegra_ehci_hcd), + .reset = tegra_ehci_reset, +}; + +static int __init ehci_tegra_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info(DRV_NAME ": " DRIVER_DESC "\n"); + + ehci_init_driver(&tegra_ehci_hc_driver, &tegra_overrides); + + /* + * The Tegra HW has some unusual quirks, which require Tegra-specific + * workarounds. We override certain hc_driver functions here to + * achieve that. We explicitly do not enhance ehci_driver_overrides to + * allow this more easily, since this is an unusual case, and we don't + * want to encourage others to override these functions by making it + * too easy. + */ + + tegra_ehci_hc_driver.map_urb_for_dma = tegra_ehci_map_urb_for_dma; + tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma; + tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control; + + return platform_driver_register(&tegra_ehci_driver); +} +module_init(ehci_tegra_init); + +static void __exit ehci_tegra_cleanup(void) +{ + platform_driver_unregister(&tegra_ehci_driver); +} +module_exit(ehci_tegra_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_ehci_of_match); diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c index b083a350eea..0d247673c3c 100644 --- a/drivers/usb/host/ehci-tilegx.c +++ b/drivers/usb/host/ehci-tilegx.c @@ -61,7 +61,7 @@ static const struct hc_driver ehci_tilegx_hc_driver = { * Generic hardware linkage. */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * Basic lifecycle operations. @@ -101,7 +101,7 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct ehci_hcd *ehci; - struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); pte_t pte = { 0 }; int my_cpu = smp_processor_id(); int ret; @@ -142,8 +142,8 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) ehci->hcs_params = readl(&ehci->caps->hcs_params); /* Create our IRQs and register them. */ - pdata->irq = create_irq(); - if (pdata->irq < 0) { + pdata->irq = irq_alloc_hwirq(-1); + if (!pdata->irq) { ret = -ENXIO; goto err_no_irq; } @@ -170,11 +170,12 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); if (ret == 0) { platform_set_drvdata(pdev, hcd); + device_wakeup_enable(hcd->self.controller); return ret; } err_have_irq: - destroy_irq(pdata->irq); + irq_free_hwirq(pdata->irq); err_no_irq: tilegx_stop_ehc(); usb_put_hcd(hcd); @@ -186,14 +187,13 @@ err_hcd: static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); usb_remove_hcd(hcd); usb_put_hcd(hcd); tilegx_stop_ehc(); gxio_usb_host_destroy(&pdata->usb_ctx); - destroy_irq(pdata->irq); - platform_set_drvdata(pdev, NULL); + irq_free_hwirq(pdata->irq); return 0; } diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 11e5b32f73e..424ac5d8371 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = { 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ + 5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */ 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ @@ -215,6 +216,36 @@ static void ehci_handle_controller_death(struct ehci_hcd *ehci) /* Not in process context, so don't try to reset the controller */ } +/* start to unlink interrupt QHs */ +static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci) +{ + bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); + + /* + * Process all the QHs on the intr_unlink list that were added + * before the current unlink cycle began. The list is in + * temporal order, so stop when we reach the first entry in the + * current cycle. But if the root hub isn't running then + * process all the QHs on the list. + */ + while (!list_empty(&ehci->intr_unlink_wait)) { + struct ehci_qh *qh; + + qh = list_first_entry(&ehci->intr_unlink_wait, + struct ehci_qh, unlink_node); + if (!stopped && (qh->unlink_cycle == + ehci->intr_unlink_wait_cycle)) + break; + list_del_init(&qh->unlink_node); + start_unlink_intr(ehci, qh); + } + + /* Handle remaining entries later */ + if (!list_empty(&ehci->intr_unlink_wait)) { + ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true); + ++ehci->intr_unlink_wait_cycle; + } +} /* Handle unlinked interrupt QHs once they are gone from the hardware */ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) @@ -236,7 +267,7 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) unlink_node); if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) break; - list_del(&qh->unlink_node); + list_del_init(&qh->unlink_node); end_unlink_intr(ehci, qh); } @@ -363,6 +394,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ + ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */ unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */ ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index 59e0e24c753..a9303aff125 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -11,13 +11,28 @@ * */ +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ehci.h" /* enable phy0 and phy1 for w90p910 */ #define ENPHY (0x01<<8) #define PHY0_CTR (0xA4) #define PHY1_CTR (0xA8) +#define DRIVER_DESC "EHCI w90x900 driver" + +static const char hcd_name[] = "ehci-w90x900 "; + +static struct hc_driver __read_mostly ehci_w90x900_hc_driver; + static int usb_w90x900_probe(const struct hc_driver *driver, struct platform_device *pdev) { @@ -43,17 +58,12 @@ static int usb_w90x900_probe(const struct hc_driver *driver, hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - retval = -EBUSY; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); goto err2; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - retval = -EFAULT; - goto err3; - } - ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; ehci->regs = hcd->regs + @@ -73,80 +83,27 @@ static int usb_w90x900_probe(const struct hc_driver *driver, irq = platform_get_irq(pdev, 0); if (irq < 0) - goto err4; + goto err2; retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval != 0) - goto err4; + goto err2; + device_wakeup_enable(hcd->self.controller); return retval; -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err2: usb_put_hcd(hcd); err1: return retval; } -static -void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev) +static void usb_w90x900_remove(struct usb_hcd *hcd, + struct platform_device *pdev) { usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); } -static const struct hc_driver ehci_w90x900_hc_driver = { - .description = hcd_name, - .product_desc = "Nuvoton w90x900 EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2|HCD_MEMORY, - - /* - * 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, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .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 ehci_w90x900_probe(struct platform_device *pdev) { if (usb_disabled()) @@ -173,7 +130,25 @@ static struct platform_driver ehci_hcd_w90x900_driver = { }, }; +static int __init ehci_w90X900_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_w90x900_hc_driver, NULL); + return platform_driver_register(&ehci_hcd_w90x900_driver); +} +module_init(ehci_w90X900_init); + +static void __exit ehci_w90X900_cleanup(void) +{ + platform_driver_unregister(&ehci_hcd_w90x900_driver); +} +module_exit(ehci_w90X900_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("w90p910 usb ehci driver!"); -MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:w90p910-ehci"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index d845e3bcfaf..fe57710753e 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -79,7 +79,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -155,7 +155,8 @@ static int ehci_hcd_xilinx_of_probe(struct platform_device *op) irq = irq_of_parse_and_map(dn, 0); if (!irq) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); + dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", + __FILE__); rv = -EBUSY; goto err_irq; } @@ -191,8 +192,10 @@ static int ehci_hcd_xilinx_of_probe(struct platform_device *op) ehci->caps = hcd->regs + 0x100; rv = usb_add_hcd(hcd, irq, 0); - if (rv == 0) + if (rv == 0) { + device_wakeup_enable(hcd->self.controller); return 0; + } err_irq: usb_put_hcd(hcd); @@ -209,8 +212,7 @@ err_irq: */ static int ehci_hcd_xilinx_of_remove(struct platform_device *op) { - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - dev_set_drvdata(&op->dev, NULL); + struct usb_hcd *hcd = platform_get_drvdata(op); dev_dbg(&op->dev, "stopping XILINX-OF USB Controller\n"); @@ -221,21 +223,6 @@ static int ehci_hcd_xilinx_of_remove(struct platform_device *op) return 0; } -/** - * ehci_hcd_xilinx_of_shutdown - shutdown the hcd - * @op: pointer to platform_device structure that is to be removed - * - * Properly shutdown the hcd, call driver's shutdown routine. - */ -static void ehci_hcd_xilinx_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ehci_hcd_xilinx_of_match[] = { {.compatible = "xlnx,xps-usb-host-1.00.a",}, {}, @@ -245,7 +232,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match); static struct platform_driver ehci_hcd_xilinx_of_driver = { .probe = ehci_hcd_xilinx_of_probe, .remove = ehci_hcd_xilinx_of_remove, - .shutdown = ehci_hcd_xilinx_of_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xilinx-of-ehci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 7c978b23520..eee228a26a0 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -38,7 +38,7 @@ typedef __u16 __bitwise __hc16; #endif /* statistics can be kept for tuning/monitoring */ -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG #define EHCI_STATS #endif @@ -54,6 +54,28 @@ struct ehci_stats { unsigned long unlink; }; +/* + * Scheduling and budgeting information for periodic transfers, for both + * high-speed devices and full/low-speed devices lying behind a TT. + */ +struct ehci_per_sched { + struct usb_device *udev; /* access to the TT */ + struct usb_host_endpoint *ep; + struct list_head ps_list; /* node on ehci_tt's ps_list */ + u16 tt_usecs; /* time on the FS/LS bus */ + u16 cs_mask; /* C-mask and S-mask bytes */ + u16 period; /* actual period in frames */ + u16 phase; /* actual phase, frame part */ + u8 bw_phase; /* same, for bandwidth + reservation */ + u8 phase_uf; /* uframe part of the phase */ + u8 usecs, c_usecs; /* times on the HS bus */ + u8 bw_uperiod; /* period in microframes, for + bandwidth reservation */ + u8 bw_period; /* same, in frames */ +}; +#define NO_FRAME 29999 /* frame not assigned yet */ + /* ehci_hcd->lock guards shared data against other CPUs: * ehci_hcd: async, unlink, periodic (and shadow), ... * usb_host_endpoint: hcpriv @@ -88,6 +110,7 @@ enum ehci_hrtimer_event { EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ + EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */ EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ @@ -143,7 +166,9 @@ struct ehci_hcd { /* one per controller */ unsigned i_thresh; /* uframes HC might cache */ union ehci_shadow *pshadow; /* mirror hw periodic table */ + struct list_head intr_unlink_wait; struct list_head intr_unlink; + unsigned intr_unlink_wait_cycle; unsigned intr_unlink_cycle; unsigned now_frame; /* frame from HC hardware */ unsigned last_iso_frame; /* last frame scanned for iso */ @@ -200,6 +225,7 @@ struct ehci_hcd { /* one per controller */ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ unsigned need_oc_pp_cycle:1; /* MPC834X port power */ + unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) @@ -210,6 +236,7 @@ struct ehci_hcd { /* one per controller */ #define OHCI_HCCTRL_LEN 0x4 __hc32 *ohci_hcctrl_reg; unsigned has_hostpc:1; + unsigned has_tdi_phy_lpm:1; unsigned has_ppcd:1; /* support per-port change bits */ u8 sbrn; /* packed release number */ @@ -222,10 +249,19 @@ struct ehci_hcd { /* one per controller */ #endif /* debug files */ -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG struct dentry *debug_dir; #endif + /* bandwidth usage */ +#define EHCI_BANDWIDTH_SIZE 64 +#define EHCI_BANDWIDTH_FRAMES (EHCI_BANDWIDTH_SIZE >> 3) + u8 bandwidth[EHCI_BANDWIDTH_SIZE]; + /* us allocated per uframe */ + u8 tt_budget[EHCI_BANDWIDTH_SIZE]; + /* us budgeted per uframe */ + struct list_head tt_list; + /* platform-specific data -- must come last */ unsigned long priv[0] __aligned(sizeof(s64)); }; @@ -381,6 +417,7 @@ struct ehci_qh { struct list_head intr_node; /* list of intr QHs */ struct ehci_qtd *dummy; struct list_head unlink_node; + struct ehci_per_sched ps; /* scheduling info */ unsigned unlink_cycle; @@ -394,16 +431,8 @@ struct ehci_qh { u8 xacterrs; /* XactErr retry counter */ #define QH_XACTERR_MAX 32 /* XactErr retry limit */ - /* periodic schedule info */ - u8 usecs; /* intr bandwidth */ u8 gap_uf; /* uframes split/csplit gap */ - u8 c_usecs; /* ... split completion bw */ - u16 tt_usecs; /* tt downstream bandwidth */ - unsigned short period; /* polling interval */ - unsigned short start; /* where polling starts */ -#define NO_FRAME ((unsigned short)~0) /* pick new start */ - struct usb_device *dev; /* access to TT */ unsigned is_out:1; /* bulk or intr OUT */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ unsigned dequeue_during_giveback:1; @@ -430,6 +459,7 @@ struct ehci_iso_packet { struct ehci_iso_sched { struct list_head td_list; unsigned span; + unsigned first_packet; struct ehci_iso_packet packet [0]; }; @@ -445,22 +475,17 @@ struct ehci_iso_stream { u8 highspeed; struct list_head td_list; /* queued itds/sitds */ struct list_head free_list; /* list of unused itds/sitds */ - struct usb_device *udev; - struct usb_host_endpoint *ep; /* output of (re)scheduling */ - int next_uframe; + struct ehci_per_sched ps; /* scheduling info */ + unsigned next_uframe; __hc32 splits; /* the rest is derived from the endpoint descriptor, - * trusting urb->interval == f(epdesc->bInterval) and * including the extra info for hw_bufp[0..2] */ - u8 usecs, c_usecs; - u16 interval; - u16 tt_usecs; + u16 uperiod; /* period in uframes */ u16 maxp; - u16 raw_mask; unsigned bandwidth; /* This is used to initialize iTD's hw_bufp fields */ @@ -575,6 +600,35 @@ struct ehci_fstn { /*-------------------------------------------------------------------------*/ +/* + * USB-2.0 Specification Sections 11.14 and 11.18 + * Scheduling and budgeting split transactions using TTs + * + * A hub can have a single TT for all its ports, or multiple TTs (one for each + * port). The bandwidth and budgeting information for the full/low-speed bus + * below each TT is self-contained and independent of the other TTs or the + * high-speed bus. + * + * "Bandwidth" refers to the number of microseconds on the FS/LS bus allocated + * to an interrupt or isochronous endpoint for each frame. "Budget" refers to + * the best-case estimate of the number of full-speed bytes allocated to an + * endpoint for each microframe within an allocated frame. + * + * Removal of an endpoint invalidates a TT's budget. Instead of trying to + * keep an up-to-date record, we recompute the budget when it is needed. + */ + +struct ehci_tt { + u16 bandwidth[EHCI_BANDWIDTH_FRAMES]; + + struct list_head tt_list; /* List of all ehci_tt's */ + struct list_head ps_list; /* Items using this TT */ + struct usb_tt *usb_tt; + int tt_port; /* TT port number */ +}; + +/*-------------------------------------------------------------------------*/ + /* Prepare the PORTSC wakeup flags during controller suspend/resume */ #define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \ @@ -675,6 +729,18 @@ static inline unsigned int ehci_readl(const struct ehci_hcd *ehci, #endif } +#ifdef CONFIG_SOC_IMX28 +static inline void imx28_ehci_writel(const unsigned int val, + volatile __u32 __iomem *addr) +{ + __asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr)); +} +#else +static inline void imx28_ehci_writel(const unsigned int val, + volatile __u32 __iomem *addr) +{ +} +#endif static inline void ehci_writel(const struct ehci_hcd *ehci, const unsigned int val, __u32 __iomem *regs) { @@ -683,7 +749,10 @@ static inline void ehci_writel(const struct ehci_hcd *ehci, writel_be(val, regs) : writel(val, regs); #else - writel(val, regs); + if (ehci->imx28_write_fix) + imx28_ehci_writel(val, regs); + else + writel(val, regs); #endif } @@ -778,15 +847,10 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) #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 -#ifndef DEBUG +#ifndef CONFIG_DYNAMIC_DEBUG #define STUB_DEBUG_FILES -#endif /* DEBUG */ +#endif /*-------------------------------------------------------------------------*/ @@ -800,10 +864,15 @@ struct ehci_driver_overrides { extern void ehci_init_driver(struct hc_driver *drv, const struct ehci_driver_overrides *over); extern int ehci_setup(struct usb_hcd *hcd); +extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec); #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 */ +extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength); + #endif /* __LINUX_EHCI_HCD_H */ diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 0b46542591f..1cf68eaf2ed 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -26,6 +26,8 @@ #include <linux/io.h> #include <linux/usb.h> #include <linux/usb/hcd.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/slab.h> @@ -752,6 +754,8 @@ static int of_fhci_probe(struct platform_device *ofdev) if (ret < 0) goto err_add_hcd; + device_wakeup_enable(hcd->self.controller); + fhci_dfs_create(fhci); return 0; diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index 8f18538e0ff..95ca5986e67 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -739,9 +739,13 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) } /* for ISO transfer calculate start frame index */ - if (ed->mode == FHCI_TF_ISO && urb->transfer_flags & URB_ISO_ASAP) - urb->start_frame = ed->td_head ? ed->last_iso + 1 : + if (ed->mode == FHCI_TF_ISO) { + /* Ignore the possibility of underruns */ + urb->start_frame = ed->td_head ? ed->next_iso : get_frame_num(fhci); + ed->next_iso = (urb->start_frame + urb->interval * + urb->number_of_packets) & 0x07ff; + } /* * OHCI handles the DATA toggle itself,we just use the USB diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h index 7cc1c32dc36..154e6a00772 100644 --- a/drivers/usb/host/fhci.h +++ b/drivers/usb/host/fhci.h @@ -338,7 +338,7 @@ struct ed { /* read only parameters, should be cleared upon initialization */ u8 toggle_carry; /* toggle carry from the last TD submitted */ - u32 last_iso; /* time stamp of last queued ISO transfer */ + u16 next_iso; /* time stamp of next queued ISO transfer */ struct td *td_head; /* a pointer to the current TD handled */ }; diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c new file mode 100644 index 00000000000..98a89d16cc3 --- /dev/null +++ b/drivers/usb/host/fotg210-hcd.c @@ -0,0 +1,5981 @@ +/* + * Faraday FOTG210 EHCI-like driver + * + * Copyright (c) 2013 Faraday Technology Corporation + * + * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com> + * Feng-Hsin Chiang <john453@faraday-tech.com> + * Po-Yu Chuang <ratbert.chuang@gmail.com> + * + * Most of code borrowed from the Linux-3.7 EHCI driver + * + * 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; either version 2 of the License, or (at your + * option) any later version. + * + * 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. + */ +#include <linux/module.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/hrtimer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/moduleparam.h> +#include <linux/dma-mapping.h> +#include <linux/debugfs.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/byteorder.h> +#include <asm/irq.h> +#include <asm/unaligned.h> + +/*-------------------------------------------------------------------------*/ +#define DRIVER_AUTHOR "Yuan-Hsin Chen" +#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver" + +static const char hcd_name[] = "fotg210_hcd"; + +#undef FOTG210_URB_TRACE + +#define FOTG210_STATS + +/* magic numbers that can affect system performance */ +#define FOTG210_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define FOTG210_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ +#define FOTG210_TUNE_RL_TT 0 +#define FOTG210_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define FOTG210_TUNE_MULT_TT 1 +/* + * Some drivers think it's safe to schedule isochronous transfers more than + * 256 ms into the future (partly as a result of an old bug in the scheduling + * code). In an attempt to avoid trouble, we will use a minimum scheduling + * length of 512 frames instead of 256. + */ +#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */ + +/* Initial IRQ latency: faster than hw default */ +static int log2_irq_thresh; /* 0 to 6 */ +module_param(log2_irq_thresh, int, S_IRUGO); +MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); + +/* initial park setting: slower than hw default */ +static unsigned park; +module_param(park, uint, S_IRUGO); +MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets"); + +/* 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 "fotg210.h" + +/*-------------------------------------------------------------------------*/ + +#define fotg210_dbg(fotg210, fmt, args...) \ + dev_dbg(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) +#define fotg210_err(fotg210, fmt, args...) \ + dev_err(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) +#define fotg210_info(fotg210, fmt, args...) \ + dev_info(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) +#define fotg210_warn(fotg210, fmt, args...) \ + dev_warn(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) + +/* check the values in the HCSPARAMS register + * (host controller _Structural_ parameters) + * see EHCI spec, Table 2-4 for each value + */ +static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) +{ + u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params); + + fotg210_dbg(fotg210, + "%s hcs_params 0x%x ports=%d\n", + label, params, + HCS_N_PORTS(params) + ); +} + +/* check the values in the HCCPARAMS register + * (host controller _Capability_ parameters) + * see EHCI Spec, Table 2-5 for each value + * */ +static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) +{ + u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + + fotg210_dbg(fotg210, + "%s hcc_params %04x uframes %s%s\n", + label, + params, + HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", + HCC_CANPARK(params) ? " park" : ""); +} + +static void __maybe_unused +dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd) +{ + fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, + hc32_to_cpup(fotg210, &qtd->hw_next), + hc32_to_cpup(fotg210, &qtd->hw_alt_next), + hc32_to_cpup(fotg210, &qtd->hw_token), + hc32_to_cpup(fotg210, &qtd->hw_buf[0])); + if (qtd->hw_buf[1]) + fotg210_dbg(fotg210, " p1=%08x p2=%08x p3=%08x p4=%08x\n", + hc32_to_cpup(fotg210, &qtd->hw_buf[1]), + hc32_to_cpup(fotg210, &qtd->hw_buf[2]), + hc32_to_cpup(fotg210, &qtd->hw_buf[3]), + hc32_to_cpup(fotg210, &qtd->hw_buf[4])); +} + +static void __maybe_unused +dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qh_hw *hw = qh->hw; + + fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label, + qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current); + dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next); +} + +static void __maybe_unused +dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd) +{ + fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n", + label, itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next), + itd->urb); + fotg210_dbg(fotg210, + " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", + hc32_to_cpu(fotg210, itd->hw_transaction[0]), + hc32_to_cpu(fotg210, itd->hw_transaction[1]), + hc32_to_cpu(fotg210, itd->hw_transaction[2]), + hc32_to_cpu(fotg210, itd->hw_transaction[3]), + hc32_to_cpu(fotg210, itd->hw_transaction[4]), + hc32_to_cpu(fotg210, itd->hw_transaction[5]), + hc32_to_cpu(fotg210, itd->hw_transaction[6]), + hc32_to_cpu(fotg210, itd->hw_transaction[7])); + fotg210_dbg(fotg210, + " buf: %08x %08x %08x %08x %08x %08x %08x\n", + hc32_to_cpu(fotg210, itd->hw_bufp[0]), + hc32_to_cpu(fotg210, itd->hw_bufp[1]), + hc32_to_cpu(fotg210, itd->hw_bufp[2]), + hc32_to_cpu(fotg210, itd->hw_bufp[3]), + hc32_to_cpu(fotg210, itd->hw_bufp[4]), + hc32_to_cpu(fotg210, itd->hw_bufp[5]), + hc32_to_cpu(fotg210, itd->hw_bufp[6])); + fotg210_dbg(fotg210, " index: %d %d %d %d %d %d %d %d\n", + itd->index[0], itd->index[1], itd->index[2], + itd->index[3], itd->index[4], itd->index[5], + itd->index[6], itd->index[7]); +} + +static int __maybe_unused +dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) +{ + return scnprintf(buf, len, + "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", + label, label[0] ? " " : "", status, + (status & STS_ASS) ? " Async" : "", + (status & STS_PSS) ? " Periodic" : "", + (status & STS_RECL) ? " Recl" : "", + (status & STS_HALT) ? " Halt" : "", + (status & STS_IAA) ? " IAA" : "", + (status & STS_FATAL) ? " FATAL" : "", + (status & STS_FLR) ? " FLR" : "", + (status & STS_PCD) ? " PCD" : "", + (status & STS_ERR) ? " ERR" : "", + (status & STS_INT) ? " INT" : "" + ); +} + +static int __maybe_unused +dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) +{ + return scnprintf(buf, len, + "%s%sintrenable %02x%s%s%s%s%s%s", + label, label[0] ? " " : "", enable, + (enable & STS_IAA) ? " IAA" : "", + (enable & STS_FATAL) ? " FATAL" : "", + (enable & STS_FLR) ? " FLR" : "", + (enable & STS_PCD) ? " PCD" : "", + (enable & STS_ERR) ? " ERR" : "", + (enable & STS_INT) ? " INT" : "" + ); +} + +static const char *const fls_strings[] = { "1024", "512", "256", "??" }; + +static int +dbg_command_buf(char *buf, unsigned len, const char *label, u32 command) +{ + return scnprintf(buf, len, + "%s%scommand %07x %s=%d ithresh=%d%s%s%s " + "period=%s%s %s", + label, label[0] ? " " : "", command, + (command & CMD_PARK) ? " park" : "(park)", + CMD_PARK_CNT(command), + (command >> 16) & 0x3f, + (command & CMD_IAAD) ? " IAAD" : "", + (command & CMD_ASE) ? " Async" : "", + (command & CMD_PSE) ? " Periodic" : "", + fls_strings[(command >> 2) & 0x3], + (command & CMD_RESET) ? " Reset" : "", + (command & CMD_RUN) ? "RUN" : "HALT" + ); +} + +static char +*dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) +{ + char *sig; + + /* signaling state */ + switch (status & (3 << 10)) { + case 0 << 10: + sig = "se0"; + break; + case 1 << 10: + sig = "k"; + break; /* low speed */ + case 2 << 10: + sig = "j"; + break; + default: + sig = "?"; + break; + } + + scnprintf(buf, len, + "%s%sport:%d status %06x %d " + "sig=%s%s%s%s%s%s%s%s", + label, label[0] ? " " : "", port, status, + status>>25,/*device address */ + sig, + (status & PORT_RESET) ? " RESET" : "", + (status & PORT_SUSPEND) ? " SUSPEND" : "", + (status & PORT_RESUME) ? " RESUME" : "", + (status & PORT_PEC) ? " PEC" : "", + (status & PORT_PE) ? " PE" : "", + (status & PORT_CSC) ? " CSC" : "", + (status & PORT_CONNECT) ? " CONNECT" : ""); + return buf; +} + +/* functions have the "wrong" filename when they're output... */ +#define dbg_status(fotg210, label, status) { \ + char _buf[80]; \ + dbg_status_buf(_buf, sizeof(_buf), label, status); \ + fotg210_dbg(fotg210, "%s\n", _buf); \ +} + +#define dbg_cmd(fotg210, label, command) { \ + char _buf[80]; \ + dbg_command_buf(_buf, sizeof(_buf), label, command); \ + fotg210_dbg(fotg210, "%s\n", _buf); \ +} + +#define dbg_port(fotg210, label, port, status) { \ + char _buf[80]; \ + fotg210_dbg(fotg210, "%s\n", dbg_port_buf(_buf, sizeof(_buf), label, port, status) ); \ +} + +/*-------------------------------------------------------------------------*/ + +/* troubleshooting help: expose state in debugfs */ + +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_output(struct file*, char __user*, size_t, loff_t*); +static int debug_close(struct inode *, struct file *); + +static const struct file_operations debug_async_fops = { + .owner = THIS_MODULE, + .open = debug_async_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; +static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; +static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; + +static struct dentry *fotg210_debug_root; + +struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ + struct usb_bus *bus; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *output_buf; + size_t alloc_size; +}; + +#define speed_char(info1)({ char tmp; \ + switch (info1 & (3 << 12)) { \ + case QH_FULL_SPEED: \ + tmp = 'f'; break; \ + case QH_LOW_SPEED: \ + tmp = 'l'; break; \ + case QH_HIGH_SPEED: \ + tmp = 'h'; break; \ + default: \ + tmp = '?'; break; \ + } tmp; }) + +static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token) +{ + __u32 v = hc32_to_cpu(fotg210, token); + + if (v & QTD_STS_ACTIVE) + return '*'; + if (v & QTD_STS_HALT) + return '-'; + if (!IS_SHORT_READ(v)) + return ' '; + /* tries to advance through hw_alt_next */ + return '/'; +} + +static void qh_lines( + struct fotg210_hcd *fotg210, + struct fotg210_qh *qh, + char **nextp, + unsigned *sizep +) +{ + u32 scratch; + u32 hw_curr; + struct fotg210_qtd *td; + unsigned temp; + unsigned size = *sizep; + char *next = *nextp; + char mark; + __le32 list_end = FOTG210_LIST_END(fotg210); + struct fotg210_qh_hw *hw = qh->hw; + + if (hw->hw_qtd_next == list_end) /* NEC does this */ + mark = '@'; + else + mark = token_mark(fotg210, hw->hw_token); + if (mark == '/') { /* qh_alt_next controls qh advance? */ + if ((hw->hw_alt_next & QTD_MASK(fotg210)) + == fotg210->async->hw->hw_alt_next) + mark = '#'; /* blocked */ + else if (hw->hw_alt_next == list_end) + mark = '.'; /* use hw_qtd_next */ + /* else alt_next points to some other qtd */ + } + scratch = hc32_to_cpup(fotg210, &hw->hw_info1); + hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0; + temp = scnprintf(next, size, + "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)", + qh, scratch & 0x007f, + speed_char(scratch), + (scratch >> 8) & 0x000f, + scratch, hc32_to_cpup(fotg210, &hw->hw_info2), + hc32_to_cpup(fotg210, &hw->hw_token), mark, + (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token) + ? "data1" : "data0", + (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f); + size -= temp; + next += temp; + + /* hc may be modifying the list as we read it ... */ + list_for_each_entry(td, &qh->qtd_list, qtd_list) { + scratch = hc32_to_cpup(fotg210, &td->hw_token); + mark = ' '; + if (hw_curr == td->qtd_dma) + mark = '*'; + else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma)) + mark = '+'; + else if (QTD_LENGTH(scratch)) { + if (td->hw_alt_next == fotg210->async->hw->hw_alt_next) + mark = '#'; + else if (td->hw_alt_next != list_end) + mark = '/'; + } + temp = snprintf(next, size, + "\n\t%p%c%s len=%d %08x urb %p", + td, mark, ({ char *tmp; + switch ((scratch>>8)&0x03) { + case 0: + tmp = "out"; + break; + case 1: + tmp = "in"; + break; + case 2: + tmp = "setup"; + break; + default: + tmp = "?"; + break; + } tmp; }), + (scratch >> 16) & 0x7fff, + scratch, + td->urb); + if (size < temp) + temp = size; + size -= temp; + next += temp; + if (temp == size) + goto done; + } + + temp = snprintf(next, size, "\n"); + if (size < temp) + temp = size; + size -= temp; + next += temp; + +done: + *sizep = size; + *nextp = next; +} + +static ssize_t fill_async_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fotg210_hcd *fotg210; + unsigned long flags; + unsigned temp, size; + char *next; + struct fotg210_qh *qh; + + hcd = bus_to_hcd(buf->bus); + fotg210 = hcd_to_fotg210(hcd); + next = buf->output_buf; + size = buf->alloc_size; + + *next = 0; + + /* dumps a snapshot of the async schedule. + * usually empty except for long-term bulk reads, or head. + * one QH per line, and TDs we know about + */ + spin_lock_irqsave(&fotg210->lock, flags); + for (qh = fotg210->async->qh_next.qh; size > 0 && qh; + qh = qh->qh_next.qh) + qh_lines(fotg210, qh, &next, &size); + if (fotg210->async_unlink && size > 0) { + temp = scnprintf(next, size, "\nunlink =\n"); + size -= temp; + next += temp; + + for (qh = fotg210->async_unlink; size > 0 && qh; + qh = qh->unlink_next) + qh_lines(fotg210, qh, &next, &size); + } + spin_unlock_irqrestore(&fotg210->lock, flags); + + return strlen(buf->output_buf); +} + +#define DBG_SCHED_LIMIT 64 +static ssize_t fill_periodic_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fotg210_hcd *fotg210; + unsigned long flags; + union fotg210_shadow p, *seen; + unsigned temp, size, seen_count; + char *next; + unsigned i; + __hc32 tag; + + seen = kmalloc(DBG_SCHED_LIMIT * sizeof(*seen), GFP_ATOMIC); + if (!seen) + return 0; + seen_count = 0; + + hcd = bus_to_hcd(buf->bus); + fotg210 = hcd_to_fotg210(hcd); + next = buf->output_buf; + size = buf->alloc_size; + + temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size); + size -= temp; + next += temp; + + /* dump a snapshot of the periodic schedule. + * iso changes, interrupt usually doesn't. + */ + spin_lock_irqsave(&fotg210->lock, flags); + for (i = 0; i < fotg210->periodic_size; i++) { + p = fotg210->pshadow[i]; + if (likely(!p.ptr)) + continue; + tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]); + + temp = scnprintf(next, size, "%4d: ", i); + size -= temp; + next += temp; + + do { + struct fotg210_qh_hw *hw; + + switch (hc32_to_cpu(fotg210, tag)) { + case Q_TYPE_QH: + hw = p.qh->hw; + temp = scnprintf(next, size, " qh%d-%04x/%p", + p.qh->period, + hc32_to_cpup(fotg210, + &hw->hw_info2) + /* uframe masks */ + & (QH_CMASK | QH_SMASK), + p.qh); + size -= temp; + next += temp; + /* don't repeat what follows this qh */ + for (temp = 0; temp < seen_count; temp++) { + if (seen[temp].ptr != p.ptr) + continue; + if (p.qh->qh_next.ptr) { + temp = scnprintf(next, size, + " ..."); + size -= temp; + next += temp; + } + break; + } + /* show more info the first time around */ + if (temp == seen_count) { + u32 scratch = hc32_to_cpup(fotg210, + &hw->hw_info1); + struct fotg210_qtd *qtd; + char *type = ""; + + /* count tds, get ep direction */ + temp = 0; + list_for_each_entry(qtd, + &p.qh->qtd_list, + qtd_list) { + temp++; + switch (0x03 & (hc32_to_cpu( + fotg210, + qtd->hw_token) >> 8)) { + case 0: + type = "out"; + continue; + case 1: + type = "in"; + continue; + } + } + + temp = scnprintf(next, size, + "(%c%d ep%d%s " + "[%d/%d] q%d p%d)", + speed_char(scratch), + scratch & 0x007f, + (scratch >> 8) & 0x000f, type, + p.qh->usecs, p.qh->c_usecs, + temp, + 0x7ff & (scratch >> 16)); + + if (seen_count < DBG_SCHED_LIMIT) + seen[seen_count++].qh = p.qh; + } else + temp = 0; + tag = Q_NEXT_TYPE(fotg210, hw->hw_next); + p = p.qh->qh_next; + break; + case Q_TYPE_FSTN: + temp = scnprintf(next, size, + " fstn-%8x/%p", p.fstn->hw_prev, + p.fstn); + tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next); + p = p.fstn->fstn_next; + break; + case Q_TYPE_ITD: + temp = scnprintf(next, size, + " itd/%p", p.itd); + tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next); + p = p.itd->itd_next; + break; + } + size -= temp; + next += temp; + } while (p.ptr); + + temp = scnprintf(next, size, "\n"); + size -= temp; + next += temp; + } + spin_unlock_irqrestore(&fotg210->lock, flags); + kfree(seen); + + return buf->alloc_size - size; +} +#undef DBG_SCHED_LIMIT + +static const char *rh_state_string(struct fotg210_hcd *fotg210) +{ + switch (fotg210->rh_state) { + case FOTG210_RH_HALTED: + return "halted"; + case FOTG210_RH_SUSPENDED: + return "suspended"; + case FOTG210_RH_RUNNING: + return "running"; + case FOTG210_RH_STOPPING: + return "stopping"; + } + return "?"; +} + +static ssize_t fill_registers_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fotg210_hcd *fotg210; + unsigned long flags; + unsigned temp, size, i; + char *next, scratch[80]; + static const char fmt[] = "%*s\n"; + static const char label[] = ""; + + hcd = bus_to_hcd(buf->bus); + fotg210 = hcd_to_fotg210(hcd); + next = buf->output_buf; + size = buf->alloc_size; + + spin_lock_irqsave(&fotg210->lock, flags); + + if (!HCD_HW_ACCESSIBLE(hcd)) { + size = scnprintf(next, size, + "bus %s, device %s\n" + "%s\n" + "SUSPENDED(no register access)\n", + hcd->self.controller->bus->name, + dev_name(hcd->self.controller), + hcd->product_desc); + goto done; + } + + /* Capability Registers */ + i = HC_VERSION(fotg210, fotg210_readl(fotg210, + &fotg210->caps->hc_capbase)); + temp = scnprintf(next, size, + "bus %s, device %s\n" + "%s\n" + "EHCI %x.%02x, rh state %s\n", + hcd->self.controller->bus->name, + dev_name(hcd->self.controller), + hcd->product_desc, + i >> 8, i & 0x0ff, rh_state_string(fotg210)); + size -= temp; + next += temp; + + /* FIXME interpret both types of params */ + i = fotg210_readl(fotg210, &fotg210->caps->hcs_params); + temp = scnprintf(next, size, "structural params 0x%08x\n", i); + size -= temp; + next += temp; + + i = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + temp = scnprintf(next, size, "capability params 0x%08x\n", i); + size -= temp; + next += temp; + + /* Operational Registers */ + temp = dbg_status_buf(scratch, sizeof(scratch), label, + fotg210_readl(fotg210, &fotg210->regs->status)); + temp = scnprintf(next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_command_buf(scratch, sizeof(scratch), label, + fotg210_readl(fotg210, &fotg210->regs->command)); + temp = scnprintf(next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_intr_buf(scratch, sizeof(scratch), label, + fotg210_readl(fotg210, &fotg210->regs->intr_enable)); + temp = scnprintf(next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = scnprintf(next, size, "uframe %04x\n", + fotg210_read_frame_index(fotg210)); + size -= temp; + next += temp; + + if (fotg210->async_unlink) { + temp = scnprintf(next, size, "async unlink qh %p\n", + fotg210->async_unlink); + size -= temp; + next += temp; + } + +#ifdef FOTG210_STATS + temp = scnprintf(next, size, + "irq normal %ld err %ld iaa %ld(lost %ld)\n", + fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa, + fotg210->stats.lost_iaa); + size -= temp; + next += temp; + + temp = scnprintf(next, size, "complete %ld unlink %ld\n", + fotg210->stats.complete, fotg210->stats.unlink); + size -= temp; + next += temp; +#endif + +done: + spin_unlock_irqrestore(&fotg210->lock, flags); + + return buf->alloc_size - size; +} + +static struct debug_buffer *alloc_buffer(struct usb_bus *bus, + ssize_t (*fill_func)(struct debug_buffer *)) +{ + struct debug_buffer *buf; + + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); + + if (buf) { + buf->bus = bus; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + buf->alloc_size = PAGE_SIZE; + } + + return buf; +} + +static int fill_buffer(struct debug_buffer *buf) +{ + int ret = 0; + + if (!buf->output_buf) + buf->output_buf = vmalloc(buf->alloc_size); + + if (!buf->output_buf) { + ret = -ENOMEM; + goto out; + } + + ret = buf->fill_func(buf); + + if (ret >= 0) { + buf->count = ret; + ret = 0; + } + +out: + return ret; +} + +static ssize_t debug_output(struct file *file, char __user *user_buf, + size_t len, loff_t *offset) +{ + struct debug_buffer *buf = file->private_data; + int ret = 0; + + mutex_lock(&buf->mutex); + if (buf->count == 0) { + ret = fill_buffer(buf); + if (ret != 0) { + mutex_unlock(&buf->mutex); + goto out; + } + } + mutex_unlock(&buf->mutex); + + ret = simple_read_from_buffer(user_buf, len, offset, + buf->output_buf, buf->count); + +out: + return ret; + +} + +static int debug_close(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf = file->private_data; + + if (buf) { + vfree(buf->output_buf); + kfree(buf); + } + + return 0; +} +static int debug_async_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_periodic_open(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf; + buf = alloc_buffer(inode->i_private, fill_periodic_buffer); + if (!buf) + return -ENOMEM; + + buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE; + file->private_data = buf; + return 0; +} + +static int debug_registers_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_registers_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static inline void create_debug_files(struct fotg210_hcd *fotg210) +{ + struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; + + fotg210->debug_dir = debugfs_create_dir(bus->bus_name, + fotg210_debug_root); + if (!fotg210->debug_dir) + return; + + if (!debugfs_create_file("async", S_IRUGO, fotg210->debug_dir, bus, + &debug_async_fops)) + goto file_error; + + if (!debugfs_create_file("periodic", S_IRUGO, fotg210->debug_dir, bus, + &debug_periodic_fops)) + goto file_error; + + if (!debugfs_create_file("registers", S_IRUGO, fotg210->debug_dir, bus, + &debug_registers_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(fotg210->debug_dir); +} + +static inline void remove_debug_files(struct fotg210_hcd *fotg210) +{ + debugfs_remove_recursive(fotg210->debug_dir); +} + +/*-------------------------------------------------------------------------*/ + +/* + * handshake - spin reading hc until handshake completes or fails + * @ptr: address of hc register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + * + * That last failure should_only happen in cases like physical cardbus eject + * before driver shutdown. But it also seems to be caused by bugs in cardbus + * bridge shutdown: shutting down the bridge before the devices using it. + */ +static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = fotg210_readl(fotg210, ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* + * Force HC to halt state from unknown (EHCI spec section 2.3). + * Must be called with interrupts enabled and the lock not held. + */ +static int fotg210_halt(struct fotg210_hcd *fotg210) +{ + u32 temp; + + spin_lock_irq(&fotg210->lock); + + /* disable any irqs left enabled by previous code */ + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); + + /* + * This routine gets called during probe before fotg210->command + * has been initialized, so we can't rely on its value. + */ + fotg210->command &= ~CMD_RUN; + temp = fotg210_readl(fotg210, &fotg210->regs->command); + temp &= ~(CMD_RUN | CMD_IAAD); + fotg210_writel(fotg210, temp, &fotg210->regs->command); + + spin_unlock_irq(&fotg210->lock); + synchronize_irq(fotg210_to_hcd(fotg210)->irq); + + return handshake(fotg210, &fotg210->regs->status, + STS_HALT, STS_HALT, 16 * 125); +} + +/* + * Reset a non-running (STS_HALT == 1) controller. + * Must be called with interrupts enabled and the lock not held. + */ +static int fotg210_reset(struct fotg210_hcd *fotg210) +{ + int retval; + u32 command = fotg210_readl(fotg210, &fotg210->regs->command); + + /* If the EHCI debug controller is active, special care must be + * taken before and after a host controller reset */ + if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210))) + fotg210->debug = NULL; + + command |= CMD_RESET; + dbg_cmd(fotg210, "reset", command); + fotg210_writel(fotg210, command, &fotg210->regs->command); + fotg210->rh_state = FOTG210_RH_HALTED; + fotg210->next_statechange = jiffies; + retval = handshake(fotg210, &fotg210->regs->command, + CMD_RESET, 0, 250 * 1000); + + if (retval) + return retval; + + if (fotg210->debug) + dbgp_external_startup(fotg210_to_hcd(fotg210)); + + fotg210->port_c_suspend = fotg210->suspended_ports = + fotg210->resuming_ports = 0; + return retval; +} + +/* + * Idle the controller (turn off the schedules). + * Must be called with interrupts enabled and the lock not held. + */ +static void fotg210_quiesce(struct fotg210_hcd *fotg210) +{ + u32 temp; + + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + /* wait for any schedule enables/disables to take effect */ + temp = (fotg210->command << 10) & (STS_ASS | STS_PSS); + handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp, + 16 * 125); + + /* then disable anything that's still active */ + spin_lock_irq(&fotg210->lock); + fotg210->command &= ~(CMD_ASE | CMD_PSE); + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + spin_unlock_irq(&fotg210->lock); + + /* hardware can take 16 microframes to turn off ... */ + handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0, + 16 * 125); +} + +/*-------------------------------------------------------------------------*/ + +static void end_unlink_async(struct fotg210_hcd *fotg210); +static void unlink_empty_async(struct fotg210_hcd *fotg210); +static void fotg210_work(struct fotg210_hcd *fotg210); +static void start_unlink_intr(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh); +static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); + +/*-------------------------------------------------------------------------*/ + +/* Set a bit in the USBCMD register */ +static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit) +{ + fotg210->command |= bit; + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + + /* unblock posted write */ + fotg210_readl(fotg210, &fotg210->regs->command); +} + +/* Clear a bit in the USBCMD register */ +static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit) +{ + fotg210->command &= ~bit; + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + + /* unblock posted write */ + fotg210_readl(fotg210, &fotg210->regs->command); +} + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI timer support... Now using hrtimers. + * + * Lots of different events are triggered from fotg210->hrtimer. Whenever + * the timer routine runs, it checks each possible event; events that are + * currently enabled and whose expiration time has passed get handled. + * The set of enabled events is stored as a collection of bitflags in + * fotg210->enabled_hrtimer_events, and they are numbered in order of + * increasing delay values (ranging between 1 ms and 100 ms). + * + * Rather than implementing a sorted list or tree of all pending events, + * we keep track only of the lowest-numbered pending event, in + * fotg210->next_hrtimer_event. Whenever fotg210->hrtimer gets restarted, its + * expiration time is set to the timeout value for this event. + * + * As a result, events might not get handled right away; the actual delay + * could be anywhere up to twice the requested delay. This doesn't + * matter, because none of the events are especially time-critical. The + * ones that matter most all have a delay of 1 ms, so they will be + * handled after 2 ms at most, which is okay. In addition to this, we + * allow for an expiration range of 1 ms. + */ + +/* + * Delay lengths for the hrtimer event types. + * Keep this list sorted by delay length, in the same order as + * the event types indexed by enum fotg210_hrtimer_event in fotg210.h. + */ +static unsigned event_delays_ns[] = { + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_ASS */ + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_PSS */ + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_DEAD */ + 1125 * NSEC_PER_USEC, /* FOTG210_HRTIMER_UNLINK_INTR */ + 2 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_FREE_ITDS */ + 6 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ + 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IAA_WATCHDOG */ + 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ + 15 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_ASYNC */ + 100 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IO_WATCHDOG */ +}; + +/* Enable a pending hrtimer event */ +static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event, + bool resched) +{ + ktime_t *timeout = &fotg210->hr_timeouts[event]; + + if (resched) + *timeout = ktime_add(ktime_get(), + ktime_set(0, event_delays_ns[event])); + fotg210->enabled_hrtimer_events |= (1 << event); + + /* Track only the lowest-numbered pending event */ + if (event < fotg210->next_hrtimer_event) { + fotg210->next_hrtimer_event = event; + hrtimer_start_range_ns(&fotg210->hrtimer, *timeout, + NSEC_PER_MSEC, HRTIMER_MODE_ABS); + } +} + + +/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */ +static void fotg210_poll_ASS(struct fotg210_hcd *fotg210) +{ + unsigned actual, want; + + /* Don't enable anything if the controller isn't running (e.g., died) */ + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + want = (fotg210->command & CMD_ASE) ? STS_ASS : 0; + actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (fotg210->ASS_poll_count++ < 20) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS, + true); + return; + } + fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n", + want, actual); + } + fotg210->ASS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + if (fotg210->async_count > 0) + fotg210_set_command_bit(fotg210, CMD_ASE); + + } else { /* Running */ + if (fotg210->async_count == 0) { + + /* Turn off the schedule after a while */ + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_DISABLE_ASYNC, + true); + } + } +} + +/* Turn off the async schedule after a brief delay */ +static void fotg210_disable_ASE(struct fotg210_hcd *fotg210) +{ + fotg210_clear_command_bit(fotg210, CMD_ASE); +} + + +/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ +static void fotg210_poll_PSS(struct fotg210_hcd *fotg210) +{ + unsigned actual, want; + + /* Don't do anything if the controller isn't running (e.g., died) */ + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + want = (fotg210->command & CMD_PSE) ? STS_PSS : 0; + actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (fotg210->PSS_poll_count++ < 20) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS, + true); + return; + } + fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n", + want, actual); + } + fotg210->PSS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + if (fotg210->periodic_count > 0) + fotg210_set_command_bit(fotg210, CMD_PSE); + + } else { /* Running */ + if (fotg210->periodic_count == 0) { + + /* Turn off the schedule after a while */ + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_DISABLE_PERIODIC, + true); + } + } +} + +/* Turn off the periodic schedule after a brief delay */ +static void fotg210_disable_PSE(struct fotg210_hcd *fotg210) +{ + fotg210_clear_command_bit(fotg210, CMD_PSE); +} + + +/* Poll the STS_HALT status bit; see when a dead controller stops */ +static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210) +{ + if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) { + + /* Give up after a few milliseconds */ + if (fotg210->died_poll_count++ < 5) { + /* Try again later */ + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_POLL_DEAD, true); + return; + } + fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n"); + } + + /* Clean up the mess */ + fotg210->rh_state = FOTG210_RH_HALTED; + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); + fotg210_work(fotg210); + end_unlink_async(fotg210); + + /* Not in process context, so don't try to reset the controller */ +} + + +/* Handle unlinked interrupt QHs once they are gone from the hardware */ +static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210) +{ + bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); + + /* + * Process all the QHs on the intr_unlink list that were added + * before the current unlink cycle began. The list is in + * temporal order, so stop when we reach the first entry in the + * current cycle. But if the root hub isn't running then + * process all the QHs on the list. + */ + fotg210->intr_unlinking = true; + while (fotg210->intr_unlink) { + struct fotg210_qh *qh = fotg210->intr_unlink; + + if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle) + break; + fotg210->intr_unlink = qh->unlink_next; + qh->unlink_next = NULL; + end_unlink_intr(fotg210, qh); + } + + /* Handle remaining entries later */ + if (fotg210->intr_unlink) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, + true); + ++fotg210->intr_unlink_cycle; + } + fotg210->intr_unlinking = false; +} + + +/* Start another free-iTDs/siTDs cycle */ +static void start_free_itds(struct fotg210_hcd *fotg210) +{ + if (!(fotg210->enabled_hrtimer_events & + BIT(FOTG210_HRTIMER_FREE_ITDS))) { + fotg210->last_itd_to_free = list_entry( + fotg210->cached_itd_list.prev, + struct fotg210_itd, itd_list); + fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true); + } +} + +/* Wait for controller to stop using old iTDs and siTDs */ +static void end_free_itds(struct fotg210_hcd *fotg210) +{ + struct fotg210_itd *itd, *n; + + if (fotg210->rh_state < FOTG210_RH_RUNNING) + fotg210->last_itd_to_free = NULL; + + list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) { + list_del(&itd->itd_list); + dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma); + if (itd == fotg210->last_itd_to_free) + break; + } + + if (!list_empty(&fotg210->cached_itd_list)) + start_free_itds(fotg210); +} + + +/* Handle lost (or very late) IAA interrupts */ +static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210) +{ + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + /* + * Lost IAA irqs wedge things badly; seen first with a vt8235. + * So we need this watchdog, but must protect it against both + * (a) SMP races against real IAA firing and retriggering, and + * (b) clean HC shutdown, when IAA watchdog was pending. + */ + if (fotg210->async_iaa) { + u32 cmd, status; + + /* If we get here, IAA is *REALLY* late. It's barely + * conceivable that the system is so busy that CMD_IAAD + * is still legitimately set, so let's be sure it's + * clear before we read STS_IAA. (The HC should clear + * CMD_IAAD when it sets STS_IAA.) + */ + cmd = fotg210_readl(fotg210, &fotg210->regs->command); + + /* + * If IAA is set here it either legitimately triggered + * after the watchdog timer expired (_way_ late, so we'll + * still count it as lost) ... or a silicon erratum: + * - VIA seems to set IAA without triggering the IRQ; + * - IAAD potentially cleared without setting IAA. + */ + status = fotg210_readl(fotg210, &fotg210->regs->status); + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { + COUNT(fotg210->stats.lost_iaa); + fotg210_writel(fotg210, STS_IAA, + &fotg210->regs->status); + } + + fotg210_dbg(fotg210, "IAA watchdog: status %x cmd %x\n", + status, cmd); + end_unlink_async(fotg210); + } +} + + +/* Enable the I/O watchdog, if appropriate */ +static void turn_on_io_watchdog(struct fotg210_hcd *fotg210) +{ + /* Not needed if the controller isn't running or it's already enabled */ + if (fotg210->rh_state != FOTG210_RH_RUNNING || + (fotg210->enabled_hrtimer_events & + BIT(FOTG210_HRTIMER_IO_WATCHDOG))) + return; + + /* + * Isochronous transfers always need the watchdog. + * For other sorts we use it only if the flag is set. + */ + if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog && + fotg210->async_count + fotg210->intr_count > 0)) + fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG, + true); +} + + +/* + * Handler functions for the hrtimer event types. + * Keep this array in the same order as the event types indexed by + * enum fotg210_hrtimer_event in fotg210.h. + */ +static void (*event_handlers[])(struct fotg210_hcd *) = { + fotg210_poll_ASS, /* FOTG210_HRTIMER_POLL_ASS */ + fotg210_poll_PSS, /* FOTG210_HRTIMER_POLL_PSS */ + fotg210_handle_controller_death, /* FOTG210_HRTIMER_POLL_DEAD */ + fotg210_handle_intr_unlinks, /* FOTG210_HRTIMER_UNLINK_INTR */ + end_free_itds, /* FOTG210_HRTIMER_FREE_ITDS */ + unlink_empty_async, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ + fotg210_iaa_watchdog, /* FOTG210_HRTIMER_IAA_WATCHDOG */ + fotg210_disable_PSE, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ + fotg210_disable_ASE, /* FOTG210_HRTIMER_DISABLE_ASYNC */ + fotg210_work, /* FOTG210_HRTIMER_IO_WATCHDOG */ +}; + +static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t) +{ + struct fotg210_hcd *fotg210 = + container_of(t, struct fotg210_hcd, hrtimer); + ktime_t now; + unsigned long events; + unsigned long flags; + unsigned e; + + spin_lock_irqsave(&fotg210->lock, flags); + + events = fotg210->enabled_hrtimer_events; + fotg210->enabled_hrtimer_events = 0; + fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; + + /* + * Check each pending event. If its time has expired, handle + * the event; otherwise re-enable it. + */ + now = ktime_get(); + for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) { + if (now.tv64 >= fotg210->hr_timeouts[e].tv64) + event_handlers[e](fotg210); + else + fotg210_enable_event(fotg210, e, false); + } + + spin_unlock_irqrestore(&fotg210->lock, flags); + return HRTIMER_NORESTART; +} + +/*-------------------------------------------------------------------------*/ + +#define fotg210_bus_suspend NULL +#define fotg210_bus_resume NULL + +/*-------------------------------------------------------------------------*/ + +static int check_reset_complete( + struct fotg210_hcd *fotg210, + int index, + u32 __iomem *status_reg, + int port_status +) { + if (!(port_status & PORT_CONNECT)) + return port_status; + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + /* with integrated TT, there's nobody to hand it to! */ + fotg210_dbg(fotg210, + "Failed to enable port %d on root hub TT\n", + index+1); + return port_status; + } else { + fotg210_dbg(fotg210, "port %d reset complete, port enabled\n", + index + 1); + } + + return port_status; +} + +/*-------------------------------------------------------------------------*/ + + +/* build "status change" packet (one or two bytes) from HC registers */ + +static int +fotg210_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 temp, status; + u32 mask; + int retval = 1; + unsigned long flags; + + /* init status to no-changes */ + buf[0] = 0; + + /* Inform the core about resumes-in-progress by returning + * a non-zero value even if there are no status changes. + */ + status = fotg210->resuming_ports; + + mask = PORT_CSC | PORT_PEC; + /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */ + + /* no hub change reports (bit 0) for now (power, ...) */ + + /* port N changes (bit N)? */ + spin_lock_irqsave(&fotg210->lock, flags); + + temp = fotg210_readl(fotg210, &fotg210->regs->port_status); + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + + if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend) + || (fotg210->reset_done[0] && time_after_eq( + jiffies, fotg210->reset_done[0]))) { + buf[0] |= 1 << 1; + status = STS_PCD; + } + /* FIXME autosuspend idle root hubs */ + spin_unlock_irqrestore(&fotg210->lock, flags); + return status ? retval : 0; +} + +/*-------------------------------------------------------------------------*/ + +static void +fotg210_hub_descriptor( + struct fotg210_hcd *fotg210, + struct usb_hub_descriptor *desc +) { + int ports = HCS_N_PORTS(fotg210->hcs_params); + u16 temp; + + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = 10; /* fotg210 1.0, 2.3.9 says 20ms max */ + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); + + temp = 0x0008; /* per-port overcurrent reporting */ + temp |= 0x0002; /* no power switching */ + desc->wHubCharacteristics = cpu_to_le16(temp); +} + +/*-------------------------------------------------------------------------*/ + +static int fotg210_hub_control( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + int ports = HCS_N_PORTS(fotg210->hcs_params); + u32 __iomem *status_reg = &fotg210->regs->port_status; + u32 temp, temp1, status; + unsigned long flags; + int retval = 0; + unsigned selector; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave(&fotg210->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = fotg210_readl(fotg210, status_reg); + temp &= ~PORT_RWC_BITS; + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_STAT_C_CONNECTION). + */ + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + fotg210_writel(fotg210, temp & ~PORT_PE, status_reg); + break; + case USB_PORT_FEAT_C_ENABLE: + fotg210_writel(fotg210, temp | PORT_PEC, status_reg); + break; + case USB_PORT_FEAT_SUSPEND: + if (temp & PORT_RESET) + goto error; + if (!(temp & PORT_SUSPEND)) + break; + if ((temp & PORT_PE) == 0) + goto error; + + /* resume signaling for 20 msec */ + fotg210_writel(fotg210, temp | PORT_RESUME, status_reg); + fotg210->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + break; + case USB_PORT_FEAT_C_SUSPEND: + clear_bit(wIndex, &fotg210->port_c_suspend); + break; + case USB_PORT_FEAT_C_CONNECTION: + fotg210_writel(fotg210, temp | PORT_CSC, status_reg); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + fotg210_writel(fotg210, temp | OTGISR_OVC, + &fotg210->regs->otgisr); + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + fotg210_readl(fotg210, &fotg210->regs->command); + break; + case GetHubDescriptor: + fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset(buf, 0, 4); + /*cpu_to_le32s ((u32 *) buf); */ + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + status = 0; + temp = fotg210_readl(fotg210, status_reg); + + /* wPortChange bits */ + if (temp & PORT_CSC) + status |= USB_PORT_STAT_C_CONNECTION << 16; + if (temp & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + + temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); + if (temp1 & OTGISR_OVC) + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + + /* whoever resumes must GetPortStatus to complete it!! */ + if (temp & PORT_RESUME) { + + /* Remote Wakeup received? */ + if (!fotg210->reset_done[wIndex]) { + /* resume signaling for 20 msec */ + fotg210->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&fotg210_to_hcd(fotg210)->rh_timer, + fotg210->reset_done[wIndex]); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + fotg210->reset_done[wIndex])) { + clear_bit(wIndex, &fotg210->suspended_ports); + set_bit(wIndex, &fotg210->port_c_suspend); + fotg210->reset_done[wIndex] = 0; + + /* stop resume signaling */ + temp = fotg210_readl(fotg210, status_reg); + fotg210_writel(fotg210, + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + clear_bit(wIndex, &fotg210->resuming_ports); + retval = handshake(fotg210, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + fotg210_err(fotg210, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); + } + } + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && time_after_eq(jiffies, + fotg210->reset_done[wIndex])) { + status |= USB_PORT_STAT_C_RESET << 16; + fotg210->reset_done[wIndex] = 0; + clear_bit(wIndex, &fotg210->resuming_ports); + + /* force reset to complete */ + fotg210_writel(fotg210, + temp & ~(PORT_RWC_BITS | PORT_RESET), + status_reg); + /* REVISIT: some hardware needs 550+ usec to clear + * this bit; seems too long to spin routinely... + */ + retval = handshake(fotg210, status_reg, + PORT_RESET, 0, 1000); + if (retval != 0) { + fotg210_err(fotg210, "port %d reset error %d\n", + wIndex + 1, retval); + goto error; + } + + /* see what we found out */ + temp = check_reset_complete(fotg210, wIndex, status_reg, + fotg210_readl(fotg210, status_reg)); + } + + if (!(temp & (PORT_RESUME|PORT_RESET))) { + fotg210->reset_done[wIndex] = 0; + clear_bit(wIndex, &fotg210->resuming_ports); + } + + /* transfer dedicated ports to the companion hc */ + if ((temp & PORT_CONNECT) && + test_bit(wIndex, &fotg210->companion_ports)) { + temp &= ~PORT_RWC_BITS; + fotg210_writel(fotg210, temp, status_reg); + fotg210_dbg(fotg210, "port %d --> companion\n", + wIndex + 1); + temp = fotg210_readl(fotg210, status_reg); + } + + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_CONNECT) { + status |= USB_PORT_STAT_CONNECTION; + status |= fotg210_port_speed(fotg210, temp); + } + if (temp & PORT_PE) + status |= USB_PORT_STAT_ENABLE; + + /* maybe the port was unsuspended without our knowledge */ + if (temp & (PORT_SUSPEND|PORT_RESUME)) { + status |= USB_PORT_STAT_SUSPEND; + } else if (test_bit(wIndex, &fotg210->suspended_ports)) { + clear_bit(wIndex, &fotg210->suspended_ports); + clear_bit(wIndex, &fotg210->resuming_ports); + fotg210->reset_done[wIndex] = 0; + if (temp & PORT_PE) + set_bit(wIndex, &fotg210->port_c_suspend); + } + + temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); + if (temp1 & OTGISR_OVC) + status |= USB_PORT_STAT_OVERCURRENT; + if (temp & PORT_RESET) + status |= USB_PORT_STAT_RESET; + if (test_bit(wIndex, &fotg210->port_c_suspend)) + status |= USB_PORT_STAT_C_SUSPEND << 16; + + if (status & ~0xffff) /* only if wPortChange is interesting */ + dbg_port(fotg210, "GetStatus", wIndex + 1, temp); + put_unaligned_le32(status, buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + selector = wIndex >> 8; + wIndex &= 0xff; + + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = fotg210_readl(fotg210, status_reg); + temp &= ~PORT_RWC_BITS; + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + if ((temp & PORT_PE) == 0 + || (temp & PORT_RESET) != 0) + goto error; + + /* After above check the port must be connected. + * Set appropriate bit thus could put phy into low power + * mode if we have hostpc feature + */ + fotg210_writel(fotg210, temp | PORT_SUSPEND, + status_reg); + set_bit(wIndex, &fotg210->suspended_ports); + break; + case USB_PORT_FEAT_RESET: + if (temp & PORT_RESUME) + goto error; + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ + fotg210_dbg(fotg210, "port %d reset\n", wIndex + 1); + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + fotg210->reset_done[wIndex] = jiffies + + msecs_to_jiffies(50); + fotg210_writel(fotg210, temp, status_reg); + break; + + /* For downstream facing ports (these): one hub port is put + * into test mode according to USB2 11.24.2.13, then the hub + * must be reset (which for root hub now means rmmod+modprobe, + * or else system reboot). See EHCI 2.3.9 and 4.14 for info + * about the EHCI-specific stuff. + */ + case USB_PORT_FEAT_TEST: + if (!selector || selector > 5) + goto error; + spin_unlock_irqrestore(&fotg210->lock, flags); + fotg210_quiesce(fotg210); + spin_lock_irqsave(&fotg210->lock, flags); + + /* Put all enabled ports into suspend */ + temp = fotg210_readl(fotg210, status_reg) & + ~PORT_RWC_BITS; + if (temp & PORT_PE) + fotg210_writel(fotg210, temp | PORT_SUSPEND, + status_reg); + + spin_unlock_irqrestore(&fotg210->lock, flags); + fotg210_halt(fotg210); + spin_lock_irqsave(&fotg210->lock, flags); + + temp = fotg210_readl(fotg210, status_reg); + temp |= selector << 16; + fotg210_writel(fotg210, temp, status_reg); + break; + + default: + goto error; + } + fotg210_readl(fotg210, &fotg210->regs->command); + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore(&fotg210->lock, flags); + return retval; +} + +static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd, + int portnum) +{ + return; +} + +static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd, + int portnum) +{ + return 0; +} +/*-------------------------------------------------------------------------*/ +/* + * There's basically three types of memory: + * - data used only by the HCD ... kmalloc is fine + * - async and periodic schedules, shared by HC and HCD ... these + * need to use dma_pool or dma_alloc_coherent + * - driver buffers, read/written by HC ... single shot DMA mapped + * + * There's also "register" data (e.g. PCI or SOC), which is memory mapped. + * No memory seen by this driver is pageable. + */ + +/*-------------------------------------------------------------------------*/ + +/* Allocate the key transfer structures from the previously allocated pool */ + +static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210, + struct fotg210_qtd *qtd, dma_addr_t dma) +{ + memset(qtd, 0, sizeof(*qtd)); + qtd->qtd_dma = dma; + qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); + qtd->hw_next = FOTG210_LIST_END(fotg210); + qtd->hw_alt_next = FOTG210_LIST_END(fotg210); + INIT_LIST_HEAD(&qtd->qtd_list); +} + +static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210, + gfp_t flags) +{ + struct fotg210_qtd *qtd; + dma_addr_t dma; + + qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma); + if (qtd != NULL) + fotg210_qtd_init(fotg210, qtd, dma); + + return qtd; +} + +static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210, + struct fotg210_qtd *qtd) +{ + dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma); +} + + +static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + /* clean qtds first, and know this is not linked */ + if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) { + fotg210_dbg(fotg210, "unused qh not empty!\n"); + BUG(); + } + if (qh->dummy) + fotg210_qtd_free(fotg210, qh->dummy); + dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); + kfree(qh); +} + +static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210, + gfp_t flags) +{ + struct fotg210_qh *qh; + dma_addr_t dma; + + qh = kzalloc(sizeof(*qh), GFP_ATOMIC); + if (!qh) + goto done; + qh->hw = (struct fotg210_qh_hw *) + dma_pool_alloc(fotg210->qh_pool, flags, &dma); + if (!qh->hw) + goto fail; + memset(qh->hw, 0, sizeof(*qh->hw)); + qh->qh_dma = dma; + INIT_LIST_HEAD(&qh->qtd_list); + + /* dummy td enables safe urb queuing */ + qh->dummy = fotg210_qtd_alloc(fotg210, flags); + if (qh->dummy == NULL) { + fotg210_dbg(fotg210, "no dummy td\n"); + goto fail1; + } +done: + return qh; +fail1: + dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); +fail: + kfree(qh); + return NULL; +} + +/*-------------------------------------------------------------------------*/ + +/* The queue heads and transfer descriptors are managed from pools tied + * to each of the "per device" structures. + * This is the initialisation and cleanup code. + */ + +static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210) +{ + if (fotg210->async) + qh_destroy(fotg210, fotg210->async); + fotg210->async = NULL; + + if (fotg210->dummy) + qh_destroy(fotg210, fotg210->dummy); + fotg210->dummy = NULL; + + /* DMA consistent memory and pools */ + if (fotg210->qtd_pool) + dma_pool_destroy(fotg210->qtd_pool); + fotg210->qtd_pool = NULL; + + if (fotg210->qh_pool) { + dma_pool_destroy(fotg210->qh_pool); + fotg210->qh_pool = NULL; + } + + if (fotg210->itd_pool) + dma_pool_destroy(fotg210->itd_pool); + fotg210->itd_pool = NULL; + + if (fotg210->periodic) + dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller, + fotg210->periodic_size * sizeof(u32), + fotg210->periodic, fotg210->periodic_dma); + fotg210->periodic = NULL; + + /* shadow periodic table */ + kfree(fotg210->pshadow); + fotg210->pshadow = NULL; +} + +/* remember to add cleanup code (above) if you add anything here */ +static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags) +{ + int i; + + /* QTDs for control/bulk/intr transfers */ + fotg210->qtd_pool = dma_pool_create("fotg210_qtd", + fotg210_to_hcd(fotg210)->self.controller, + sizeof(struct fotg210_qtd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fotg210->qtd_pool) + goto fail; + + /* QHs for control/bulk/intr transfers */ + fotg210->qh_pool = dma_pool_create("fotg210_qh", + fotg210_to_hcd(fotg210)->self.controller, + sizeof(struct fotg210_qh_hw), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fotg210->qh_pool) + goto fail; + + fotg210->async = fotg210_qh_alloc(fotg210, flags); + if (!fotg210->async) + goto fail; + + /* ITD for high speed ISO transfers */ + fotg210->itd_pool = dma_pool_create("fotg210_itd", + fotg210_to_hcd(fotg210)->self.controller, + sizeof(struct fotg210_itd), + 64 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fotg210->itd_pool) + goto fail; + + /* Hardware periodic table */ + fotg210->periodic = (__le32 *) + dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller, + fotg210->periodic_size * sizeof(__le32), + &fotg210->periodic_dma, 0); + if (fotg210->periodic == NULL) + goto fail; + + for (i = 0; i < fotg210->periodic_size; i++) + fotg210->periodic[i] = FOTG210_LIST_END(fotg210); + + /* software shadow of hardware table */ + fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *), + flags); + if (fotg210->pshadow != NULL) + return 0; + +fail: + fotg210_dbg(fotg210, "couldn't init memory\n"); + fotg210_mem_cleanup(fotg210); + return -ENOMEM; +} +/*-------------------------------------------------------------------------*/ +/* + * EHCI hardware queue manipulation ... the core. QH/QTD manipulation. + * + * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" + * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned + * buffers needed for the larger number). We use one QH per endpoint, queue + * multiple urbs (all three types) per endpoint. URBs may need several qtds. + * + * ISO traffic uses "ISO TD" (itd) records, and (along with + * interrupts) needs careful scheduling. Performance improvements can be + * an ongoing challenge. That's in "ehci-sched.c". + * + * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, + * or otherwise through transaction translators (TTs) in USB 2.0 hubs using + * (b) special fields in qh entries or (c) split iso entries. TTs will + * buffer low/full speed data so the host collects it at high speed. + */ + +/*-------------------------------------------------------------------------*/ + +/* fill a qtd, returning how much of the buffer we were able to queue up */ + +static int +qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, dma_addr_t buf, + size_t len, int token, int maxpacket) +{ + int i, count; + u64 addr = buf; + + /* one buffer entry per 4K ... first might be short or unaligned */ + qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr); + qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32)); + count = 0x1000 - (buf & 0x0fff); /* rest of that page */ + if (likely(len < count)) /* ... iff needed */ + count = len; + else { + buf += 0x1000; + buf &= ~0x0fff; + + /* per-qtd limit: from 16K to 20K (best alignment) */ + for (i = 1; count < len && i < 5; i++) { + addr = buf; + qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr); + qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210, + (u32)(addr >> 32)); + buf += 0x1000; + if ((count + 0x1000) < len) + count += 0x1000; + else + count = len; + } + + /* short packets may only terminate transfers */ + if (count != len) + count -= (count % maxpacket); + } + qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token); + qtd->length = count; + + return count; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +qh_update(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, + struct fotg210_qtd *qtd) +{ + struct fotg210_qh_hw *hw = qh->hw; + + /* writes to an active overlay are unsafe */ + BUG_ON(qh->qh_state != QH_STATE_IDLE); + + hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma); + hw->hw_alt_next = FOTG210_LIST_END(fotg210); + + /* Except for control endpoints, we make hardware maintain data + * toggle (like OHCI) ... here (re)initialize the toggle in the QH, + * and set the pseudo-toggle in udev. Only usb_clear_halt() will + * ever clear it. + */ + if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) { + unsigned is_out, epnum; + + is_out = qh->is_out; + epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f; + if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) { + hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE); + usb_settoggle(qh->dev, epnum, is_out, 1); + } + } + + hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING); +} + +/* if it weren't for a common silicon quirk (writing the dummy into the qh + * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault + * recovery (including urb dequeue) would need software changes to a QH... + */ +static void +qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qtd *qtd; + + if (list_empty(&qh->qtd_list)) + qtd = qh->dummy; + else { + qtd = list_entry(qh->qtd_list.next, + struct fotg210_qtd, qtd_list); + /* + * first qtd may already be partially processed. + * If we come here during unlink, the QH overlay region + * might have reference to the just unlinked qtd. The + * qtd is updated in qh_completions(). Update the QH + * overlay here. + */ + if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) { + qh->hw->hw_qtd_next = qtd->hw_next; + qtd = NULL; + } + } + + if (qtd) + qh_update(fotg210, qh, qtd); +} + +/*-------------------------------------------------------------------------*/ + +static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); + +static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct fotg210_qh *qh = ep->hcpriv; + unsigned long flags; + + spin_lock_irqsave(&fotg210->lock, flags); + qh->clearing_tt = 0; + if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) + && fotg210->rh_state == FOTG210_RH_RUNNING) + qh_link_async(fotg210, qh); + spin_unlock_irqrestore(&fotg210->lock, flags); +} + +static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh, + struct urb *urb, u32 token) +{ + + /* If an async split transaction gets an error or is unlinked, + * the TT buffer may be left in an indeterminate state. We + * have to clear the TT buffer. + * + * Note: this routine is never called for Isochronous transfers. + */ + if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { + struct usb_device *tt = urb->dev->tt->hub; + dev_dbg(&tt->dev, + "clear tt buffer port %d, a%d ep%d t%08x\n", + urb->dev->ttport, urb->dev->devnum, + usb_pipeendpoint(urb->pipe), token); + + if (urb->dev->tt->hub != + fotg210_to_hcd(fotg210)->self.root_hub) { + if (usb_hub_clear_tt_buffer(urb) == 0) + qh->clearing_tt = 1; + } + } +} + +static int qtd_copy_status( + struct fotg210_hcd *fotg210, + struct urb *urb, + size_t length, + u32 token +) +{ + int status = -EINPROGRESS; + + /* count IN/OUT bytes, not SETUP (even short packets) */ + if (likely(QTD_PID(token) != 2)) + urb->actual_length += length - QTD_LENGTH(token); + + /* don't modify error codes */ + if (unlikely(urb->unlinked)) + return status; + + /* force cleanup after short read; not always an error */ + if (unlikely(IS_SHORT_READ(token))) + status = -EREMOTEIO; + + /* serious "can't proceed" faults reported by the hardware */ + if (token & QTD_STS_HALT) { + if (token & QTD_STS_BABBLE) { + /* FIXME "must" disable babbling device's port too */ + status = -EOVERFLOW; + /* CERR nonzero + halt --> stall */ + } else if (QTD_CERR(token)) { + status = -EPIPE; + + /* In theory, more than one of the following bits can be set + * since they are sticky and the transaction is retried. + * Which to test first is rather arbitrary. + */ + } else if (token & QTD_STS_MMF) { + /* fs/ls interrupt xfer missed the complete-split */ + status = -EPROTO; + } else if (token & QTD_STS_DBE) { + status = (QTD_PID(token) == 1) /* IN ? */ + ? -ENOSR /* hc couldn't read data */ + : -ECOMM; /* hc couldn't write data */ + } else if (token & QTD_STS_XACT) { + /* timeout, bad CRC, wrong PID, etc */ + fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n", + urb->dev->devpath, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out"); + status = -EPROTO; + } else { /* unknown */ + status = -EPROTO; + } + + fotg210_dbg(fotg210, + "dev%d ep%d%s qtd token %08x --> status %d\n", + usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + token, status); + } + + return status; +} + +static void +fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, int status) +__releases(fotg210->lock) +__acquires(fotg210->lock) +{ + if (likely(urb->hcpriv != NULL)) { + struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv; + + /* S-mask in a QH means it's an interrupt urb */ + if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) { + + /* ... update hc-wide periodic stats (for usbfs) */ + fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--; + } + } + + if (unlikely(urb->unlinked)) { + COUNT(fotg210->stats.unlink); + } else { + /* report non-error and short read status as zero */ + if (status == -EINPROGRESS || status == -EREMOTEIO) + status = 0; + COUNT(fotg210->stats.complete); + } + +#ifdef FOTG210_URB_TRACE + fotg210_dbg(fotg210, + "%s %s urb %p ep%d%s status %d len %d/%d\n", + __func__, urb->dev->devpath, urb, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + status, + urb->actual_length, urb->transfer_buffer_length); +#endif + + /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); + spin_unlock(&fotg210->lock); + usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status); + spin_lock(&fotg210->lock); +} + +static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); + +/* + * Process and free completed qtds for a qh, returning URBs to drivers. + * Chases up to qh->hw_current. Returns number of completions called, + * indicating how much "real" work we did. + */ +static unsigned +qh_completions(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qtd *last, *end = qh->dummy; + struct list_head *entry, *tmp; + int last_status; + int stopped; + unsigned count = 0; + u8 state; + struct fotg210_qh_hw *hw = qh->hw; + + if (unlikely(list_empty(&qh->qtd_list))) + return count; + + /* completions (or tasks on other cpus) must never clobber HALT + * till we've gone through and cleaned everything up, even when + * they add urbs to this qh's queue or mark them for unlinking. + * + * NOTE: unlinking expects to be done in queue order. + * + * It's a bug for qh->qh_state to be anything other than + * QH_STATE_IDLE, unless our caller is scan_async() or + * scan_intr(). + */ + state = qh->qh_state; + qh->qh_state = QH_STATE_COMPLETING; + stopped = (state == QH_STATE_IDLE); + + rescan: + last = NULL; + last_status = -EINPROGRESS; + qh->needs_rescan = 0; + + /* remove de-activated QTDs from front of queue. + * after faults (including short reads), cleanup this urb + * then let the queue advance. + * if queue is stopped, handles unlinks. + */ + list_for_each_safe(entry, tmp, &qh->qtd_list) { + struct fotg210_qtd *qtd; + struct urb *urb; + u32 token = 0; + + qtd = list_entry(entry, struct fotg210_qtd, qtd_list); + urb = qtd->urb; + + /* clean up any state from previous QTD ...*/ + if (last) { + if (likely(last->urb != urb)) { + fotg210_urb_done(fotg210, last->urb, + last_status); + count++; + last_status = -EINPROGRESS; + } + fotg210_qtd_free(fotg210, last); + last = NULL; + } + + /* ignore urbs submitted during completions we reported */ + if (qtd == end) + break; + + /* hardware copies qtd out of qh overlay */ + rmb(); + token = hc32_to_cpu(fotg210, qtd->hw_token); + + /* always clean up qtds the hc de-activated */ + retry_xacterr: + if ((token & QTD_STS_ACTIVE) == 0) { + + /* Report Data Buffer Error: non-fatal but useful */ + if (token & QTD_STS_DBE) + fotg210_dbg(fotg210, + "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n", + urb, + usb_endpoint_num(&urb->ep->desc), + usb_endpoint_dir_in(&urb->ep->desc) + ? "in" : "out", + urb->transfer_buffer_length, + qtd, + qh); + + /* on STALL, error, and short reads this urb must + * complete and all its qtds must be recycled. + */ + if ((token & QTD_STS_HALT) != 0) { + + /* retry transaction errors until we + * reach the software xacterr limit + */ + if ((token & QTD_STS_XACT) && + QTD_CERR(token) == 0 && + ++qh->xacterrs < QH_XACTERR_MAX && + !urb->unlinked) { + fotg210_dbg(fotg210, + "detected XactErr len %zu/%zu retry %d\n", + qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs); + + /* reset the token in the qtd and the + * qh overlay (which still contains + * the qtd) so that we pick up from + * where we left off + */ + token &= ~QTD_STS_HALT; + token |= QTD_STS_ACTIVE | + (FOTG210_TUNE_CERR << 10); + qtd->hw_token = cpu_to_hc32(fotg210, + token); + wmb(); + hw->hw_token = cpu_to_hc32(fotg210, + token); + goto retry_xacterr; + } + stopped = 1; + + /* magic dummy for some short reads; qh won't advance. + * that silicon quirk can kick in with this dummy too. + * + * other short reads won't stop the queue, including + * control transfers (status stage handles that) or + * most other single-qtd reads ... the queue stops if + * URB_SHORT_NOT_OK was set so the driver submitting + * the urbs could clean it up. + */ + } else if (IS_SHORT_READ(token) + && !(qtd->hw_alt_next + & FOTG210_LIST_END(fotg210))) { + stopped = 1; + } + + /* stop scanning when we reach qtds the hc is using */ + } else if (likely(!stopped + && fotg210->rh_state >= FOTG210_RH_RUNNING)) { + break; + + /* scan the whole queue for unlinks whenever it stops */ + } else { + stopped = 1; + + /* cancel everything if we halt, suspend, etc */ + if (fotg210->rh_state < FOTG210_RH_RUNNING) + last_status = -ESHUTDOWN; + + /* this qtd is active; skip it unless a previous qtd + * for its urb faulted, or its urb was canceled. + */ + else if (last_status == -EINPROGRESS && !urb->unlinked) + continue; + + /* qh unlinked; token in overlay may be most current */ + if (state == QH_STATE_IDLE + && cpu_to_hc32(fotg210, qtd->qtd_dma) + == hw->hw_current) { + token = hc32_to_cpu(fotg210, hw->hw_token); + + /* An unlink may leave an incomplete + * async transaction in the TT buffer. + * We have to clear it. + */ + fotg210_clear_tt_buffer(fotg210, qh, urb, + token); + } + } + + /* unless we already know the urb's status, collect qtd status + * and update count of bytes transferred. in common short read + * cases with only one data qtd (including control transfers), + * queue processing won't halt. but with two or more qtds (for + * example, with a 32 KB transfer), when the first qtd gets a + * short read the second must be removed by hand. + */ + if (last_status == -EINPROGRESS) { + last_status = qtd_copy_status(fotg210, urb, + qtd->length, token); + if (last_status == -EREMOTEIO + && (qtd->hw_alt_next + & FOTG210_LIST_END(fotg210))) + last_status = -EINPROGRESS; + + /* As part of low/full-speed endpoint-halt processing + * we must clear the TT buffer (11.17.5). + */ + if (unlikely(last_status != -EINPROGRESS && + last_status != -EREMOTEIO)) { + /* The TT's in some hubs malfunction when they + * receive this request following a STALL (they + * stop sending isochronous packets). Since a + * STALL can't leave the TT buffer in a busy + * state (if you believe Figures 11-48 - 11-51 + * in the USB 2.0 spec), we won't clear the TT + * buffer in this case. Strictly speaking this + * is a violation of the spec. + */ + if (last_status != -EPIPE) + fotg210_clear_tt_buffer(fotg210, qh, + urb, token); + } + } + + /* if we're removing something not at the queue head, + * patch the hardware queue pointer. + */ + if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { + last = list_entry(qtd->qtd_list.prev, + struct fotg210_qtd, qtd_list); + last->hw_next = qtd->hw_next; + } + + /* remove qtd; it's recycled after possible urb completion */ + list_del(&qtd->qtd_list); + last = qtd; + + /* reinit the xacterr counter for the next qtd */ + qh->xacterrs = 0; + } + + /* last urb's completion might still need calling */ + if (likely(last != NULL)) { + fotg210_urb_done(fotg210, last->urb, last_status); + count++; + fotg210_qtd_free(fotg210, last); + } + + /* Do we need to rescan for URBs dequeued during a giveback? */ + if (unlikely(qh->needs_rescan)) { + /* If the QH is already unlinked, do the rescan now. */ + if (state == QH_STATE_IDLE) + goto rescan; + + /* Otherwise we have to wait until the QH is fully unlinked. + * Our caller will start an unlink if qh->needs_rescan is + * set. But if an unlink has already started, nothing needs + * to be done. + */ + if (state != QH_STATE_LINKED) + qh->needs_rescan = 0; + } + + /* restore original state; caller must unlink or relink */ + qh->qh_state = state; + + /* be sure the hardware's done with the qh before refreshing + * it after fault cleanup, or recovering from silicon wrongly + * overlaying the dummy qtd (which reduces DMA chatter). + */ + if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) { + switch (state) { + case QH_STATE_IDLE: + qh_refresh(fotg210, qh); + break; + case QH_STATE_LINKED: + /* We won't refresh a QH that's linked (after the HC + * stopped the queue). That avoids a race: + * - HC reads first part of QH; + * - CPU updates that first part and the token; + * - HC reads rest of that QH, including token + * Result: HC gets an inconsistent image, and then + * DMAs to/from the wrong memory (corrupting it). + * + * That should be rare for interrupt transfers, + * except maybe high bandwidth ... + */ + + /* Tell the caller to start an unlink */ + qh->needs_rescan = 1; + break; + /* otherwise, unlink already started */ + } + } + + return count; +} + +/*-------------------------------------------------------------------------*/ + +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) +/* ... and packet size, for any kind of endpoint descriptor */ +#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) + +/* + * reverse of qh_urb_transaction: free a list of TDs. + * used for cleanup after errors, before HC sees an URB's TDs. + */ +static void qtd_list_free( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list +) { + struct list_head *entry, *temp; + + list_for_each_safe(entry, temp, qtd_list) { + struct fotg210_qtd *qtd; + + qtd = list_entry(entry, struct fotg210_qtd, qtd_list); + list_del(&qtd->qtd_list); + fotg210_qtd_free(fotg210, qtd); + } +} + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head * +qh_urb_transaction( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *head, + gfp_t flags +) { + struct fotg210_qtd *qtd, *qtd_prev; + dma_addr_t buf; + int len, this_sg_len, maxpacket; + int is_input; + u32 token; + int i; + struct scatterlist *sg; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + return NULL; + list_add_tail(&qtd->qtd_list, head); + qtd->urb = urb; + + token = QTD_STS_ACTIVE; + token |= (FOTG210_TUNE_CERR << 10); + /* for split transactions, SplitXState initialized to zero */ + + len = urb->transfer_buffer_length; + is_input = usb_pipein(urb->pipe); + if (usb_pipecontrol(urb->pipe)) { + /* SETUP pid */ + qtd_fill(fotg210, qtd, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + token | (2 /* "setup" */ << 8), 8); + + /* ... and always at least one more pid */ + token ^= QTD_TOGGLE; + qtd_prev = qtd; + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + + /* for zero length DATA stages, STATUS is always IN */ + if (len == 0) + token |= (1 /* "in" */ << 8); + } + + /* + * data transfer stage: buffer setup + */ + i = urb->num_mapped_sgs; + if (len > 0 && i > 0) { + sg = urb->sg; + buf = sg_dma_address(sg); + + /* urb->transfer_buffer_length may be smaller than the + * size of the scatterlist (or vice versa) + */ + this_sg_len = min_t(int, sg_dma_len(sg), len); + } else { + sg = NULL; + buf = urb->transfer_dma; + this_sg_len = len; + } + + if (is_input) + token |= (1 /* "in" */ << 8); + /* else it's already initted to "out" pid (0 << 8) */ + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token, + maxpacket); + this_sg_len -= this_qtd_len; + len -= this_qtd_len; + buf += this_qtd_len; + + /* + * short reads advance to a "magic" dummy instead of the next + * qtd ... that forces the queue to stop, for manual cleanup. + * (this will usually be overridden later.) + */ + if (is_input) + qtd->hw_alt_next = fotg210->async->hw->hw_alt_next; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= QTD_TOGGLE; + + if (likely(this_sg_len <= 0)) { + if (--i <= 0 || len <= 0) + break; + sg = sg_next(sg); + buf = sg_dma_address(sg); + this_sg_len = min_t(int, sg_dma_len(sg), len); + } + + qtd_prev = qtd; + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + } + + /* + * unless the caller requires manual cleanup after short reads, + * have the alt_next mechanism keep the queue running after the + * last data qtd (the only one, for control and most other cases). + */ + if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 + || usb_pipecontrol(urb->pipe))) + qtd->hw_alt_next = FOTG210_LIST_END(fotg210); + + /* + * control requests may need a terminating data "status" ack; + * other OUT ones may need a terminating short packet + * (zero length). + */ + if (likely(urb->transfer_buffer_length != 0)) { + int one_more = 0; + + if (usb_pipecontrol(urb->pipe)) { + one_more = 1; + token ^= 0x0100; /* "in" <--> "out" */ + token |= QTD_TOGGLE; /* force DATA1 */ + } else if (usb_pipeout(urb->pipe) + && (urb->transfer_flags & URB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill(fotg210, qtd, 0, 0, token, 0); + } + } + + /* by default, enable interrupt on urb completion */ + if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) + qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC); + return head; + +cleanup: + qtd_list_free(fotg210, urb, head); + return NULL; +} + +/*-------------------------------------------------------------------------*/ +/* + * Would be best to create all qh's from config descriptors, + * when each interface/altsetting is established. Unlink + * any previous qh and cancel its urbs first; endpoints are + * implicitly reset then (data toggle too). + * That'd mean updating how usbcore talks to HCDs. (2.7?) +*/ + + +/* + * Each QH holds a qtd list; a QH is used for everything except iso. + * + * For interrupt urbs, the scheduler must set the microframe scheduling + * mask(s) each time the QH gets scheduled. For highspeed, that's + * just one microframe in the s-mask. For split interrupt transactions + * there are additional complications: c-mask, maybe FSTNs. + */ +static struct fotg210_qh * +qh_make( + struct fotg210_hcd *fotg210, + struct urb *urb, + gfp_t flags +) { + struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags); + u32 info1 = 0, info2 = 0; + int is_input, type; + int maxp = 0; + struct usb_tt *tt = urb->dev->tt; + struct fotg210_qh_hw *hw; + + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + info1 |= usb_pipeendpoint(urb->pipe) << 8; + info1 |= usb_pipedevice(urb->pipe) << 0; + + is_input = usb_pipein(urb->pipe); + type = usb_pipetype(urb->pipe); + maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input); + + /* 1024 byte maxpacket is a hardware ceiling. High bandwidth + * acts like up to 3KB, but is built from smaller packets. + */ + if (max_packet(maxp) > 1024) { + fotg210_dbg(fotg210, "bogus qh maxpacket %d\n", + max_packet(maxp)); + goto done; + } + + /* Compute interrupt scheduling parameters just once, and save. + * - allowing for high bandwidth, how many nsec/uframe are used? + * - split transactions need a second CSPLIT uframe; same question + * - splits also need a schedule gap (for full/low speed I/O) + * - qh has a polling interval + * + * For control/bulk requests, the HC or TT handles these. + */ + if (type == PIPE_INTERRUPT) { + qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + is_input, 0, + hb_mult(maxp) * max_packet(maxp))); + qh->start = NO_FRAME; + + if (urb->dev->speed == USB_SPEED_HIGH) { + qh->c_usecs = 0; + qh->gap_uf = 0; + + qh->period = urb->interval >> 3; + if (qh->period == 0 && urb->interval != 1) { + /* NOTE interval 2 or 4 uframes could work. + * But interval 1 scheduling is simpler, and + * includes high bandwidth. + */ + urb->interval = 1; + } else if (qh->period > fotg210->periodic_size) { + qh->period = fotg210->periodic_size; + urb->interval = qh->period << 3; + } + } else { + int think_time; + + /* gap is f(FS/LS transfer times) */ + qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed, + is_input, 0, maxp) / (125 * 1000); + + /* FIXME this just approximates SPLIT/CSPLIT times */ + if (is_input) { /* SPLIT, gap, CSPLIT+DATA */ + qh->c_usecs = qh->usecs + HS_USECS(0); + qh->usecs = HS_USECS(1); + } else { /* SPLIT+DATA, gap, CSPLIT */ + qh->usecs += HS_USECS(1); + qh->c_usecs = HS_USECS(0); + } + + think_time = tt ? tt->think_time : 0; + qh->tt_usecs = NS_TO_US(think_time + + usb_calc_bus_time(urb->dev->speed, + is_input, 0, max_packet(maxp))); + qh->period = urb->interval; + if (qh->period > fotg210->periodic_size) { + qh->period = fotg210->periodic_size; + urb->interval = qh->period; + } + } + } + + /* support for tt scheduling, and access to toggles */ + qh->dev = urb->dev; + + /* using TT? */ + switch (urb->dev->speed) { + case USB_SPEED_LOW: + info1 |= QH_LOW_SPEED; + /* FALL THROUGH */ + + case USB_SPEED_FULL: + /* EPS 0 means "full" */ + if (type != PIPE_INTERRUPT) + info1 |= (FOTG210_TUNE_RL_TT << 28); + if (type == PIPE_CONTROL) { + info1 |= QH_CONTROL_EP; /* for TT */ + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ + } + info1 |= maxp << 16; + + info2 |= (FOTG210_TUNE_MULT_TT << 30); + + /* Some Freescale processors have an erratum in which the + * port number in the queue head was 0..N-1 instead of 1..N. + */ + if (fotg210_has_fsl_portno_bug(fotg210)) + info2 |= (urb->dev->ttport-1) << 23; + else + info2 |= urb->dev->ttport << 23; + + /* set the address of the TT; for TDI's integrated + * root hub tt, leave it zeroed. + */ + if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub) + info2 |= tt->hub->devnum << 16; + + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ + + break; + + case USB_SPEED_HIGH: /* no TT involved */ + info1 |= QH_HIGH_SPEED; + if (type == PIPE_CONTROL) { + info1 |= (FOTG210_TUNE_RL_HS << 28); + info1 |= 64 << 16; /* usb2 fixed maxpacket */ + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ + info2 |= (FOTG210_TUNE_MULT_HS << 30); + } else if (type == PIPE_BULK) { + info1 |= (FOTG210_TUNE_RL_HS << 28); + /* The USB spec says that high speed bulk endpoints + * always use 512 byte maxpacket. But some device + * vendors decided to ignore that, and MSFT is happy + * to help them do so. So now people expect to use + * such nonconformant devices with Linux too; sigh. + */ + info1 |= max_packet(maxp) << 16; + info2 |= (FOTG210_TUNE_MULT_HS << 30); + } else { /* PIPE_INTERRUPT */ + info1 |= max_packet(maxp) << 16; + info2 |= hb_mult(maxp) << 30; + } + break; + default: + fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev, + urb->dev->speed); +done: + qh_destroy(fotg210, qh); + return NULL; + } + + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ + + /* init as live, toggle clear, advance to dummy */ + qh->qh_state = QH_STATE_IDLE; + hw = qh->hw; + hw->hw_info1 = cpu_to_hc32(fotg210, info1); + hw->hw_info2 = cpu_to_hc32(fotg210, info2); + qh->is_out = !is_input; + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1); + qh_refresh(fotg210, qh); + return qh; +} + +/*-------------------------------------------------------------------------*/ + +static void enable_async(struct fotg210_hcd *fotg210) +{ + if (fotg210->async_count++) + return; + + /* Stop waiting to turn off the async schedule */ + fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC); + + /* Don't start the schedule until ASS is 0 */ + fotg210_poll_ASS(fotg210); + turn_on_io_watchdog(fotg210); +} + +static void disable_async(struct fotg210_hcd *fotg210) +{ + if (--fotg210->async_count) + return; + + /* The async schedule and async_unlink list are supposed to be empty */ + WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink); + + /* Don't turn off the schedule until ASS is 1 */ + fotg210_poll_ASS(fotg210); +} + +/* move qh (and its qtds) onto async queue; maybe enable queue. */ + +static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + __hc32 dma = QH_NEXT(fotg210, qh->qh_dma); + struct fotg210_qh *head; + + /* Don't link a QH if there's a Clear-TT-Buffer pending */ + if (unlikely(qh->clearing_tt)) + return; + + WARN_ON(qh->qh_state != QH_STATE_IDLE); + + /* clear halt and/or toggle; and maybe recover from silicon quirk */ + qh_refresh(fotg210, qh); + + /* splice right after start */ + head = fotg210->async; + qh->qh_next = head->qh_next; + qh->hw->hw_next = head->hw->hw_next; + wmb(); + + head->qh_next.qh = qh; + head->hw->hw_next = dma; + + qh->xacterrs = 0; + qh->qh_state = QH_STATE_LINKED; + /* qtd completions reported later by interrupt */ + + enable_async(fotg210); +} + +/*-------------------------------------------------------------------------*/ + +/* + * For control/bulk/interrupt, return QH with these TDs appended. + * Allocates and initializes the QH if necessary. + * Returns null if it can't allocate a QH it needs to. + * If the QH has TDs (urbs) already, that's great. + */ +static struct fotg210_qh *qh_append_tds( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list, + int epnum, + void **ptr +) +{ + struct fotg210_qh *qh = NULL; + __hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f); + + qh = (struct fotg210_qh *) *ptr; + if (unlikely(qh == NULL)) { + /* can't sleep here, we have fotg210->lock... */ + qh = qh_make(fotg210, urb, GFP_ATOMIC); + *ptr = qh; + } + if (likely(qh != NULL)) { + struct fotg210_qtd *qtd; + + if (unlikely(list_empty(qtd_list))) + qtd = NULL; + else + qtd = list_entry(qtd_list->next, struct fotg210_qtd, + qtd_list); + + /* control qh may need patching ... */ + if (unlikely(epnum == 0)) { + /* usb_reset_device() briefly reverts to address 0 */ + if (usb_pipedevice(urb->pipe) == 0) + qh->hw->hw_info1 &= ~qh_addr_mask; + } + + /* just one way to queue requests: swap with the dummy qtd. + * only hc or qh_refresh() ever modify the overlay. + */ + if (likely(qtd != NULL)) { + struct fotg210_qtd *dummy; + dma_addr_t dma; + __hc32 token; + + /* to avoid racing the HC, use the dummy td instead of + * the first td of our list (becomes new dummy). both + * tds stay deactivated until we're done, when the + * HC is allowed to fetch the old dummy (4.10.2). + */ + token = qtd->hw_token; + qtd->hw_token = HALT_BIT(fotg210); + + dummy = qh->dummy; + + dma = dummy->qtd_dma; + *dummy = *qtd; + dummy->qtd_dma = dma; + + list_del(&qtd->qtd_list); + list_add(&dummy->qtd_list, qtd_list); + list_splice_tail(qtd_list, &qh->qtd_list); + + fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma); + qh->dummy = qtd; + + /* hc must see the new dummy at list end */ + dma = qtd->qtd_dma; + qtd = list_entry(qh->qtd_list.prev, + struct fotg210_qtd, qtd_list); + qtd->hw_next = QTD_NEXT(fotg210, dma); + + /* let the hc process these next qtds */ + wmb(); + dummy->hw_token = token; + + urb->hcpriv = qh; + } + } + return qh; +} + +/*-------------------------------------------------------------------------*/ + +static int +submit_async( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list, + gfp_t mem_flags +) { + int epnum; + unsigned long flags; + struct fotg210_qh *qh = NULL; + int rc; + + epnum = urb->ep->desc.bEndpointAddress; + +#ifdef FOTG210_URB_TRACE + { + struct fotg210_qtd *qtd; + qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list); + fotg210_dbg(fotg210, + "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", + __func__, urb->dev->devpath, urb, + epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", + urb->transfer_buffer_length, + qtd, urb->ep->hcpriv); + } +#endif + + spin_lock_irqsave(&fotg210->lock, flags); + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { + rc = -ESHUTDOWN; + goto done; + } + rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); + if (unlikely(rc)) + goto done; + + qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); + if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); + rc = -ENOMEM; + goto done; + } + + /* Control/bulk operations through TTs don't need scheduling, + * the HC and TT handle it when the TT has a buffer ready. + */ + if (likely(qh->qh_state == QH_STATE_IDLE)) + qh_link_async(fotg210, qh); + done: + spin_unlock_irqrestore(&fotg210->lock, flags); + if (unlikely(qh == NULL)) + qtd_list_free(fotg210, urb, qtd_list); + return rc; +} + +/*-------------------------------------------------------------------------*/ + +static void single_unlink_async(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + struct fotg210_qh *prev; + + /* Add to the end of the list of QHs waiting for the next IAAD */ + qh->qh_state = QH_STATE_UNLINK; + if (fotg210->async_unlink) + fotg210->async_unlink_last->unlink_next = qh; + else + fotg210->async_unlink = qh; + fotg210->async_unlink_last = qh; + + /* Unlink it from the schedule */ + prev = fotg210->async; + while (prev->qh_next.qh != qh) + prev = prev->qh_next.qh; + + prev->hw->hw_next = qh->hw->hw_next; + prev->qh_next = qh->qh_next; + if (fotg210->qh_scan_next == qh) + fotg210->qh_scan_next = qh->qh_next.qh; +} + +static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested) +{ + /* + * Do nothing if an IAA cycle is already running or + * if one will be started shortly. + */ + if (fotg210->async_iaa || fotg210->async_unlinking) + return; + + /* Do all the waiting QHs at once */ + fotg210->async_iaa = fotg210->async_unlink; + fotg210->async_unlink = NULL; + + /* If the controller isn't running, we don't have to wait for it */ + if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) { + if (!nested) /* Avoid recursion */ + end_unlink_async(fotg210); + + /* Otherwise start a new IAA cycle */ + } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) { + /* Make sure the unlinks are all visible to the hardware */ + wmb(); + + fotg210_writel(fotg210, fotg210->command | CMD_IAAD, + &fotg210->regs->command); + fotg210_readl(fotg210, &fotg210->regs->command); + fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG, + true); + } +} + +/* the async qh for the qtds being unlinked are now gone from the HC */ + +static void end_unlink_async(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh; + + /* Process the idle QHs */ + restart: + fotg210->async_unlinking = true; + while (fotg210->async_iaa) { + qh = fotg210->async_iaa; + fotg210->async_iaa = qh->unlink_next; + qh->unlink_next = NULL; + + qh->qh_state = QH_STATE_IDLE; + qh->qh_next.qh = NULL; + + qh_completions(fotg210, qh); + if (!list_empty(&qh->qtd_list) && + fotg210->rh_state == FOTG210_RH_RUNNING) + qh_link_async(fotg210, qh); + disable_async(fotg210); + } + fotg210->async_unlinking = false; + + /* Start a new IAA cycle if any QHs are waiting for it */ + if (fotg210->async_unlink) { + start_iaa_cycle(fotg210, true); + if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) + goto restart; + } +} + +static void unlink_empty_async(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh, *next; + bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); + bool check_unlinks_later = false; + + /* Unlink all the async QHs that have been empty for a timer cycle */ + next = fotg210->async->qh_next.qh; + while (next) { + qh = next; + next = qh->qh_next.qh; + + if (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED) { + if (!stopped && qh->unlink_cycle == + fotg210->async_unlink_cycle) + check_unlinks_later = true; + else + single_unlink_async(fotg210, qh); + } + } + + /* Start a new IAA cycle if any QHs are waiting for it */ + if (fotg210->async_unlink) + start_iaa_cycle(fotg210, false); + + /* QHs that haven't been empty for long enough will be handled later */ + if (check_unlinks_later) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS, + true); + ++fotg210->async_unlink_cycle; + } +} + +/* makes sure the async qh will become idle */ +/* caller must own fotg210->lock */ + +static void start_unlink_async(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + /* + * If the QH isn't linked then there's nothing we can do + * unless we were called during a giveback, in which case + * qh_completions() has to deal with it. + */ + if (qh->qh_state != QH_STATE_LINKED) { + if (qh->qh_state == QH_STATE_COMPLETING) + qh->needs_rescan = 1; + return; + } + + single_unlink_async(fotg210, qh); + start_iaa_cycle(fotg210, false); +} + +/*-------------------------------------------------------------------------*/ + +static void scan_async(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh; + bool check_unlinks_later = false; + + fotg210->qh_scan_next = fotg210->async->qh_next.qh; + while (fotg210->qh_scan_next) { + qh = fotg210->qh_scan_next; + fotg210->qh_scan_next = qh->qh_next.qh; + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; + + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why fotg210->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then fotg210->qh_scan_next is adjusted + * in single_unlink_async(). + */ + temp = qh_completions(fotg210, qh); + if (qh->needs_rescan) { + start_unlink_async(fotg210, qh); + } else if (list_empty(&qh->qtd_list) + && qh->qh_state == QH_STATE_LINKED) { + qh->unlink_cycle = fotg210->async_unlink_cycle; + check_unlinks_later = true; + } else if (temp != 0) + goto rescan; + } + } + + /* + * Unlink empty entries, reducing DMA usage as well + * as HCD schedule-scanning costs. Delay for any qh + * we just scanned, there's a not-unusual case that it + * doesn't stay idle for long. + */ + if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING && + !(fotg210->enabled_hrtimer_events & + BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) { + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_ASYNC_UNLINKS, true); + ++fotg210->async_unlink_cycle; + } +} +/*-------------------------------------------------------------------------*/ +/* + * EHCI scheduled transaction support: interrupt, iso, split iso + * These are called "periodic" transactions in the EHCI spec. + * + * Note that for interrupt transfers, the QH/QTD manipulation is shared + * with the "asynchronous" transaction support (control/bulk transfers). + * The only real difference is in how interrupt transfers are scheduled. + * + * For ISO, we make an "iso_stream" head to serve the same role as a QH. + * It keeps track of every ITD (or SITD) that's linked, and holds enough + * pre-calculated schedule data to make appending to the queue be quick. + */ + +static int fotg210_get_frame(struct usb_hcd *hcd); + +/*-------------------------------------------------------------------------*/ + +/* + * periodic_next_shadow - return "next" pointer on shadow list + * @periodic: host pointer to qh/itd + * @tag: hardware tag for type of this record + */ +static union fotg210_shadow * +periodic_next_shadow(struct fotg210_hcd *fotg210, + union fotg210_shadow *periodic, __hc32 tag) +{ + switch (hc32_to_cpu(fotg210, tag)) { + case Q_TYPE_QH: + return &periodic->qh->qh_next; + case Q_TYPE_FSTN: + return &periodic->fstn->fstn_next; + default: + return &periodic->itd->itd_next; + } +} + +static __hc32 * +shadow_next_periodic(struct fotg210_hcd *fotg210, + union fotg210_shadow *periodic, __hc32 tag) +{ + switch (hc32_to_cpu(fotg210, tag)) { + /* our fotg210_shadow.qh is actually software part */ + case Q_TYPE_QH: + return &periodic->qh->hw->hw_next; + /* others are hw parts */ + default: + return periodic->hw_next; + } +} + +/* caller must hold fotg210->lock */ +static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame, + void *ptr) +{ + union fotg210_shadow *prev_p = &fotg210->pshadow[frame]; + __hc32 *hw_p = &fotg210->periodic[frame]; + union fotg210_shadow here = *prev_p; + + /* find predecessor of "ptr"; hw and shadow lists are in sync */ + while (here.ptr && here.ptr != ptr) { + prev_p = periodic_next_shadow(fotg210, prev_p, + Q_NEXT_TYPE(fotg210, *hw_p)); + hw_p = shadow_next_periodic(fotg210, &here, + Q_NEXT_TYPE(fotg210, *hw_p)); + here = *prev_p; + } + /* an interrupt entry (at list end) could have been shared */ + if (!here.ptr) + return; + + /* update shadow and hardware lists ... the old "next" pointers + * from ptr may still be in use, the caller updates them. + */ + *prev_p = *periodic_next_shadow(fotg210, &here, + Q_NEXT_TYPE(fotg210, *hw_p)); + + *hw_p = *shadow_next_periodic(fotg210, &here, + Q_NEXT_TYPE(fotg210, *hw_p)); +} + +/* how many of the uframe's 125 usecs are allocated? */ +static unsigned short +periodic_usecs(struct fotg210_hcd *fotg210, unsigned frame, unsigned uframe) +{ + __hc32 *hw_p = &fotg210->periodic[frame]; + union fotg210_shadow *q = &fotg210->pshadow[frame]; + unsigned usecs = 0; + struct fotg210_qh_hw *hw; + + while (q->ptr) { + switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) { + case Q_TYPE_QH: + hw = q->qh->hw; + /* is it in the S-mask? */ + if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe)) + usecs += q->qh->usecs; + /* ... or C-mask? */ + if (hw->hw_info2 & cpu_to_hc32(fotg210, + 1 << (8 + uframe))) + usecs += q->qh->c_usecs; + hw_p = &hw->hw_next; + q = &q->qh->qh_next; + break; + /* case Q_TYPE_FSTN: */ + default: + /* for "save place" FSTNs, count the relevant INTR + * bandwidth from the previous frame + */ + if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210)) + fotg210_dbg(fotg210, "ignoring FSTN cost ...\n"); + + hw_p = &q->fstn->hw_next; + q = &q->fstn->fstn_next; + break; + case Q_TYPE_ITD: + if (q->itd->hw_transaction[uframe]) + usecs += q->itd->stream->usecs; + hw_p = &q->itd->hw_next; + q = &q->itd->itd_next; + break; + } + } + if (usecs > fotg210->uframe_periodic_max) + fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n", + frame * 8 + uframe, usecs); + return usecs; +} + +/*-------------------------------------------------------------------------*/ + +static int same_tt(struct usb_device *dev1, struct usb_device *dev2) +{ + if (!dev1->tt || !dev2->tt) + return 0; + if (dev1->tt != dev2->tt) + return 0; + if (dev1->tt->multi) + return dev1->ttport == dev2->ttport; + else + return 1; +} + +/* return true iff the device's transaction translator is available + * for a periodic transfer starting at the specified frame, using + * all the uframes in the mask. + */ +static int tt_no_collision( + struct fotg210_hcd *fotg210, + unsigned period, + struct usb_device *dev, + unsigned frame, + u32 uf_mask +) +{ + if (period == 0) /* error */ + return 0; + + /* note bandwidth wastage: split never follows csplit + * (different dev or endpoint) until the next uframe. + * calling convention doesn't make that distinction. + */ + for (; frame < fotg210->periodic_size; frame += period) { + union fotg210_shadow here; + __hc32 type; + struct fotg210_qh_hw *hw; + + here = fotg210->pshadow[frame]; + type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]); + while (here.ptr) { + switch (hc32_to_cpu(fotg210, type)) { + case Q_TYPE_ITD: + type = Q_NEXT_TYPE(fotg210, here.itd->hw_next); + here = here.itd->itd_next; + continue; + case Q_TYPE_QH: + hw = here.qh->hw; + if (same_tt(dev, here.qh->dev)) { + u32 mask; + + mask = hc32_to_cpu(fotg210, + hw->hw_info2); + /* "knows" no gap is needed */ + mask |= mask >> 8; + if (mask & uf_mask) + break; + } + type = Q_NEXT_TYPE(fotg210, hw->hw_next); + here = here.qh->qh_next; + continue; + /* case Q_TYPE_FSTN: */ + default: + fotg210_dbg(fotg210, + "periodic frame %d bogus type %d\n", + frame, type); + } + + /* collision or error */ + return 0; + } + } + + /* no collision */ + return 1; +} + +/*-------------------------------------------------------------------------*/ + +static void enable_periodic(struct fotg210_hcd *fotg210) +{ + if (fotg210->periodic_count++) + return; + + /* Stop waiting to turn off the periodic schedule */ + fotg210->enabled_hrtimer_events &= + ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC); + + /* Don't start the schedule until PSS is 0 */ + fotg210_poll_PSS(fotg210); + turn_on_io_watchdog(fotg210); +} + +static void disable_periodic(struct fotg210_hcd *fotg210) +{ + if (--fotg210->periodic_count) + return; + + /* Don't turn off the schedule until PSS is 1 */ + fotg210_poll_PSS(fotg210); +} + +/*-------------------------------------------------------------------------*/ + +/* periodic schedule slots have iso tds (normal or split) first, then a + * sparse tree for active interrupt transfers. + * + * this just links in a qh; caller guarantees uframe masks are set right. + * no FSTN support (yet; fotg210 0.96+) + */ +static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + unsigned i; + unsigned period = qh->period; + + dev_dbg(&qh->dev->dev, + "link qh%d-%04x/%p start %d [%d/%d us]\n", + period, hc32_to_cpup(fotg210, &qh->hw->hw_info2) + & (QH_CMASK | QH_SMASK), + qh, qh->start, qh->usecs, qh->c_usecs); + + /* high bandwidth, or otherwise every microframe */ + if (period == 0) + period = 1; + + for (i = qh->start; i < fotg210->periodic_size; i += period) { + union fotg210_shadow *prev = &fotg210->pshadow[i]; + __hc32 *hw_p = &fotg210->periodic[i]; + union fotg210_shadow here = *prev; + __hc32 type = 0; + + /* skip the iso nodes at list head */ + while (here.ptr) { + type = Q_NEXT_TYPE(fotg210, *hw_p); + if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) + break; + prev = periodic_next_shadow(fotg210, prev, type); + hw_p = shadow_next_periodic(fotg210, &here, type); + here = *prev; + } + + /* sorting each branch by period (slow-->fast) + * enables sharing interior tree nodes + */ + while (here.ptr && qh != here.qh) { + if (qh->period > here.qh->period) + break; + prev = &here.qh->qh_next; + hw_p = &here.qh->hw->hw_next; + here = *prev; + } + /* link in this qh, unless some earlier pass did that */ + if (qh != here.qh) { + qh->qh_next = here; + if (here.qh) + qh->hw->hw_next = *hw_p; + wmb(); + prev->qh = qh; + *hw_p = QH_NEXT(fotg210, qh->qh_dma); + } + } + qh->qh_state = QH_STATE_LINKED; + qh->xacterrs = 0; + + /* update per-qh bandwidth for usbfs */ + fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period + ? ((qh->usecs + qh->c_usecs) / qh->period) + : (qh->usecs * 8); + + list_add(&qh->intr_node, &fotg210->intr_qh_list); + + /* maybe enable periodic schedule processing */ + ++fotg210->intr_count; + enable_periodic(fotg210); +} + +static void qh_unlink_periodic(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + unsigned i; + unsigned period; + + /* + * If qh is for a low/full-speed device, simply unlinking it + * could interfere with an ongoing split transaction. To unlink + * it safely would require setting the QH_INACTIVATE bit and + * waiting at least one frame, as described in EHCI 4.12.2.5. + * + * We won't bother with any of this. Instead, we assume that the + * only reason for unlinking an interrupt QH while the current URB + * is still active is to dequeue all the URBs (flush the whole + * endpoint queue). + * + * If rebalancing the periodic schedule is ever implemented, this + * approach will no longer be valid. + */ + + /* high bandwidth, or otherwise part of every microframe */ + period = qh->period; + if (!period) + period = 1; + + for (i = qh->start; i < fotg210->periodic_size; i += period) + periodic_unlink(fotg210, i, qh); + + /* update per-qh bandwidth for usbfs */ + fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period + ? ((qh->usecs + qh->c_usecs) / qh->period) + : (qh->usecs * 8); + + dev_dbg(&qh->dev->dev, + "unlink qh%d-%04x/%p start %d [%d/%d us]\n", + qh->period, + hc32_to_cpup(fotg210, &qh->hw->hw_info2) & + (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); + + /* qh->qh_next still "live" to HC */ + qh->qh_state = QH_STATE_UNLINK; + qh->qh_next.ptr = NULL; + + if (fotg210->qh_scan_next == qh) + fotg210->qh_scan_next = list_entry(qh->intr_node.next, + struct fotg210_qh, intr_node); + list_del(&qh->intr_node); +} + +static void start_unlink_intr(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + /* If the QH isn't linked then there's nothing we can do + * unless we were called during a giveback, in which case + * qh_completions() has to deal with it. + */ + if (qh->qh_state != QH_STATE_LINKED) { + if (qh->qh_state == QH_STATE_COMPLETING) + qh->needs_rescan = 1; + return; + } + + qh_unlink_periodic(fotg210, qh); + + /* Make sure the unlinks are visible before starting the timer */ + wmb(); + + /* + * The EHCI spec doesn't say how long it takes the controller to + * stop accessing an unlinked interrupt QH. The timer delay is + * 9 uframes; presumably that will be long enough. + */ + qh->unlink_cycle = fotg210->intr_unlink_cycle; + + /* New entries go at the end of the intr_unlink list */ + if (fotg210->intr_unlink) + fotg210->intr_unlink_last->unlink_next = qh; + else + fotg210->intr_unlink = qh; + fotg210->intr_unlink_last = qh; + + if (fotg210->intr_unlinking) + ; /* Avoid recursive calls */ + else if (fotg210->rh_state < FOTG210_RH_RUNNING) + fotg210_handle_intr_unlinks(fotg210); + else if (fotg210->intr_unlink == qh) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, + true); + ++fotg210->intr_unlink_cycle; + } +} + +static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qh_hw *hw = qh->hw; + int rc; + + qh->qh_state = QH_STATE_IDLE; + hw->hw_next = FOTG210_LIST_END(fotg210); + + qh_completions(fotg210, qh); + + /* reschedule QH iff another request is queued */ + if (!list_empty(&qh->qtd_list) && + fotg210->rh_state == FOTG210_RH_RUNNING) { + rc = qh_schedule(fotg210, qh); + + /* An error here likely indicates handshake failure + * or no space left in the schedule. Neither fault + * should happen often ... + * + * FIXME kill the now-dysfunctional queued urbs + */ + if (rc != 0) + fotg210_err(fotg210, "can't reschedule qh %p, err %d\n", + qh, rc); + } + + /* maybe turn off periodic schedule */ + --fotg210->intr_count; + disable_periodic(fotg210); +} + +/*-------------------------------------------------------------------------*/ + +static int check_period( + struct fotg210_hcd *fotg210, + unsigned frame, + unsigned uframe, + unsigned period, + unsigned usecs +) { + int claimed; + + /* complete split running into next frame? + * given FSTN support, we could sometimes check... + */ + if (uframe >= 8) + return 0; + + /* convert "usecs we need" to "max already claimed" */ + usecs = fotg210->uframe_periodic_max - usecs; + + /* we "know" 2 and 4 uframe intervals were rejected; so + * for period 0, check _every_ microframe in the schedule. + */ + if (unlikely(period == 0)) { + do { + for (uframe = 0; uframe < 7; uframe++) { + claimed = periodic_usecs(fotg210, frame, + uframe); + if (claimed > usecs) + return 0; + } + } while ((frame += 1) < fotg210->periodic_size); + + /* just check the specified uframe, at that period */ + } else { + do { + claimed = periodic_usecs(fotg210, frame, uframe); + if (claimed > usecs) + return 0; + } while ((frame += period) < fotg210->periodic_size); + } + + /* success! */ + return 1; +} + +static int check_intr_schedule( + struct fotg210_hcd *fotg210, + unsigned frame, + unsigned uframe, + const struct fotg210_qh *qh, + __hc32 *c_maskp +) +{ + int retval = -ENOSPC; + u8 mask = 0; + + if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ + goto done; + + if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs)) + goto done; + if (!qh->c_usecs) { + retval = 0; + *c_maskp = 0; + goto done; + } + + /* Make sure this tt's buffer is also available for CSPLITs. + * We pessimize a bit; probably the typical full speed case + * doesn't need the second CSPLIT. + * + * NOTE: both SPLIT and CSPLIT could be checked in just + * one smart pass... + */ + mask = 0x03 << (uframe + qh->gap_uf); + *c_maskp = cpu_to_hc32(fotg210, mask << 8); + + mask |= 1 << uframe; + if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) { + if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1, + qh->period, qh->c_usecs)) + goto done; + if (!check_period(fotg210, frame, uframe + qh->gap_uf, + qh->period, qh->c_usecs)) + goto done; + retval = 0; + } +done: + return retval; +} + +/* "first fit" scheduling policy used the first time through, + * or when the previous schedule slot can't be re-used. + */ +static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + int status; + unsigned uframe; + __hc32 c_mask; + unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ + struct fotg210_qh_hw *hw = qh->hw; + + qh_refresh(fotg210, qh); + hw->hw_next = FOTG210_LIST_END(fotg210); + frame = qh->start; + + /* reuse the previous schedule slots, if we can */ + if (frame < qh->period) { + uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK); + status = check_intr_schedule(fotg210, frame, --uframe, + qh, &c_mask); + } else { + uframe = 0; + c_mask = 0; + status = -ENOSPC; + } + + /* else scan the schedule to find a group of slots such that all + * uframes have enough periodic bandwidth available. + */ + if (status) { + /* "normal" case, uframing flexible except with splits */ + if (qh->period) { + int i; + + for (i = qh->period; status && i > 0; --i) { + frame = ++fotg210->random_frame % qh->period; + for (uframe = 0; uframe < 8; uframe++) { + status = check_intr_schedule(fotg210, + frame, uframe, qh, + &c_mask); + if (status == 0) + break; + } + } + + /* qh->period == 0 means every uframe */ + } else { + frame = 0; + status = check_intr_schedule(fotg210, 0, 0, qh, + &c_mask); + } + if (status) + goto done; + qh->start = frame; + + /* reset S-frame and (maybe) C-frame masks */ + hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK)); + hw->hw_info2 |= qh->period + ? cpu_to_hc32(fotg210, 1 << uframe) + : cpu_to_hc32(fotg210, QH_SMASK); + hw->hw_info2 |= c_mask; + } else + fotg210_dbg(fotg210, "reused qh %p schedule\n", qh); + + /* stuff into the periodic schedule */ + qh_link_periodic(fotg210, qh); +done: + return status; +} + +static int intr_submit( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list, + gfp_t mem_flags +) { + unsigned epnum; + unsigned long flags; + struct fotg210_qh *qh; + int status; + struct list_head empty; + + /* get endpoint and transfer/schedule data */ + epnum = urb->ep->desc.bEndpointAddress; + + spin_lock_irqsave(&fotg210->lock, flags); + + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { + status = -ESHUTDOWN; + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); + if (unlikely(status)) + goto done_not_linked; + + /* get qh and force any scheduling errors */ + INIT_LIST_HEAD(&empty); + qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv); + if (qh == NULL) { + status = -ENOMEM; + goto done; + } + if (qh->qh_state == QH_STATE_IDLE) { + status = qh_schedule(fotg210, qh); + if (status) + goto done; + } + + /* then queue the urb's tds to the qh */ + qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); + BUG_ON(qh == NULL); + + /* ... update usbfs periodic stats */ + fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++; + +done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); +done_not_linked: + spin_unlock_irqrestore(&fotg210->lock, flags); + if (status) + qtd_list_free(fotg210, urb, qtd_list); + + return status; +} + +static void scan_intr(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh; + + list_for_each_entry_safe(qh, fotg210->qh_scan_next, + &fotg210->intr_qh_list, intr_node) { + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; + + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why fotg210->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then fotg210->qh_scan_next is adjusted + * in qh_unlink_periodic(). + */ + temp = qh_completions(fotg210, qh); + if (unlikely(qh->needs_rescan || + (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED))) + start_unlink_intr(fotg210, qh); + else if (temp != 0) + goto rescan; + } + } +} + +/*-------------------------------------------------------------------------*/ + +/* fotg210_iso_stream ops work with both ITD and SITD */ + +static struct fotg210_iso_stream * +iso_stream_alloc(gfp_t mem_flags) +{ + struct fotg210_iso_stream *stream; + + stream = kzalloc(sizeof(*stream), mem_flags); + if (likely(stream != NULL)) { + INIT_LIST_HEAD(&stream->td_list); + INIT_LIST_HEAD(&stream->free_list); + stream->next_uframe = -1; + } + return stream; +} + +static void +iso_stream_init( + struct fotg210_hcd *fotg210, + struct fotg210_iso_stream *stream, + struct usb_device *dev, + int pipe, + unsigned interval +) +{ + u32 buf1; + unsigned epnum, maxp; + int is_input; + long bandwidth; + unsigned multi; + + /* + * this might be a "high bandwidth" highspeed endpoint, + * as encoded in the ep descriptor's wMaxPacket field + */ + epnum = usb_pipeendpoint(pipe); + is_input = usb_pipein(pipe) ? USB_DIR_IN : 0; + maxp = usb_maxpacket(dev, pipe, !is_input); + if (is_input) + buf1 = (1 << 11); + else + buf1 = 0; + + maxp = max_packet(maxp); + multi = hb_mult(maxp); + buf1 |= maxp; + maxp *= multi; + + stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum); + stream->buf1 = cpu_to_hc32(fotg210, buf1); + stream->buf2 = cpu_to_hc32(fotg210, multi); + + /* usbfs wants to report the average usecs per frame tied up + * when transfers on this endpoint are scheduled ... + */ + if (dev->speed == USB_SPEED_FULL) { + interval <<= 3; + stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed, + is_input, 1, maxp)); + stream->usecs /= 8; + } else { + stream->highspeed = 1; + stream->usecs = HS_USECS_ISO(maxp); + } + bandwidth = stream->usecs * 8; + bandwidth /= interval; + + stream->bandwidth = bandwidth; + stream->udev = dev; + stream->bEndpointAddress = is_input | epnum; + stream->interval = interval; + stream->maxp = maxp; +} + +static struct fotg210_iso_stream * +iso_stream_find(struct fotg210_hcd *fotg210, struct urb *urb) +{ + unsigned epnum; + struct fotg210_iso_stream *stream; + struct usb_host_endpoint *ep; + unsigned long flags; + + epnum = usb_pipeendpoint(urb->pipe); + if (usb_pipein(urb->pipe)) + ep = urb->dev->ep_in[epnum]; + else + ep = urb->dev->ep_out[epnum]; + + spin_lock_irqsave(&fotg210->lock, flags); + stream = ep->hcpriv; + + if (unlikely(stream == NULL)) { + stream = iso_stream_alloc(GFP_ATOMIC); + if (likely(stream != NULL)) { + ep->hcpriv = stream; + stream->ep = ep; + iso_stream_init(fotg210, stream, urb->dev, urb->pipe, + urb->interval); + } + + /* if dev->ep[epnum] is a QH, hw is set */ + } else if (unlikely(stream->hw != NULL)) { + fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n", + urb->dev->devpath, epnum, + usb_pipein(urb->pipe) ? "in" : "out"); + stream = NULL; + } + + spin_unlock_irqrestore(&fotg210->lock, flags); + return stream; +} + +/*-------------------------------------------------------------------------*/ + +/* fotg210_iso_sched ops can be ITD-only or SITD-only */ + +static struct fotg210_iso_sched * +iso_sched_alloc(unsigned packets, gfp_t mem_flags) +{ + struct fotg210_iso_sched *iso_sched; + int size = sizeof(*iso_sched); + + size += packets * sizeof(struct fotg210_iso_packet); + iso_sched = kzalloc(size, mem_flags); + if (likely(iso_sched != NULL)) + INIT_LIST_HEAD(&iso_sched->td_list); + + return iso_sched; +} + +static inline void +itd_sched_init( + struct fotg210_hcd *fotg210, + struct fotg210_iso_sched *iso_sched, + struct fotg210_iso_stream *stream, + struct urb *urb +) +{ + unsigned i; + dma_addr_t dma = urb->transfer_dma; + + /* how many uframes are needed for these transfers */ + iso_sched->span = urb->number_of_packets * stream->interval; + + /* figure out per-uframe itd fields that we'll need later + * when we fit new itds into the schedule. + */ + for (i = 0; i < urb->number_of_packets; i++) { + struct fotg210_iso_packet *uframe = &iso_sched->packet[i]; + unsigned length; + dma_addr_t buf; + u32 trans; + + length = urb->iso_frame_desc[i].length; + buf = dma + urb->iso_frame_desc[i].offset; + + trans = FOTG210_ISOC_ACTIVE; + trans |= buf & 0x0fff; + if (unlikely(((i + 1) == urb->number_of_packets)) + && !(urb->transfer_flags & URB_NO_INTERRUPT)) + trans |= FOTG210_ITD_IOC; + trans |= length << 16; + uframe->transaction = cpu_to_hc32(fotg210, trans); + + /* might need to cross a buffer page within a uframe */ + uframe->bufp = (buf & ~(u64)0x0fff); + buf += length; + if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff)))) + uframe->cross = 1; + } +} + +static void +iso_sched_free( + struct fotg210_iso_stream *stream, + struct fotg210_iso_sched *iso_sched +) +{ + if (!iso_sched) + return; + /* caller must hold fotg210->lock!*/ + list_splice(&iso_sched->td_list, &stream->free_list); + kfree(iso_sched); +} + +static int +itd_urb_transaction( + struct fotg210_iso_stream *stream, + struct fotg210_hcd *fotg210, + struct urb *urb, + gfp_t mem_flags +) +{ + struct fotg210_itd *itd; + dma_addr_t itd_dma; + int i; + unsigned num_itds; + struct fotg210_iso_sched *sched; + unsigned long flags; + + sched = iso_sched_alloc(urb->number_of_packets, mem_flags); + if (unlikely(sched == NULL)) + return -ENOMEM; + + itd_sched_init(fotg210, sched, stream, urb); + + if (urb->interval < 8) + num_itds = 1 + (sched->span + 7) / 8; + else + num_itds = urb->number_of_packets; + + /* allocate/init ITDs */ + spin_lock_irqsave(&fotg210->lock, flags); + for (i = 0; i < num_itds; i++) { + + /* + * Use iTDs from the free list, but not iTDs that may + * still be in use by the hardware. + */ + if (likely(!list_empty(&stream->free_list))) { + itd = list_first_entry(&stream->free_list, + struct fotg210_itd, itd_list); + if (itd->frame == fotg210->now_frame) + goto alloc_itd; + list_del(&itd->itd_list); + itd_dma = itd->itd_dma; + } else { + alloc_itd: + spin_unlock_irqrestore(&fotg210->lock, flags); + itd = dma_pool_alloc(fotg210->itd_pool, mem_flags, + &itd_dma); + spin_lock_irqsave(&fotg210->lock, flags); + if (!itd) { + iso_sched_free(stream, sched); + spin_unlock_irqrestore(&fotg210->lock, flags); + return -ENOMEM; + } + } + + memset(itd, 0, sizeof(*itd)); + itd->itd_dma = itd_dma; + list_add(&itd->itd_list, &sched->td_list); + } + spin_unlock_irqrestore(&fotg210->lock, flags); + + /* temporarily store schedule info in hcpriv */ + urb->hcpriv = sched; + urb->error_count = 0; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static inline int +itd_slot_ok( + struct fotg210_hcd *fotg210, + u32 mod, + u32 uframe, + u8 usecs, + u32 period +) +{ + uframe %= period; + do { + /* can't commit more than uframe_periodic_max usec */ + if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7) + > (fotg210->uframe_periodic_max - usecs)) + return 0; + + /* we know urb->interval is 2^N uframes */ + uframe += period; + } while (uframe < mod); + return 1; +} + +/* + * This scheduler plans almost as far into the future as it has actual + * periodic schedule slots. (Affected by TUNE_FLS, which defaults to + * "as small as possible" to be cache-friendlier.) That limits the size + * transfers you can stream reliably; avoid more than 64 msec per urb. + * Also avoid queue depths of less than fotg210's worst irq latency (affected + * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter, + * and other factors); or more than about 230 msec total (for portability, + * given FOTG210_TUNE_FLS and the slop). Or, write a smarter scheduler! + */ + +#define SCHEDULE_SLOP 80 /* microframes */ + +static int +iso_stream_schedule( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct fotg210_iso_stream *stream +) +{ + u32 now, next, start, period, span; + int status; + unsigned mod = fotg210->periodic_size << 3; + struct fotg210_iso_sched *sched = urb->hcpriv; + + period = urb->interval; + span = sched->span; + + if (span > mod - SCHEDULE_SLOP) { + fotg210_dbg(fotg210, "iso request %p too long\n", urb); + status = -EFBIG; + goto fail; + } + + now = fotg210_read_frame_index(fotg210) & (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. + */ + 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 && fotg210->fs_i_thresh) + next = now + fotg210->i_thresh; + else + next = now; + + /* 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. + */ + 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) { + fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", + urb, start - now - period, period, + mod); + status = -EFBIG; + goto fail; + } + } + + /* need to schedule; when's the next (u)frame we could start? + * this is bigger than fotg210->i_thresh allows; scheduling itself + * isn't free, the slop 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 */ + + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; + /* check schedule: enough space? */ + if (itd_slot_ok(fotg210, mod, start, + stream->usecs, period)) + done = 1; + } while (start > next && !done); + + /* no room in the schedule */ + if (!done) { + fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n", + urb, now, now + mod); + status = -ENOSPC; + goto fail; + } + } + + /* Tried to schedule too far into the future? */ + if (unlikely(start - now + span - period + >= mod - 2 * SCHEDULE_SLOP)) { + fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", + urb, start - now, span - period, + mod - 2 * SCHEDULE_SLOP); + status = -EFBIG; + goto fail; + } + + stream->next_uframe = start & (mod - 1); + + /* report high speed start in uframes; full speed, in frames */ + urb->start_frame = stream->next_uframe; + if (!stream->highspeed) + urb->start_frame >>= 3; + + /* Make sure scan_isoc() sees these */ + if (fotg210->isoc_count == 0) + fotg210->next_frame = now >> 3; + return 0; + + fail: + iso_sched_free(stream, sched); + urb->hcpriv = NULL; + return status; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +itd_init(struct fotg210_hcd *fotg210, struct fotg210_iso_stream *stream, + struct fotg210_itd *itd) +{ + int i; + + /* it's been recently zeroed */ + itd->hw_next = FOTG210_LIST_END(fotg210); + itd->hw_bufp[0] = stream->buf0; + itd->hw_bufp[1] = stream->buf1; + itd->hw_bufp[2] = stream->buf2; + + for (i = 0; i < 8; i++) + itd->index[i] = -1; + + /* All other fields are filled when scheduling */ +} + +static inline void +itd_patch( + struct fotg210_hcd *fotg210, + struct fotg210_itd *itd, + struct fotg210_iso_sched *iso_sched, + unsigned index, + u16 uframe +) +{ + struct fotg210_iso_packet *uf = &iso_sched->packet[index]; + unsigned pg = itd->pg; + + uframe &= 0x07; + itd->index[uframe] = index; + + itd->hw_transaction[uframe] = uf->transaction; + itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12); + itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0); + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32)); + + /* iso_frame_desc[].offset must be strictly increasing */ + if (unlikely(uf->cross)) { + u64 bufp = uf->bufp + 4096; + + itd->pg = ++pg; + itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0); + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32)); + } +} + +static inline void +itd_link(struct fotg210_hcd *fotg210, unsigned frame, struct fotg210_itd *itd) +{ + union fotg210_shadow *prev = &fotg210->pshadow[frame]; + __hc32 *hw_p = &fotg210->periodic[frame]; + union fotg210_shadow here = *prev; + __hc32 type = 0; + + /* skip any iso nodes which might belong to previous microframes */ + while (here.ptr) { + type = Q_NEXT_TYPE(fotg210, *hw_p); + if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) + break; + prev = periodic_next_shadow(fotg210, prev, type); + hw_p = shadow_next_periodic(fotg210, &here, type); + here = *prev; + } + + itd->itd_next = here; + itd->hw_next = *hw_p; + prev->itd = itd; + itd->frame = frame; + wmb(); + *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD); +} + +/* fit urb's itds into the selected schedule slot; activate as needed */ +static void itd_link_urb( + struct fotg210_hcd *fotg210, + struct urb *urb, + unsigned mod, + struct fotg210_iso_stream *stream +) +{ + int packet; + unsigned next_uframe, uframe, frame; + struct fotg210_iso_sched *iso_sched = urb->hcpriv; + struct fotg210_itd *itd; + + next_uframe = stream->next_uframe & (mod - 1); + + if (unlikely(list_empty(&stream->td_list))) { + fotg210_to_hcd(fotg210)->self.bandwidth_allocated + += stream->bandwidth; + fotg210_dbg(fotg210, + "schedule devp %s ep%d%s-iso period %d start %d.%d\n", + urb->dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + urb->interval, + next_uframe >> 3, next_uframe & 0x7); + } + + /* fill iTDs uframe by uframe */ + for (packet = 0, itd = NULL; packet < urb->number_of_packets;) { + if (itd == NULL) { + /* ASSERT: we have all necessary itds */ + + /* ASSERT: no itds for this endpoint in this uframe */ + + itd = list_entry(iso_sched->td_list.next, + struct fotg210_itd, itd_list); + list_move_tail(&itd->itd_list, &stream->td_list); + itd->stream = stream; + itd->urb = urb; + itd_init(fotg210, stream, itd); + } + + uframe = next_uframe & 0x07; + frame = next_uframe >> 3; + + itd_patch(fotg210, itd, iso_sched, packet, uframe); + + next_uframe += stream->interval; + next_uframe &= mod - 1; + packet++; + + /* link completed itds into the schedule */ + if (((next_uframe >> 3) != frame) + || packet == urb->number_of_packets) { + itd_link(fotg210, frame & (fotg210->periodic_size - 1), + itd); + itd = NULL; + } + } + stream->next_uframe = next_uframe; + + /* don't need that schedule data any more */ + iso_sched_free(stream, iso_sched); + urb->hcpriv = NULL; + + ++fotg210->isoc_count; + enable_periodic(fotg210); +} + +#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\ + FOTG210_ISOC_XACTERR) + +/* Process and recycle a completed ITD. Return true iff its urb completed, + * and hence its completion callback probably added things to the hardware + * schedule. + * + * Note that we carefully avoid recycling this descriptor until after any + * completion callback runs, so that it won't be reused quickly. That is, + * assuming (a) no more than two urbs per frame on this endpoint, and also + * (b) only this endpoint's completions submit URBs. It seems some silicon + * corrupts things if you reuse completed descriptors very quickly... + */ +static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd) +{ + struct urb *urb = itd->urb; + struct usb_iso_packet_descriptor *desc; + u32 t; + unsigned uframe; + int urb_index = -1; + struct fotg210_iso_stream *stream = itd->stream; + struct usb_device *dev; + bool retval = false; + + /* for each uframe with a packet */ + for (uframe = 0; uframe < 8; uframe++) { + if (likely(itd->index[uframe] == -1)) + continue; + urb_index = itd->index[uframe]; + desc = &urb->iso_frame_desc[urb_index]; + + t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]); + itd->hw_transaction[uframe] = 0; + + /* report transfer status */ + if (unlikely(t & ISO_ERRS)) { + urb->error_count++; + if (t & FOTG210_ISOC_BUF_ERR) + desc->status = usb_pipein(urb->pipe) + ? -ENOSR /* hc couldn't read */ + : -ECOMM; /* hc couldn't write */ + else if (t & FOTG210_ISOC_BABBLE) + desc->status = -EOVERFLOW; + else /* (t & FOTG210_ISOC_XACTERR) */ + desc->status = -EPROTO; + + /* HC need not update length with this error */ + if (!(t & FOTG210_ISOC_BABBLE)) { + desc->actual_length = + fotg210_itdlen(urb, desc, t); + urb->actual_length += desc->actual_length; + } + } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) { + desc->status = 0; + desc->actual_length = fotg210_itdlen(urb, desc, t); + urb->actual_length += desc->actual_length; + } else { + /* URB was too late */ + desc->status = -EXDEV; + } + } + + /* handle completion now? */ + if (likely((urb_index + 1) != urb->number_of_packets)) + goto done; + + /* ASSERT: it's really the last itd for this urb + list_for_each_entry (itd, &stream->td_list, itd_list) + BUG_ON (itd->urb == urb); + */ + + /* give urb back to the driver; completion often (re)submits */ + dev = urb->dev; + fotg210_urb_done(fotg210, urb, 0); + retval = true; + urb = NULL; + + --fotg210->isoc_count; + disable_periodic(fotg210); + + if (unlikely(list_is_singular(&stream->td_list))) { + fotg210_to_hcd(fotg210)->self.bandwidth_allocated + -= stream->bandwidth; + fotg210_dbg(fotg210, + "deschedule devp %s ep%d%s-iso\n", + dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); + } + +done: + itd->urb = NULL; + + /* Add to the end of the free list for later reuse */ + list_move_tail(&itd->itd_list, &stream->free_list); + + /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */ + if (list_empty(&stream->td_list)) { + list_splice_tail_init(&stream->free_list, + &fotg210->cached_itd_list); + start_free_itds(fotg210); + } + + return retval; +} + +/*-------------------------------------------------------------------------*/ + +static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb, + gfp_t mem_flags) +{ + int status = -EINVAL; + unsigned long flags; + struct fotg210_iso_stream *stream; + + /* Get iso_stream head */ + stream = iso_stream_find(fotg210, urb); + if (unlikely(stream == NULL)) { + fotg210_dbg(fotg210, "can't get iso stream\n"); + return -ENOMEM; + } + if (unlikely(urb->interval != stream->interval && + fotg210_port_speed(fotg210, 0) == + USB_PORT_STAT_HIGH_SPEED)) { + fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n", + stream->interval, urb->interval); + goto done; + } + +#ifdef FOTG210_URB_TRACE + fotg210_dbg(fotg210, + "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n", + __func__, urb->dev->devpath, urb, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + urb->transfer_buffer_length, + urb->number_of_packets, urb->interval, + stream); +#endif + + /* allocate ITDs w/o locking anything */ + status = itd_urb_transaction(stream, fotg210, urb, mem_flags); + if (unlikely(status < 0)) { + fotg210_dbg(fotg210, "can't init itds\n"); + goto done; + } + + /* schedule ... need to lock */ + spin_lock_irqsave(&fotg210->lock, flags); + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { + status = -ESHUTDOWN; + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(fotg210, urb, stream); + if (likely(status == 0)) + itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); + done_not_linked: + spin_unlock_irqrestore(&fotg210->lock, flags); + done: + return status; +} + +/*-------------------------------------------------------------------------*/ + +static void scan_isoc(struct fotg210_hcd *fotg210) +{ + unsigned uf, now_frame, frame; + unsigned fmask = fotg210->periodic_size - 1; + bool modified, live; + + /* + * When running, scan from last scan point up to "now" + * else clean up by scanning everything that's left. + * Touches as few pages as possible: cache-friendly. + */ + if (fotg210->rh_state >= FOTG210_RH_RUNNING) { + uf = fotg210_read_frame_index(fotg210); + now_frame = (uf >> 3) & fmask; + live = true; + } else { + now_frame = (fotg210->next_frame - 1) & fmask; + live = false; + } + fotg210->now_frame = now_frame; + + frame = fotg210->next_frame; + for (;;) { + union fotg210_shadow q, *q_p; + __hc32 type, *hw_p; + +restart: + /* scan each element in frame's queue for completions */ + q_p = &fotg210->pshadow[frame]; + hw_p = &fotg210->periodic[frame]; + q.ptr = q_p->ptr; + type = Q_NEXT_TYPE(fotg210, *hw_p); + modified = false; + + while (q.ptr != NULL) { + switch (hc32_to_cpu(fotg210, type)) { + case Q_TYPE_ITD: + /* If this ITD is still active, leave it for + * later processing ... check the next entry. + * No need to check for activity unless the + * frame is current. + */ + if (frame == now_frame && live) { + rmb(); + for (uf = 0; uf < 8; uf++) { + if (q.itd->hw_transaction[uf] & + ITD_ACTIVE(fotg210)) + break; + } + if (uf < 8) { + q_p = &q.itd->itd_next; + hw_p = &q.itd->hw_next; + type = Q_NEXT_TYPE(fotg210, + q.itd->hw_next); + q = *q_p; + break; + } + } + + /* Take finished ITDs out of the schedule + * and process them: recycle, maybe report + * URB completion. HC won't cache the + * pointer for much longer, if at all. + */ + *q_p = q.itd->itd_next; + *hw_p = q.itd->hw_next; + type = Q_NEXT_TYPE(fotg210, q.itd->hw_next); + wmb(); + modified = itd_complete(fotg210, q.itd); + q = *q_p; + break; + default: + fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n", + type, frame, q.ptr); + /* FALL THROUGH */ + case Q_TYPE_QH: + case Q_TYPE_FSTN: + /* End of the iTDs and siTDs */ + q.ptr = NULL; + break; + } + + /* assume completion callbacks modify the queue */ + if (unlikely(modified && fotg210->isoc_count > 0)) + goto restart; + } + + /* Stop when we have reached the current frame */ + if (frame == now_frame) + break; + frame = (frame + 1) & fmask; + } + fotg210->next_frame = now_frame; +} +/*-------------------------------------------------------------------------*/ +/* + * Display / Set uframe_periodic_max + */ +static ssize_t show_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fotg210_hcd *fotg210; + int n; + + fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); + n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max); + return n; +} + + +static ssize_t store_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fotg210_hcd *fotg210; + unsigned uframe_periodic_max; + unsigned frame, uframe; + unsigned short allocated_max; + unsigned long flags; + ssize_t ret; + + fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); + if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) + return -EINVAL; + + if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { + fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n", + uframe_periodic_max); + return -EINVAL; + } + + ret = -EINVAL; + + /* + * lock, so that our checking does not race with possible periodic + * bandwidth allocation through submitting new urbs. + */ + spin_lock_irqsave(&fotg210->lock, flags); + + /* + * for request to decrease max periodic bandwidth, we have to check + * every microframe in the schedule to see whether the decrease is + * possible. + */ + if (uframe_periodic_max < fotg210->uframe_periodic_max) { + allocated_max = 0; + + for (frame = 0; frame < fotg210->periodic_size; ++frame) + for (uframe = 0; uframe < 7; ++uframe) + allocated_max = max(allocated_max, + periodic_usecs(fotg210, frame, uframe)); + + if (allocated_max > uframe_periodic_max) { + fotg210_info(fotg210, + "cannot decrease uframe_periodic_max becase " + "periodic bandwidth is already allocated " + "(%u > %u)\n", + allocated_max, uframe_periodic_max); + goto out_unlock; + } + } + + /* increasing is always ok */ + + fotg210_info(fotg210, "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n", + 100 * uframe_periodic_max/125, uframe_periodic_max); + + if (uframe_periodic_max != 100) + fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n"); + + fotg210->uframe_periodic_max = uframe_periodic_max; + ret = count; + +out_unlock: + spin_unlock_irqrestore(&fotg210->lock, flags); + return ret; +} + +static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, + store_uframe_periodic_max); + +static inline int create_sysfs_files(struct fotg210_hcd *fotg210) +{ + struct device *controller = fotg210_to_hcd(fotg210)->self.controller; + int i = 0; + + if (i) + goto out; + + i = device_create_file(controller, &dev_attr_uframe_periodic_max); +out: + return i; +} + +static inline void remove_sysfs_files(struct fotg210_hcd *fotg210) +{ + struct device *controller = fotg210_to_hcd(fotg210)->self.controller; + + device_remove_file(controller, &dev_attr_uframe_periodic_max); +} +/*-------------------------------------------------------------------------*/ + +/* On some systems, leaving remote wakeup enabled prevents system shutdown. + * The firmware seems to think that powering off is a wakeup event! + * This routine turns off remote wakeup and everything else, on all ports. + */ +static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210) +{ + u32 __iomem *status_reg = &fotg210->regs->port_status; + + fotg210_writel(fotg210, PORT_RWC_BITS, status_reg); +} + +/* + * Halt HC, turn off all ports, and let the BIOS use the companion controllers. + * Must be called with interrupts enabled and the lock not held. + */ +static void fotg210_silence_controller(struct fotg210_hcd *fotg210) +{ + fotg210_halt(fotg210); + + spin_lock_irq(&fotg210->lock); + fotg210->rh_state = FOTG210_RH_HALTED; + fotg210_turn_off_all_ports(fotg210); + spin_unlock_irq(&fotg210->lock); +} + +/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc). + * This forcibly disables dma and IRQs, helping kexec and other cases + * where the next system software may expect clean state. + */ +static void fotg210_shutdown(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + + spin_lock_irq(&fotg210->lock); + fotg210->shutdown = true; + fotg210->rh_state = FOTG210_RH_STOPPING; + fotg210->enabled_hrtimer_events = 0; + spin_unlock_irq(&fotg210->lock); + + fotg210_silence_controller(fotg210); + + hrtimer_cancel(&fotg210->hrtimer); +} + +/*-------------------------------------------------------------------------*/ + +/* + * fotg210_work is called from some interrupts, timers, and so on. + * it calls driver completion functions, after dropping fotg210->lock. + */ +static void fotg210_work(struct fotg210_hcd *fotg210) +{ + /* another CPU may drop fotg210->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (fotg210->scanning) { + fotg210->need_rescan = true; + return; + } + fotg210->scanning = true; + + rescan: + fotg210->need_rescan = false; + if (fotg210->async_count) + scan_async(fotg210); + if (fotg210->intr_count > 0) + scan_intr(fotg210); + if (fotg210->isoc_count > 0) + scan_isoc(fotg210); + if (fotg210->need_rescan) + goto rescan; + fotg210->scanning = false; + + /* the IO watchdog guards against hardware or driver bugs that + * misplace IRQs, and should let us run completely without IRQs. + * such lossage has been observed on both VT6202 and VT8235. + */ + turn_on_io_watchdog(fotg210); +} + +/* + * Called when the fotg210_hcd module is removed. + */ +static void fotg210_stop(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + + fotg210_dbg(fotg210, "stop\n"); + + /* no more interrupts ... */ + + spin_lock_irq(&fotg210->lock); + fotg210->enabled_hrtimer_events = 0; + spin_unlock_irq(&fotg210->lock); + + fotg210_quiesce(fotg210); + fotg210_silence_controller(fotg210); + fotg210_reset(fotg210); + + hrtimer_cancel(&fotg210->hrtimer); + remove_sysfs_files(fotg210); + remove_debug_files(fotg210); + + /* root hub is shut down separately (first, when possible) */ + spin_lock_irq(&fotg210->lock); + end_free_itds(fotg210); + spin_unlock_irq(&fotg210->lock); + fotg210_mem_cleanup(fotg210); + +#ifdef FOTG210_STATS + fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n", + fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa, + fotg210->stats.lost_iaa); + fotg210_dbg(fotg210, "complete %ld unlink %ld\n", + fotg210->stats.complete, fotg210->stats.unlink); +#endif + + dbg_status(fotg210, "fotg210_stop completed", + fotg210_readl(fotg210, &fotg210->regs->status)); +} + +/* one-time init, only for memory state */ +static int hcd_fotg210_init(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 temp; + int retval; + u32 hcc_params; + struct fotg210_qh_hw *hw; + + spin_lock_init(&fotg210->lock); + + /* + * keep io watchdog by default, those good HCDs could turn off it later + */ + fotg210->need_io_watchdog = 1; + + hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + fotg210->hrtimer.function = fotg210_hrtimer_func; + fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; + + hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + + /* + * by default set standard 80% (== 100 usec/uframe) max periodic + * bandwidth as required by USB 2.0 + */ + fotg210->uframe_periodic_max = 100; + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + fotg210->periodic_size = DEFAULT_I_TDPS; + INIT_LIST_HEAD(&fotg210->intr_qh_list); + INIT_LIST_HEAD(&fotg210->cached_itd_list); + + if (HCC_PGM_FRAMELISTLEN(hcc_params)) { + /* periodic schedule size can be smaller than default */ + switch (FOTG210_TUNE_FLS) { + case 0: + fotg210->periodic_size = 1024; + break; + case 1: + fotg210->periodic_size = 512; + break; + case 2: + fotg210->periodic_size = 256; + break; + default: + BUG(); + } + } + retval = fotg210_mem_init(fotg210, GFP_KERNEL); + if (retval < 0) + return retval; + + /* controllers may cache some of the periodic schedule ... */ + fotg210->i_thresh = 2; + + /* + * dedicate a qh for the async ring head, since we couldn't unlink + * a 'real' qh without stopping the async schedule [4.8]. use it + * as the 'reclamation list head' too. + * its dummy is used in hw_alt_next of many tds, to prevent the qh + * from automatically advancing to the next td after short reads. + */ + fotg210->async->qh_next.qh = NULL; + hw = fotg210->async->hw; + hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma); + hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD); + hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); + hw->hw_qtd_next = FOTG210_LIST_END(fotg210); + fotg210->async->qh_state = QH_STATE_LINKED; + hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma); + + /* clear interrupt enables, set irq latency */ + if (log2_irq_thresh < 0 || log2_irq_thresh > 6) + log2_irq_thresh = 0; + temp = 1 << (16 + log2_irq_thresh); + if (HCC_CANPARK(hcc_params)) { + /* HW default park == 3, on hardware that supports it (like + * NVidia and ALI silicon), maximizes throughput on the async + * schedule by avoiding QH fetches between transfers. + * + * With fast usb storage devices and NForce2, "park" seems to + * make problems: throughput reduction (!), data errors... + */ + if (park) { + park = min_t(unsigned, park, 3); + temp |= CMD_PARK; + temp |= park << 8; + } + fotg210_dbg(fotg210, "park %d\n", park); + } + if (HCC_PGM_FRAMELISTLEN(hcc_params)) { + /* periodic schedule size can be smaller than default */ + temp &= ~(3 << 2); + temp |= (FOTG210_TUNE_FLS << 2); + } + fotg210->command = temp; + + /* Accept arbitrarily long scatter-gather lists */ + if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + hcd->self.sg_tablesize = ~0; + return 0; +} + +/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */ +static int fotg210_run(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 temp; + u32 hcc_params; + + hcd->uses_new_polling = 1; + + /* EHCI spec section 4.1 */ + + fotg210_writel(fotg210, fotg210->periodic_dma, + &fotg210->regs->frame_list); + fotg210_writel(fotg210, (u32)fotg210->async->qh_dma, + &fotg210->regs->async_next); + + /* + * hcc_params controls whether fotg210->regs->segment must (!!!) + * be used; it constrains QH/ITD/SITD and QTD locations. + * pci_pool consistent memory always uses segment zero. + * streaming mappings for I/O buffers, like pci_map_single(), + * can return segments above 4GB, if the device allows. + * + * NOTE: the dma mask is visible through dma_supported(), so + * drivers can pass this info along ... like NETIF_F_HIGHDMA, + * Scsi_Host.highmem_io, and so forth. It's readonly to all + * host side drivers though. + */ + hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + + /* + * Philips, Intel, and maybe others need CMD_RUN before the + * root hub will detect new devices (why?); NEC doesn't + */ + fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); + fotg210->command |= CMD_RUN; + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + dbg_cmd(fotg210, "init", fotg210->command); + + /* + * Start, enabling full USB 2.0 functionality ... usb 1.1 devices + * are explicitly handed to companion controller(s), so no TT is + * involved with the root hub. (Except where one is integrated, + * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. After we set CF, + * a short delay lets the hardware catch up; new resets shouldn't + * be started before the port switching actions could complete. + */ + down_write(&ehci_cf_port_reset_rwsem); + fotg210->rh_state = FOTG210_RH_RUNNING; + /* unblock posted writes */ + fotg210_readl(fotg210, &fotg210->regs->command); + msleep(5); + up_write(&ehci_cf_port_reset_rwsem); + fotg210->last_periodic_enable = ktime_get_real(); + + temp = HC_VERSION(fotg210, + fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); + fotg210_info(fotg210, + "USB %x.%x started, EHCI %x.%02x\n", + ((fotg210->sbrn & 0xf0)>>4), (fotg210->sbrn & 0x0f), + temp >> 8, temp & 0xff); + + fotg210_writel(fotg210, INTR_MASK, + &fotg210->regs->intr_enable); /* Turn On Interrupts */ + + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + create_debug_files(fotg210); + create_sysfs_files(fotg210); + + return 0; +} + +static int fotg210_setup(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + int retval; + + fotg210->regs = (void __iomem *)fotg210->caps + + HC_LENGTH(fotg210, + fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); + dbg_hcs_params(fotg210, "reset"); + dbg_hcc_params(fotg210, "reset"); + + /* cache this readonly data; minimize chip reads */ + fotg210->hcs_params = fotg210_readl(fotg210, + &fotg210->caps->hcs_params); + + fotg210->sbrn = HCD_USB2; + + /* data structure init */ + retval = hcd_fotg210_init(hcd); + if (retval) + return retval; + + retval = fotg210_halt(fotg210); + if (retval) + return retval; + + fotg210_reset(fotg210); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static irqreturn_t fotg210_irq(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 status, masked_status, pcd_status = 0, cmd; + int bh; + + spin_lock(&fotg210->lock); + + status = fotg210_readl(fotg210, &fotg210->regs->status); + + /* e.g. cardbus physical eject */ + if (status == ~(u32) 0) { + fotg210_dbg(fotg210, "device removed\n"); + goto dead; + } + + /* + * We don't use STS_FLR, but some controllers don't like it to + * remain on, so mask it out along with the other status bits. + */ + masked_status = status & (INTR_MASK | STS_FLR); + + /* Shared IRQ? */ + if (!masked_status || + unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) { + spin_unlock(&fotg210->lock); + return IRQ_NONE; + } + + /* clear (just) interrupts */ + fotg210_writel(fotg210, masked_status, &fotg210->regs->status); + cmd = fotg210_readl(fotg210, &fotg210->regs->command); + bh = 0; + + /* unrequested/ignored: Frame List Rollover */ + dbg_status(fotg210, "irq", status); + + /* INT, ERR, and IAA interrupt rates can be throttled */ + + /* normal [4.15.1.2] or error [4.15.1.1] completion */ + if (likely((status & (STS_INT|STS_ERR)) != 0)) { + if (likely((status & STS_ERR) == 0)) + COUNT(fotg210->stats.normal); + else + COUNT(fotg210->stats.error); + bh = 1; + } + + /* complete the unlinking of some qh [4.15.2.3] */ + if (status & STS_IAA) { + + /* Turn off the IAA watchdog */ + fotg210->enabled_hrtimer_events &= + ~BIT(FOTG210_HRTIMER_IAA_WATCHDOG); + + /* + * Mild optimization: Allow another IAAD to reset the + * hrtimer, if one occurs before the next expiration. + * In theory we could always cancel the hrtimer, but + * tests show that about half the time it will be reset + * for some other event anyway. + */ + if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG) + ++fotg210->next_hrtimer_event; + + /* guard against (alleged) silicon errata */ + if (cmd & CMD_IAAD) + fotg210_dbg(fotg210, "IAA with IAAD still set?\n"); + if (fotg210->async_iaa) { + COUNT(fotg210->stats.iaa); + end_unlink_async(fotg210); + } else + fotg210_dbg(fotg210, "IAA with nothing unlinked?\n"); + } + + /* remote wakeup [4.3.1] */ + if (status & STS_PCD) { + int pstatus; + u32 __iomem *status_reg = &fotg210->regs->port_status; + + /* kick root hub later */ + pcd_status = status; + + /* resume root hub? */ + if (fotg210->rh_state == FOTG210_RH_SUSPENDED) + usb_hcd_resume_root_hub(hcd); + + pstatus = fotg210_readl(fotg210, status_reg); + + if (test_bit(0, &fotg210->suspended_ports) && + ((pstatus & PORT_RESUME) || + !(pstatus & PORT_SUSPEND)) && + (pstatus & PORT_PE) && + fotg210->reset_done[0] == 0) { + + /* start 20 msec resume signaling from this port, + * and make khubd collect PORT_STAT_C_SUSPEND to + * stop that signaling. Use 5 ms extra for safety, + * like usb_port_resume() does. + */ + fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25); + set_bit(0, &fotg210->resuming_ports); + fotg210_dbg(fotg210, "port 1 remote wakeup\n"); + mod_timer(&hcd->rh_timer, fotg210->reset_done[0]); + } + } + + /* PCI errors [4.15.2.4] */ + if (unlikely((status & STS_FATAL) != 0)) { + fotg210_err(fotg210, "fatal error\n"); + dbg_cmd(fotg210, "fatal", cmd); + dbg_status(fotg210, "fatal", status); +dead: + usb_hc_died(hcd); + + /* Don't let the controller do anything more */ + fotg210->shutdown = true; + fotg210->rh_state = FOTG210_RH_STOPPING; + fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE); + fotg210_writel(fotg210, fotg210->command, + &fotg210->regs->command); + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); + fotg210_handle_controller_death(fotg210); + + /* Handle completions when the controller stops */ + bh = 0; + } + + if (bh) + fotg210_work(fotg210); + spin_unlock(&fotg210->lock); + if (pcd_status) + usb_hcd_poll_rh_status(hcd); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + * + * urb + dev is in hcd.self.controller.urb_list + * we're queueing TDs onto software and hardware lists + * + * hcd-specific init for hcpriv hasn't been done yet + * + * NOTE: control, bulk, and interrupt share the same code to append TDs + * to a (possibly active) QH, and the same QH scanning code. + */ +static int fotg210_urb_enqueue( + struct usb_hcd *hcd, + struct urb *urb, + gfp_t mem_flags +) { + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct list_head qtd_list; + + INIT_LIST_HEAD(&qtd_list); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + /* qh_completions() code doesn't handle all the fault cases + * in multi-TD control transfers. Even 1KB is rare anyway. + */ + if (urb->transfer_buffer_length > (16 * 1024)) + return -EMSGSIZE; + /* FALLTHROUGH */ + /* case PIPE_BULK: */ + default: + if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return submit_async(fotg210, urb, &qtd_list, mem_flags); + + case PIPE_INTERRUPT: + if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return intr_submit(fotg210, urb, &qtd_list, mem_flags); + + case PIPE_ISOCHRONOUS: + return itd_submit(fotg210, urb, mem_flags); + } +} + +/* remove from hardware lists + * completions normally happen asynchronously + */ + +static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct fotg210_qh *qh; + unsigned long flags; + int rc; + + spin_lock_irqsave(&fotg210->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + + switch (usb_pipetype(urb->pipe)) { + /* case PIPE_CONTROL: */ + /* case PIPE_BULK:*/ + default: + qh = (struct fotg210_qh *) urb->hcpriv; + if (!qh) + break; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + start_unlink_async(fotg210, qh); + break; + case QH_STATE_UNLINK: + case QH_STATE_UNLINK_WAIT: + /* already started */ + break; + case QH_STATE_IDLE: + /* QH might be waiting for a Clear-TT-Buffer */ + qh_completions(fotg210, qh); + break; + } + break; + + case PIPE_INTERRUPT: + qh = (struct fotg210_qh *) urb->hcpriv; + if (!qh) + break; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + start_unlink_intr(fotg210, qh); + break; + case QH_STATE_IDLE: + qh_completions(fotg210, qh); + break; + default: + fotg210_dbg(fotg210, "bogus qh %p state %d\n", + qh, qh->qh_state); + goto done; + } + break; + + case PIPE_ISOCHRONOUS: + /* itd... */ + + /* wait till next completion, do it then. */ + /* completion irqs can wait up to 1024 msec, */ + break; + } +done: + spin_unlock_irqrestore(&fotg210->lock, flags); + return rc; +} + +/*-------------------------------------------------------------------------*/ + +/* bulk qh holds the data toggle */ + +static void +fotg210_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + unsigned long flags; + struct fotg210_qh *qh, *tmp; + + /* ASSERT: any requests/urbs are being unlinked */ + /* ASSERT: nobody can be submitting urbs for this any more */ + +rescan: + spin_lock_irqsave(&fotg210->lock, flags); + qh = ep->hcpriv; + if (!qh) + goto done; + + /* endpoints can be iso streams. for now, we don't + * accelerate iso completions ... so spin a while. + */ + if (qh->hw == NULL) { + struct fotg210_iso_stream *stream = ep->hcpriv; + + if (!list_empty(&stream->td_list)) + goto idle_timeout; + + /* BUG_ON(!list_empty(&stream->free_list)); */ + kfree(stream); + goto done; + } + + if (fotg210->rh_state < FOTG210_RH_RUNNING) + qh->qh_state = QH_STATE_IDLE; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + for (tmp = fotg210->async->qh_next.qh; + tmp && tmp != qh; + tmp = tmp->qh_next.qh) + continue; + /* periodic qh self-unlinks on empty, and a COMPLETING qh + * may already be unlinked. + */ + if (tmp) + start_unlink_async(fotg210, qh); + /* FALL THROUGH */ + case QH_STATE_UNLINK: /* wait for hw to finish? */ + case QH_STATE_UNLINK_WAIT: +idle_timeout: + spin_unlock_irqrestore(&fotg210->lock, flags); + schedule_timeout_uninterruptible(1); + goto rescan; + case QH_STATE_IDLE: /* fully unlinked */ + if (qh->clearing_tt) + goto idle_timeout; + if (list_empty(&qh->qtd_list)) { + qh_destroy(fotg210, qh); + break; + } + /* else FALL THROUGH */ + default: + /* caller was supposed to have unlinked any requests; + * that's not our job. just leak this memory. + */ + fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n", + qh, ep->desc.bEndpointAddress, qh->qh_state, + list_empty(&qh->qtd_list) ? "" : "(has tds)"); + break; + } + done: + ep->hcpriv = NULL; + spin_unlock_irqrestore(&fotg210->lock, flags); +} + +static void +fotg210_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct fotg210_qh *qh; + int eptype = usb_endpoint_type(&ep->desc); + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + unsigned long flags; + + if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) + return; + + spin_lock_irqsave(&fotg210->lock, flags); + qh = ep->hcpriv; + + /* For Bulk and Interrupt endpoints we maintain the toggle state + * in the hardware; the toggle bits in udev aren't used at all. + * When an endpoint is reset by usb_clear_halt() we must reset + * the toggle bit in the QH. + */ + if (qh) { + usb_settoggle(qh->dev, epnum, is_out, 0); + if (!list_empty(&qh->qtd_list)) { + WARN_ONCE(1, "clear_halt for a busy endpoint\n"); + } else if (qh->qh_state == QH_STATE_LINKED || + qh->qh_state == QH_STATE_COMPLETING) { + + /* The toggle value in the QH can't be updated + * while the QH is active. Unlink it now; + * re-linking will call qh_refresh(). + */ + if (eptype == USB_ENDPOINT_XFER_BULK) + start_unlink_async(fotg210, qh); + else + start_unlink_intr(fotg210, qh); + } + } + spin_unlock_irqrestore(&fotg210->lock, flags); +} + +static int fotg210_get_frame(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + return (fotg210_read_frame_index(fotg210) >> 3) % + fotg210->periodic_size; +} + +/*-------------------------------------------------------------------------*/ + +/* + * 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 fotg210 driver exclusive access to those. + */ +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); + +static const struct hc_driver fotg210_fotg210_hc_driver = { + .description = hcd_name, + .product_desc = "Faraday USB2.0 Host Controller", + .hcd_priv_size = sizeof(struct fotg210_hcd), + + /* + * generic hardware linkage + */ + .irq = fotg210_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = hcd_fotg210_init, + .start = fotg210_run, + .stop = fotg210_stop, + .shutdown = fotg210_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = fotg210_urb_enqueue, + .urb_dequeue = fotg210_urb_dequeue, + .endpoint_disable = fotg210_endpoint_disable, + .endpoint_reset = fotg210_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = fotg210_get_frame, + + /* + * root hub support + */ + .hub_status_data = fotg210_hub_status_data, + .hub_control = fotg210_hub_control, + .bus_suspend = fotg210_bus_suspend, + .bus_resume = fotg210_bus_resume, + + .relinquish_port = fotg210_relinquish_port, + .port_handed_over = fotg210_port_handed_over, + + .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete, +}; + +static void fotg210_init(struct fotg210_hcd *fotg210) +{ + u32 value; + + iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY, + &fotg210->regs->gmir); + + value = ioread32(&fotg210->regs->otgcsr); + value &= ~OTGCSR_A_BUS_DROP; + value |= OTGCSR_A_BUS_REQ; + iowrite32(value, &fotg210->regs->otgcsr); +} + +/** + * fotg210_hcd_probe - initialize faraday FOTG210 HCDs + * + * 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. + */ +static int fotg210_hcd_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_hcd *hcd; + struct resource *res; + int irq; + int retval = -ENODEV; + struct fotg210_hcd *fotg210; + + if (usb_disabled()) + return -ENODEV; + + pdev->dev.power.power_state = PMSG_ON; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, + "Found HC with no IRQ. Check %s setup!\n", + dev_name(dev)); + return -ENODEV; + } + + irq = res->start; + + hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev, + dev_name(dev)); + if (!hcd) { + dev_err(dev, "failed to create hcd with err %d\n", retval); + retval = -ENOMEM; + goto fail_create_hcd; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(dev)); + retval = -ENODEV; + goto fail_request_resource; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + hcd->has_tt = 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + fotg210_fotg210_hc_driver.description)) { + dev_dbg(dev, "controller already in use\n"); + retval = -EBUSY; + goto fail_request_resource; + } + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(dev)); + retval = -ENODEV; + goto fail_request_resource; + } + + hcd->regs = ioremap_nocache(res->start, resource_size(res)); + if (hcd->regs == NULL) { + dev_dbg(dev, "error mapping memory\n"); + retval = -EFAULT; + goto fail_ioremap; + } + + fotg210 = hcd_to_fotg210(hcd); + + fotg210->caps = hcd->regs; + + retval = fotg210_setup(hcd); + if (retval) + goto fail_add_hcd; + + fotg210_init(fotg210); + + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval) { + dev_err(dev, "failed to add hcd with err %d\n", retval); + goto fail_add_hcd; + } + device_wakeup_enable(hcd->self.controller); + + return retval; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +fail_request_resource: + usb_put_hcd(hcd); +fail_create_hcd: + dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); + return retval; +} + +/** + * fotg210_hcd_remove - shutdown processing for EHCI HCDs + * @dev: USB Host Controller being removed + * + */ +static int fotg210_hcd_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_hcd *hcd = dev_get_drvdata(dev); + + if (!hcd) + return 0; + + 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 fotg210_hcd_driver = { + .driver = { + .name = "fotg210-hcd", + }, + .probe = fotg210_hcd_probe, + .remove = fotg210_hcd_remove, +}; + +static int __init fotg210_hcd_init(void) +{ + int retval = 0; + + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || + test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) + pr_warn(KERN_WARNING "Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n"); + + pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd\n", + hcd_name, + sizeof(struct fotg210_qh), sizeof(struct fotg210_qtd), + sizeof(struct fotg210_itd)); + + fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root); + if (!fotg210_debug_root) { + retval = -ENOENT; + goto err_debug; + } + + retval = platform_driver_register(&fotg210_hcd_driver); + if (retval < 0) + goto clean; + return retval; + + platform_driver_unregister(&fotg210_hcd_driver); +clean: + debugfs_remove(fotg210_debug_root); + fotg210_debug_root = NULL; +err_debug: + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + return retval; +} +module_init(fotg210_hcd_init); + +static void __exit fotg210_hcd_cleanup(void) +{ + platform_driver_unregister(&fotg210_hcd_driver); + debugfs_remove(fotg210_debug_root); + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); +} +module_exit(fotg210_hcd_cleanup); diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h new file mode 100644 index 00000000000..ac6cd1bfd20 --- /dev/null +++ b/drivers/usb/host/fotg210.h @@ -0,0 +1,742 @@ +#ifndef __LINUX_FOTG210_H +#define __LINUX_FOTG210_H + +/* definitions used for the EHCI driver */ + +/* + * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to + * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on + * the host controller implementation. + * + * To facilitate the strongest possible byte-order checking from "sparse" + * and so on, we use __leXX unless that's not practical. + */ +#define __hc32 __le32 +#define __hc16 __le16 + +/* statistics can be kept for tuning/monitoring */ +struct fotg210_stats { + /* irq usage */ + unsigned long normal; + unsigned long error; + unsigned long iaa; + unsigned long lost_iaa; + + /* termination of urbs from core */ + unsigned long complete; + unsigned long unlink; +}; + +/* fotg210_hcd->lock guards shared data against other CPUs: + * fotg210_hcd: async, unlink, periodic (and shadow), ... + * usb_host_endpoint: hcpriv + * fotg210_qh: qh_next, qtd_list + * fotg210_qtd: qtd_list + * + * Also, hold this lock when talking to HC registers or + * when updating hw_* fields in shared qh/qtd/... structures. + */ + +#define FOTG210_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */ + +/* + * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the + * controller may be doing DMA. Lower values mean there's no DMA. + */ +enum fotg210_rh_state { + FOTG210_RH_HALTED, + FOTG210_RH_SUSPENDED, + FOTG210_RH_RUNNING, + FOTG210_RH_STOPPING +}; + +/* + * Timer events, ordered by increasing delay length. + * Always update event_delays_ns[] and event_handlers[] (defined in + * ehci-timer.c) in parallel with this list. + */ +enum fotg210_hrtimer_event { + FOTG210_HRTIMER_POLL_ASS, /* Poll for async schedule off */ + FOTG210_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ + FOTG210_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ + FOTG210_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ + FOTG210_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ + FOTG210_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ + FOTG210_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ + FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ + FOTG210_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ + FOTG210_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */ + FOTG210_HRTIMER_NUM_EVENTS /* Must come last */ +}; +#define FOTG210_HRTIMER_NO_EVENT 99 + +struct fotg210_hcd { /* one per controller */ + /* timing support */ + enum fotg210_hrtimer_event next_hrtimer_event; + unsigned enabled_hrtimer_events; + ktime_t hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS]; + struct hrtimer hrtimer; + + int PSS_poll_count; + int ASS_poll_count; + int died_poll_count; + + /* glue to PCI and HCD framework */ + struct fotg210_caps __iomem *caps; + struct fotg210_regs __iomem *regs; + struct fotg210_dbg_port __iomem *debug; + + __u32 hcs_params; /* cached register copy */ + spinlock_t lock; + enum fotg210_rh_state rh_state; + + /* general schedule support */ + bool scanning:1; + bool need_rescan:1; + bool intr_unlinking:1; + bool async_unlinking:1; + bool shutdown:1; + struct fotg210_qh *qh_scan_next; + + /* async schedule support */ + struct fotg210_qh *async; + struct fotg210_qh *dummy; /* For AMD quirk use */ + struct fotg210_qh *async_unlink; + struct fotg210_qh *async_unlink_last; + struct fotg210_qh *async_iaa; + unsigned async_unlink_cycle; + unsigned async_count; /* async activity count */ + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ + unsigned periodic_size; + __hc32 *periodic; /* hw periodic table */ + dma_addr_t periodic_dma; + struct list_head intr_qh_list; + unsigned i_thresh; /* uframes HC might cache */ + + union fotg210_shadow *pshadow; /* mirror hw periodic table */ + struct fotg210_qh *intr_unlink; + struct fotg210_qh *intr_unlink_last; + unsigned intr_unlink_cycle; + unsigned now_frame; /* frame from HC hardware */ + unsigned next_frame; /* scan periodic, start here */ + unsigned intr_count; /* intr activity count */ + unsigned isoc_count; /* isoc activity count */ + unsigned periodic_count; /* periodic activity count */ + /* max periodic time per uframe */ + unsigned uframe_periodic_max; + + + /* list of itds completed while now_frame was still active */ + struct list_head cached_itd_list; + struct fotg210_itd *last_itd_to_free; + + /* per root hub port */ + unsigned long reset_done[FOTG210_MAX_ROOT_PORTS]; + + /* bit vectors (one bit per port) */ + unsigned long bus_suspended; /* which ports were + already suspended at the start of a bus suspend */ + unsigned long companion_ports; /* which ports are + dedicated to the companion controller */ + unsigned long owned_ports; /* which ports are + owned by the companion during a bus suspend */ + unsigned long port_c_suspend; /* which ports have + the change-suspend feature turned on */ + unsigned long suspended_ports; /* which ports are + suspended */ + unsigned long resuming_ports; /* which ports have + started to resume */ + + /* per-HC memory pools (could be per-bus, but ...) */ + struct dma_pool *qh_pool; /* qh per active urb */ + struct dma_pool *qtd_pool; /* one or more per qh */ + struct dma_pool *itd_pool; /* itd per iso urb */ + + unsigned random_frame; + unsigned long next_statechange; + ktime_t last_periodic_enable; + u32 command; + + /* SILICON QUIRKS */ + unsigned need_io_watchdog:1; + unsigned fs_i_thresh:1; /* Intel iso scheduling */ + + u8 sbrn; /* packed release number */ + + /* irq statistics */ +#ifdef FOTG210_STATS + struct fotg210_stats stats; +# define COUNT(x) ((x)++) +#else +# define COUNT(x) +#endif + + /* debug files */ + struct dentry *debug_dir; +}; + +/* convert between an HCD pointer and the corresponding FOTG210_HCD */ +static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd) +{ + return (struct fotg210_hcd *)(hcd->hcd_priv); +} +static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210) +{ + return container_of((void *) fotg210, struct usb_hcd, hcd_priv); +} + +/*-------------------------------------------------------------------------*/ + +/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ + +/* Section 2.2 Host Controller Capability Registers */ +struct fotg210_caps { + /* these fields are specified as 8 and 16 bit registers, + * but some hosts can't perform 8 or 16 bit PCI accesses. + * some hosts treat caplength and hciversion as parts of a 32-bit + * register, others treat them as two separate registers, this + * affects the memory map for big endian controllers. + */ + u32 hc_capbase; +#define HC_LENGTH(fotg210, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \ + (fotg210_big_endian_capbase(fotg210) ? 24 : 0))) +#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \ + (fotg210_big_endian_capbase(fotg210) ? 0 : 16))) + u32 hcs_params; /* HCSPARAMS - offset 0x4 */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ + + u32 hcc_params; /* HCCPARAMS - offset 0x8 */ +#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ +#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ + u8 portroute[8]; /* nibbles for routing - offset 0xC */ +}; + + +/* Section 2.3 Host Controller Operational Registers */ +struct fotg210_regs { + + /* USBCMD: offset 0x00 */ + u32 command; + +/* EHCI 1.1 addendum */ +/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ +#define CMD_PARK (1<<11) /* enable "park" on async qh */ +#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ +#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ +#define CMD_ASE (1<<5) /* async schedule enable */ +#define CMD_PSE (1<<4) /* periodic schedule enable */ +/* 3:2 is periodic frame list size */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ + + /* USBSTS: offset 0x04 */ + u32 status; +#define STS_ASS (1<<15) /* Async Schedule Status */ +#define STS_PSS (1<<14) /* Periodic Schedule Status */ +#define STS_RECL (1<<13) /* Reclamation */ +#define STS_HALT (1<<12) /* Not running (any reason) */ +/* some bits reserved */ + /* these STS_* flags are also intr_enable bits (USBINTR) */ +#define STS_IAA (1<<5) /* Interrupted on async advance */ +#define STS_FATAL (1<<4) /* such as some PCI access errors */ +#define STS_FLR (1<<3) /* frame list rolled over */ +#define STS_PCD (1<<2) /* port change detect */ +#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ +#define STS_INT (1<<0) /* "normal" completion (short, ...) */ + + /* USBINTR: offset 0x08 */ + u32 intr_enable; + + /* FRINDEX: offset 0x0C */ + u32 frame_index; /* current microframe number */ + /* CTRLDSSEGMENT: offset 0x10 */ + u32 segment; /* address bits 63:32 if needed */ + /* PERIODICLISTBASE: offset 0x14 */ + u32 frame_list; /* points to periodic list */ + /* ASYNCLISTADDR: offset 0x18 */ + u32 async_next; /* address of next async queue head */ + + u32 reserved1; + /* PORTSC: offset 0x20 */ + u32 port_status; +/* 31:23 reserved */ +#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_PEC (1<<3) /* port enable change */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +#define PORT_RWC_BITS (PORT_CSC | PORT_PEC) + u32 reserved2[19]; + + /* OTGCSR: offet 0x70 */ + u32 otgcsr; +#define OTGCSR_HOST_SPD_TYP (3 << 22) +#define OTGCSR_A_BUS_DROP (1 << 5) +#define OTGCSR_A_BUS_REQ (1 << 4) + + /* OTGISR: offset 0x74 */ + u32 otgisr; +#define OTGISR_OVC (1 << 10) + + u32 reserved3[15]; + + /* GMIR: offset 0xB4 */ + u32 gmir; +#define GMIR_INT_POLARITY (1 << 3) /*Active High*/ +#define GMIR_MHC_INT (1 << 2) +#define GMIR_MOTG_INT (1 << 1) +#define GMIR_MDEV_INT (1 << 0) +}; + +/* Appendix C, Debug port ... intended for use with special "debug devices" + * that can help if there's no serial console. (nonstandard enumeration.) + */ +struct fotg210_dbg_port { + u32 control; +#define DBGP_OWNER (1<<30) +#define DBGP_ENABLED (1<<28) +#define DBGP_DONE (1<<16) +#define DBGP_INUSE (1<<10) +#define DBGP_ERRCODE(x) (((x)>>7)&0x07) +# define DBGP_ERR_BAD 1 +# define DBGP_ERR_SIGNAL 2 +#define DBGP_ERROR (1<<6) +#define DBGP_GO (1<<5) +#define DBGP_OUT (1<<4) +#define DBGP_LEN(x) (((x)>>0)&0x0f) + u32 pids; +#define DBGP_PID_GET(x) (((x)>>16)&0xff) +#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) + u32 data03; + u32 data47; + u32 address; +#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) +}; + +#ifdef CONFIG_EARLY_PRINTK_DBGP +#include <linux/init.h> +extern int __init early_dbgp_init(char *s); +extern struct console early_dbgp_console; +#endif /* CONFIG_EARLY_PRINTK_DBGP */ + +struct usb_hcd; + +static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) +{ + return 1; /* Shouldn't this be 0? */ +} + +static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) +{ + return -1; +} + +#ifdef CONFIG_EARLY_PRINTK_DBGP +/* Call backs from fotg210 host driver to fotg210 debug driver */ +extern int dbgp_external_startup(struct usb_hcd *); +extern int dbgp_reset_prep(struct usb_hcd *hcd); +#else +static inline int dbgp_reset_prep(struct usb_hcd *hcd) +{ + return xen_dbgp_reset_prep(hcd); +} +static inline int dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_external_startup(hcd); +} +#endif + +/*-------------------------------------------------------------------------*/ + +#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma) + +/* + * EHCI Specification 0.95 Section 3.5 + * QTD: describe data transfer components (buffer, direction, ...) + * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". + * + * These are associated only with "QH" (Queue Head) structures, + * used with control, bulk, and interrupt transfers. + */ +struct fotg210_qtd { + /* first part defined by EHCI spec */ + __hc32 hw_next; /* see EHCI 3.5.1 */ + __hc32 hw_alt_next; /* see EHCI 3.5.2 */ + __hc32 hw_token; /* see EHCI 3.5.3 */ +#define QTD_TOGGLE (1 << 31) /* data toggle */ +#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) +#define QTD_IOC (1 << 15) /* interrupt on complete */ +#define QTD_CERR(tok) (((tok)>>10) & 0x3) +#define QTD_PID(tok) (((tok)>>8) & 0x3) +#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ +#define QTD_STS_HALT (1 << 6) /* halted on error */ +#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ +#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ +#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ +#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ +#define QTD_STS_STS (1 << 1) /* split transaction state */ +#define QTD_STS_PING (1 << 0) /* issue PING? */ + +#define ACTIVE_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_ACTIVE) +#define HALT_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_HALT) +#define STATUS_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_STS) + + __hc32 hw_buf[5]; /* see EHCI 3.5.4 */ + __hc32 hw_buf_hi[5]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t qtd_dma; /* qtd address */ + struct list_head qtd_list; /* sw qtd list */ + struct urb *urb; /* qtd's urb */ + size_t length; /* length of buffer */ +} __aligned(32); + +/* mask NakCnt+T in qh->hw_alt_next */ +#define QTD_MASK(fotg210) cpu_to_hc32(fotg210, ~0x1f) + +#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1) + +/*-------------------------------------------------------------------------*/ + +/* type tag from {qh,itd,fstn}->hw_next */ +#define Q_NEXT_TYPE(fotg210, dma) ((dma) & cpu_to_hc32(fotg210, 3 << 1)) + +/* + * Now the following defines are not converted using the + * cpu_to_le32() macro anymore, since we have to support + * "dynamic" switching between be and le support, so that the driver + * can be used on one system with SoC EHCI controller using big-endian + * descriptors as well as a normal little-endian PCI EHCI controller. + */ +/* values for that type tag */ +#define Q_TYPE_ITD (0 << 1) +#define Q_TYPE_QH (1 << 1) +#define Q_TYPE_SITD (2 << 1) +#define Q_TYPE_FSTN (3 << 1) + +/* next async queue entry, or pointer to interrupt/periodic QH */ +#define QH_NEXT(fotg210, dma) \ + (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH)) + +/* for periodic/async schedules and qtd lists, mark end of list */ +#define FOTG210_LIST_END(fotg210) \ + cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */ + +/* + * Entries in periodic shadow table are pointers to one of four kinds + * of data structure. That's dictated by the hardware; a type tag is + * encoded in the low bits of the hardware's periodic schedule. Use + * Q_NEXT_TYPE to get the tag. + * + * For entries in the async schedule, the type tag always says "qh". + */ +union fotg210_shadow { + struct fotg210_qh *qh; /* Q_TYPE_QH */ + struct fotg210_itd *itd; /* Q_TYPE_ITD */ + struct fotg210_fstn *fstn; /* Q_TYPE_FSTN */ + __hc32 *hw_next; /* (all types) */ + void *ptr; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.6 + * QH: describes control/bulk/interrupt endpoints + * See Fig 3-7 "Queue Head Structure Layout". + * + * These appear in both the async and (for interrupt) periodic schedules. + */ + +/* first part defined by EHCI spec */ +struct fotg210_qh_hw { + __hc32 hw_next; /* see EHCI 3.6.1 */ + __hc32 hw_info1; /* see EHCI 3.6.2 */ +#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */ +#define QH_HEAD (1 << 15) /* Head of async reclamation list */ +#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */ +#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */ +#define QH_LOW_SPEED (1 << 12) +#define QH_FULL_SPEED (0 << 12) +#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */ + __hc32 hw_info2; /* see EHCI 3.6.2 */ +#define QH_SMASK 0x000000ff +#define QH_CMASK 0x0000ff00 +#define QH_HUBADDR 0x007f0000 +#define QH_HUBPORT 0x3f800000 +#define QH_MULT 0xc0000000 + __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */ + + /* qtd overlay (hardware parts of a struct fotg210_qtd) */ + __hc32 hw_qtd_next; + __hc32 hw_alt_next; + __hc32 hw_token; + __hc32 hw_buf[5]; + __hc32 hw_buf_hi[5]; +} __aligned(32); + +struct fotg210_qh { + struct fotg210_qh_hw *hw; /* Must come first */ + /* the rest is HCD-private */ + dma_addr_t qh_dma; /* address of qh */ + union fotg210_shadow qh_next; /* ptr to qh; or periodic */ + struct list_head qtd_list; /* sw qtd list */ + struct list_head intr_node; /* list of intr QHs */ + struct fotg210_qtd *dummy; + struct fotg210_qh *unlink_next; /* next on unlink list */ + + unsigned unlink_cycle; + + u8 needs_rescan; /* Dequeue during giveback */ + u8 qh_state; +#define QH_STATE_LINKED 1 /* HC sees this */ +#define QH_STATE_UNLINK 2 /* HC may still see this */ +#define QH_STATE_IDLE 3 /* HC doesn't see this */ +#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */ +#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ + + u8 xacterrs; /* XactErr retry counter */ +#define QH_XACTERR_MAX 32 /* XactErr retry limit */ + + /* periodic schedule info */ + u8 usecs; /* intr bandwidth */ + u8 gap_uf; /* uframes split/csplit gap */ + u8 c_usecs; /* ... split completion bw */ + u16 tt_usecs; /* tt downstream bandwidth */ + unsigned short period; /* polling interval */ + unsigned short start; /* where polling starts */ +#define NO_FRAME ((unsigned short)~0) /* pick new start */ + + struct usb_device *dev; /* access to TT */ + unsigned is_out:1; /* bulk or intr OUT */ + unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ +}; + +/*-------------------------------------------------------------------------*/ + +/* description of one iso transaction (up to 3 KB data if highspeed) */ +struct fotg210_iso_packet { + /* These will be copied to iTD when scheduling */ + u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ + __hc32 transaction; /* itd->hw_transaction[i] |= */ + u8 cross; /* buf crosses pages */ + /* for full speed OUT splits */ + u32 buf1; +}; + +/* temporary schedule data for packets from iso urbs (both speeds) + * each packet is one logical usb transaction to the device (not TT), + * beginning at stream->next_uframe + */ +struct fotg210_iso_sched { + struct list_head td_list; + unsigned span; + struct fotg210_iso_packet packet[0]; +}; + +/* + * fotg210_iso_stream - groups all (s)itds for this endpoint. + * acts like a qh would, if EHCI had them for ISO. + */ +struct fotg210_iso_stream { + /* first field matches fotg210_hq, but is NULL */ + struct fotg210_qh_hw *hw; + + u8 bEndpointAddress; + u8 highspeed; + struct list_head td_list; /* queued itds */ + struct list_head free_list; /* list of unused itds */ + struct usb_device *udev; + struct usb_host_endpoint *ep; + + /* output of (re)scheduling */ + int next_uframe; + __hc32 splits; + + /* the rest is derived from the endpoint descriptor, + * trusting urb->interval == f(epdesc->bInterval) and + * including the extra info for hw_bufp[0..2] + */ + u8 usecs, c_usecs; + u16 interval; + u16 tt_usecs; + u16 maxp; + u16 raw_mask; + unsigned bandwidth; + + /* This is used to initialize iTD's hw_bufp fields */ + __hc32 buf0; + __hc32 buf1; + __hc32 buf2; + + /* this is used to initialize sITD's tt info */ + __hc32 address; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.3 + * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" + * + * Schedule records for high speed iso xfers + */ +struct fotg210_itd { + /* first part defined by EHCI spec */ + __hc32 hw_next; /* see EHCI 3.3.1 */ + __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */ +#define FOTG210_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ +#define FOTG210_ISOC_BUF_ERR (1<<30) /* Data buffer error */ +#define FOTG210_ISOC_BABBLE (1<<29) /* babble detected */ +#define FOTG210_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ +#define FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff) +#define FOTG210_ITD_IOC (1 << 15) /* interrupt on complete */ + +#define ITD_ACTIVE(fotg210) cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE) + + __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */ + __hc32 hw_bufp_hi[7]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t itd_dma; /* for this itd */ + union fotg210_shadow itd_next; /* ptr to periodic q entry */ + + struct urb *urb; + struct fotg210_iso_stream *stream; /* endpoint's queue */ + struct list_head itd_list; /* list of stream's itds */ + + /* any/all hw_transactions here may be used by that urb */ + unsigned frame; /* where scheduled */ + unsigned pg; + unsigned index[8]; /* in urb->iso_frame_desc */ +} __aligned(32); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.96 Section 3.7 + * Periodic Frame Span Traversal Node (FSTN) + * + * Manages split interrupt transactions (using TT) that span frame boundaries + * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN + * makes the HC jump (back) to a QH to scan for fs/ls QH completions until + * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. + */ +struct fotg210_fstn { + __hc32 hw_next; /* any periodic q entry */ + __hc32 hw_prev; /* qh or FOTG210_LIST_END */ + + /* the rest is HCD-private */ + dma_addr_t fstn_dma; + union fotg210_shadow fstn_next; /* ptr to periodic q entry */ +} __aligned(32); + +/*-------------------------------------------------------------------------*/ + +/* Prepare the PORTSC wakeup flags during controller suspend/resume */ + +#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \ + fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup); + +#define fotg210_prepare_ports_for_controller_resume(fotg210) \ + fotg210_adjust_port_wakeup_flags(fotg210, false, false); + +/*-------------------------------------------------------------------------*/ + +/* + * Some EHCI controllers have a Transaction Translator built into the + * root hub. This is a non-standard feature. Each controller will need + * to add code to the following inline functions, and call them as + * needed (mostly in root hub code). + */ + +static inline unsigned int +fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc) +{ + return (readl(&fotg210->regs->otgcsr) + & OTGCSR_HOST_SPD_TYP) >> 22; +} + +/* Returns the speed of a device attached to a port on the root hub. */ +static inline unsigned int +fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc) +{ + switch (fotg210_get_speed(fotg210, portsc)) { + case 0: + return 0; + case 1: + return USB_PORT_STAT_LOW_SPEED; + case 2: + default: + return USB_PORT_STAT_HIGH_SPEED; + } +} + +/*-------------------------------------------------------------------------*/ + +#define fotg210_has_fsl_portno_bug(e) (0) + +/* + * While most USB host controllers implement their registers in + * little-endian format, a minority (celleb companion chip) implement + * them in big endian format. + * + * This attempts to support either format at compile time without a + * runtime penalty, or both formats with the additional overhead + * of checking a flag bit. + * + */ + +#define fotg210_big_endian_mmio(e) 0 +#define fotg210_big_endian_capbase(e) 0 + +static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210, + __u32 __iomem *regs) +{ + return readl(regs); +} + +static inline void fotg210_writel(const struct fotg210_hcd *fotg210, + const unsigned int val, __u32 __iomem *regs) +{ + writel(val, regs); +} + +/* cpu to fotg210 */ +static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x) +{ + return cpu_to_le32(x); +} + +/* fotg210 to cpu */ +static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x) +{ + return le32_to_cpu(x); +} + +static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210, + const __hc32 *x) +{ + return le32_to_cpup(x); +} + +/*-------------------------------------------------------------------------*/ + +static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210) +{ + return fotg210_readl(fotg210, &fotg210->regs->frame_index); +} + +#define fotg210_itdlen(urb, desc, t) ({ \ + usb_pipein((urb)->pipe) ? \ + (desc)->length - FOTG210_ITD_LENGTH(t) : \ + FOTG210_ITD_LENGTH(t); \ +}) +/*-------------------------------------------------------------------------*/ + +#endif /* __LINUX_FOTG210_H */ diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 11e0b79ff9d..9162d1b6c0a 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -24,7 +24,7 @@ struct fsl_usb2_dev_data { enum fsl_usb2_operating_modes op_mode; /* operating mode */ }; -struct fsl_usb2_dev_data dr_mode_data[] = { +static struct fsl_usb2_dev_data dr_mode_data[] = { { .dr_mode = "host", .drivers = { "fsl-ehci", NULL, NULL, }, @@ -42,7 +42,7 @@ struct fsl_usb2_dev_data dr_mode_data[] = { }, }; -struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np) +static struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np) { const unsigned char *prop; int i; @@ -75,7 +75,7 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) return FSL_USB2_PHY_NONE; } -struct platform_device *fsl_usb2_device_register( +static struct platform_device *fsl_usb2_device_register( struct platform_device *ofdev, struct fsl_usb2_platform_data *pdata, const char *name, int id) @@ -258,27 +258,20 @@ static int fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev) int fsl_usb2_mpc5121_init(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); struct clk *clk; - char clk_name[10]; - int base, clk_num; - - base = pdev->resource->start & 0xf000; - if (base == 0x3000) - clk_num = 1; - else if (base == 0x4000) - clk_num = 2; - else - return -ENODEV; + int err; - snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num); - clk = clk_get(&pdev->dev, clk_name); + clk = devm_clk_get(pdev->dev.parent, "ipg"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clk\n"); return PTR_ERR(clk); } - - clk_enable(clk); + err = clk_prepare_enable(clk); + if (err) { + dev_err(&pdev->dev, "failed to enable clk\n"); + return err; + } pdata->clk = clk; if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) { @@ -298,14 +291,12 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev) static void fsl_usb2_mpc5121_exit(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); pdata->regs = NULL; - if (pdata->clk) { - clk_disable(pdata->clk); - clk_put(pdata->clk); - } + if (pdata->clk) + clk_disable_unprepare(pdata->clk); } static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = { diff --git a/drivers/usb/host/fusbh200-hcd.c b/drivers/usb/host/fusbh200-hcd.c new file mode 100644 index 00000000000..ba9499060f6 --- /dev/null +++ b/drivers/usb/host/fusbh200-hcd.c @@ -0,0 +1,5894 @@ +/* + * Faraday FUSBH200 EHCI-like driver + * + * Copyright (c) 2013 Faraday Technology Corporation + * + * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com> + * Feng-Hsin Chiang <john453@faraday-tech.com> + * Po-Yu Chuang <ratbert.chuang@gmail.com> + * + * Most of code borrowed from the Linux-3.7 EHCI driver + * + * 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; either version 2 of the License, or (at your + * option) any later version. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/hrtimer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/moduleparam.h> +#include <linux/dma-mapping.h> +#include <linux/debugfs.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/unaligned.h> + +/*-------------------------------------------------------------------------*/ +#define DRIVER_AUTHOR "Yuan-Hsin Chen" +#define DRIVER_DESC "FUSBH200 Host Controller (EHCI) Driver" + +static const char hcd_name [] = "fusbh200_hcd"; + +#undef FUSBH200_URB_TRACE + +/* magic numbers that can affect system performance */ +#define FUSBH200_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define FUSBH200_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ +#define FUSBH200_TUNE_RL_TT 0 +#define FUSBH200_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define FUSBH200_TUNE_MULT_TT 1 +/* + * Some drivers think it's safe to schedule isochronous transfers more than + * 256 ms into the future (partly as a result of an old bug in the scheduling + * code). In an attempt to avoid trouble, we will use a minimum scheduling + * length of 512 frames instead of 256. + */ +#define FUSBH200_TUNE_FLS 1 /* (medium) 512-frame schedule */ + +/* Initial IRQ latency: faster than hw default */ +static int log2_irq_thresh = 0; // 0 to 6 +module_param (log2_irq_thresh, int, S_IRUGO); +MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); + +/* initial park setting: slower than hw default */ +static unsigned park = 0; +module_param (park, uint, S_IRUGO); +MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets"); + +/* 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 "fusbh200.h" + +/*-------------------------------------------------------------------------*/ + +#define fusbh200_dbg(fusbh200, fmt, args...) \ + dev_dbg (fusbh200_to_hcd(fusbh200)->self.controller , fmt , ## args ) +#define fusbh200_err(fusbh200, fmt, args...) \ + dev_err (fusbh200_to_hcd(fusbh200)->self.controller , fmt , ## args ) +#define fusbh200_info(fusbh200, fmt, args...) \ + dev_info (fusbh200_to_hcd(fusbh200)->self.controller , fmt , ## args ) +#define fusbh200_warn(fusbh200, fmt, args...) \ + dev_warn (fusbh200_to_hcd(fusbh200)->self.controller , fmt , ## args ) + +/* check the values in the HCSPARAMS register + * (host controller _Structural_ parameters) + * see EHCI spec, Table 2-4 for each value + */ +static void dbg_hcs_params (struct fusbh200_hcd *fusbh200, char *label) +{ + u32 params = fusbh200_readl(fusbh200, &fusbh200->caps->hcs_params); + + fusbh200_dbg (fusbh200, + "%s hcs_params 0x%x ports=%d\n", + label, params, + HCS_N_PORTS (params) + ); +} + +/* check the values in the HCCPARAMS register + * (host controller _Capability_ parameters) + * see EHCI Spec, Table 2-5 for each value + * */ +static void dbg_hcc_params (struct fusbh200_hcd *fusbh200, char *label) +{ + u32 params = fusbh200_readl(fusbh200, &fusbh200->caps->hcc_params); + + fusbh200_dbg (fusbh200, + "%s hcc_params %04x uframes %s%s\n", + label, + params, + HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", + HCC_CANPARK(params) ? " park" : ""); +} + +static void __maybe_unused +dbg_qtd (const char *label, struct fusbh200_hcd *fusbh200, struct fusbh200_qtd *qtd) +{ + fusbh200_dbg(fusbh200, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, + hc32_to_cpup(fusbh200, &qtd->hw_next), + hc32_to_cpup(fusbh200, &qtd->hw_alt_next), + hc32_to_cpup(fusbh200, &qtd->hw_token), + hc32_to_cpup(fusbh200, &qtd->hw_buf [0])); + if (qtd->hw_buf [1]) + fusbh200_dbg(fusbh200, " p1=%08x p2=%08x p3=%08x p4=%08x\n", + hc32_to_cpup(fusbh200, &qtd->hw_buf[1]), + hc32_to_cpup(fusbh200, &qtd->hw_buf[2]), + hc32_to_cpup(fusbh200, &qtd->hw_buf[3]), + hc32_to_cpup(fusbh200, &qtd->hw_buf[4])); +} + +static void __maybe_unused +dbg_qh (const char *label, struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + struct fusbh200_qh_hw *hw = qh->hw; + + fusbh200_dbg (fusbh200, "%s qh %p n%08x info %x %x qtd %x\n", label, + qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current); + dbg_qtd("overlay", fusbh200, (struct fusbh200_qtd *) &hw->hw_qtd_next); +} + +static void __maybe_unused +dbg_itd (const char *label, struct fusbh200_hcd *fusbh200, struct fusbh200_itd *itd) +{ + fusbh200_dbg (fusbh200, "%s [%d] itd %p, next %08x, urb %p\n", + label, itd->frame, itd, hc32_to_cpu(fusbh200, itd->hw_next), + itd->urb); + fusbh200_dbg (fusbh200, + " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", + hc32_to_cpu(fusbh200, itd->hw_transaction[0]), + hc32_to_cpu(fusbh200, itd->hw_transaction[1]), + hc32_to_cpu(fusbh200, itd->hw_transaction[2]), + hc32_to_cpu(fusbh200, itd->hw_transaction[3]), + hc32_to_cpu(fusbh200, itd->hw_transaction[4]), + hc32_to_cpu(fusbh200, itd->hw_transaction[5]), + hc32_to_cpu(fusbh200, itd->hw_transaction[6]), + hc32_to_cpu(fusbh200, itd->hw_transaction[7])); + fusbh200_dbg (fusbh200, + " buf: %08x %08x %08x %08x %08x %08x %08x\n", + hc32_to_cpu(fusbh200, itd->hw_bufp[0]), + hc32_to_cpu(fusbh200, itd->hw_bufp[1]), + hc32_to_cpu(fusbh200, itd->hw_bufp[2]), + hc32_to_cpu(fusbh200, itd->hw_bufp[3]), + hc32_to_cpu(fusbh200, itd->hw_bufp[4]), + hc32_to_cpu(fusbh200, itd->hw_bufp[5]), + hc32_to_cpu(fusbh200, itd->hw_bufp[6])); + fusbh200_dbg (fusbh200, " index: %d %d %d %d %d %d %d %d\n", + itd->index[0], itd->index[1], itd->index[2], + itd->index[3], itd->index[4], itd->index[5], + itd->index[6], itd->index[7]); +} + +static int __maybe_unused +dbg_status_buf (char *buf, unsigned len, const char *label, u32 status) +{ + return scnprintf (buf, len, + "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", + label, label [0] ? " " : "", status, + (status & STS_ASS) ? " Async" : "", + (status & STS_PSS) ? " Periodic" : "", + (status & STS_RECL) ? " Recl" : "", + (status & STS_HALT) ? " Halt" : "", + (status & STS_IAA) ? " IAA" : "", + (status & STS_FATAL) ? " FATAL" : "", + (status & STS_FLR) ? " FLR" : "", + (status & STS_PCD) ? " PCD" : "", + (status & STS_ERR) ? " ERR" : "", + (status & STS_INT) ? " INT" : "" + ); +} + +static int __maybe_unused +dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable) +{ + return scnprintf (buf, len, + "%s%sintrenable %02x%s%s%s%s%s%s", + label, label [0] ? " " : "", enable, + (enable & STS_IAA) ? " IAA" : "", + (enable & STS_FATAL) ? " FATAL" : "", + (enable & STS_FLR) ? " FLR" : "", + (enable & STS_PCD) ? " PCD" : "", + (enable & STS_ERR) ? " ERR" : "", + (enable & STS_INT) ? " INT" : "" + ); +} + +static const char *const fls_strings [] = + { "1024", "512", "256", "??" }; + +static int +dbg_command_buf (char *buf, unsigned len, const char *label, u32 command) +{ + return scnprintf (buf, len, + "%s%scommand %07x %s=%d ithresh=%d%s%s%s " + "period=%s%s %s", + label, label [0] ? " " : "", command, + (command & CMD_PARK) ? " park" : "(park)", + CMD_PARK_CNT (command), + (command >> 16) & 0x3f, + (command & CMD_IAAD) ? " IAAD" : "", + (command & CMD_ASE) ? " Async" : "", + (command & CMD_PSE) ? " Periodic" : "", + fls_strings [(command >> 2) & 0x3], + (command & CMD_RESET) ? " Reset" : "", + (command & CMD_RUN) ? "RUN" : "HALT" + ); +} + +static int +dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status) +{ + char *sig; + + /* signaling state */ + switch (status & (3 << 10)) { + case 0 << 10: sig = "se0"; break; + case 1 << 10: sig = "k"; break; /* low speed */ + case 2 << 10: sig = "j"; break; + default: sig = "?"; break; + } + + return scnprintf (buf, len, + "%s%sport:%d status %06x %d " + "sig=%s%s%s%s%s%s%s%s", + label, label [0] ? " " : "", port, status, + status>>25,/*device address */ + sig, + (status & PORT_RESET) ? " RESET" : "", + (status & PORT_SUSPEND) ? " SUSPEND" : "", + (status & PORT_RESUME) ? " RESUME" : "", + (status & PORT_PEC) ? " PEC" : "", + (status & PORT_PE) ? " PE" : "", + (status & PORT_CSC) ? " CSC" : "", + (status & PORT_CONNECT) ? " CONNECT" : ""); +} + +/* functions have the "wrong" filename when they're output... */ +#define dbg_status(fusbh200, label, status) { \ + char _buf [80]; \ + dbg_status_buf (_buf, sizeof _buf, label, status); \ + fusbh200_dbg (fusbh200, "%s\n", _buf); \ +} + +#define dbg_cmd(fusbh200, label, command) { \ + char _buf [80]; \ + dbg_command_buf (_buf, sizeof _buf, label, command); \ + fusbh200_dbg (fusbh200, "%s\n", _buf); \ +} + +#define dbg_port(fusbh200, label, port, status) { \ + char _buf [80]; \ + dbg_port_buf (_buf, sizeof _buf, label, port, status); \ + fusbh200_dbg (fusbh200, "%s\n", _buf); \ +} + +/*-------------------------------------------------------------------------*/ + +/* troubleshooting help: expose state in debugfs */ + +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_output(struct file*, char __user*, size_t, loff_t*); +static int debug_close(struct inode *, struct file *); + +static const struct file_operations debug_async_fops = { + .owner = THIS_MODULE, + .open = debug_async_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; +static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; +static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; + +static struct dentry *fusbh200_debug_root; + +struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ + struct usb_bus *bus; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *output_buf; + size_t alloc_size; +}; + +#define speed_char(info1) ({ char tmp; \ + switch (info1 & (3 << 12)) { \ + case QH_FULL_SPEED: tmp = 'f'; break; \ + case QH_LOW_SPEED: tmp = 'l'; break; \ + case QH_HIGH_SPEED: tmp = 'h'; break; \ + default: tmp = '?'; break; \ + } tmp; }) + +static inline char token_mark(struct fusbh200_hcd *fusbh200, __hc32 token) +{ + __u32 v = hc32_to_cpu(fusbh200, token); + + if (v & QTD_STS_ACTIVE) + return '*'; + if (v & QTD_STS_HALT) + return '-'; + if (!IS_SHORT_READ (v)) + return ' '; + /* tries to advance through hw_alt_next */ + return '/'; +} + +static void qh_lines ( + struct fusbh200_hcd *fusbh200, + struct fusbh200_qh *qh, + char **nextp, + unsigned *sizep +) +{ + u32 scratch; + u32 hw_curr; + struct fusbh200_qtd *td; + unsigned temp; + unsigned size = *sizep; + char *next = *nextp; + char mark; + __le32 list_end = FUSBH200_LIST_END(fusbh200); + struct fusbh200_qh_hw *hw = qh->hw; + + if (hw->hw_qtd_next == list_end) /* NEC does this */ + mark = '@'; + else + mark = token_mark(fusbh200, hw->hw_token); + if (mark == '/') { /* qh_alt_next controls qh advance? */ + if ((hw->hw_alt_next & QTD_MASK(fusbh200)) + == fusbh200->async->hw->hw_alt_next) + mark = '#'; /* blocked */ + else if (hw->hw_alt_next == list_end) + mark = '.'; /* use hw_qtd_next */ + /* else alt_next points to some other qtd */ + } + scratch = hc32_to_cpup(fusbh200, &hw->hw_info1); + hw_curr = (mark == '*') ? hc32_to_cpup(fusbh200, &hw->hw_current) : 0; + temp = scnprintf (next, size, + "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)", + qh, scratch & 0x007f, + speed_char (scratch), + (scratch >> 8) & 0x000f, + scratch, hc32_to_cpup(fusbh200, &hw->hw_info2), + hc32_to_cpup(fusbh200, &hw->hw_token), mark, + (cpu_to_hc32(fusbh200, QTD_TOGGLE) & hw->hw_token) + ? "data1" : "data0", + (hc32_to_cpup(fusbh200, &hw->hw_alt_next) >> 1) & 0x0f); + size -= temp; + next += temp; + + /* hc may be modifying the list as we read it ... */ + list_for_each_entry(td, &qh->qtd_list, qtd_list) { + scratch = hc32_to_cpup(fusbh200, &td->hw_token); + mark = ' '; + if (hw_curr == td->qtd_dma) + mark = '*'; + else if (hw->hw_qtd_next == cpu_to_hc32(fusbh200, td->qtd_dma)) + mark = '+'; + else if (QTD_LENGTH (scratch)) { + if (td->hw_alt_next == fusbh200->async->hw->hw_alt_next) + mark = '#'; + else if (td->hw_alt_next != list_end) + mark = '/'; + } + temp = snprintf (next, size, + "\n\t%p%c%s len=%d %08x urb %p", + td, mark, ({ char *tmp; + switch ((scratch>>8)&0x03) { + case 0: tmp = "out"; break; + case 1: tmp = "in"; break; + case 2: tmp = "setup"; break; + default: tmp = "?"; break; + } tmp;}), + (scratch >> 16) & 0x7fff, + scratch, + td->urb); + if (size < temp) + temp = size; + size -= temp; + next += temp; + if (temp == size) + goto done; + } + + temp = snprintf (next, size, "\n"); + if (size < temp) + temp = size; + size -= temp; + next += temp; + +done: + *sizep = size; + *nextp = next; +} + +static ssize_t fill_async_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fusbh200_hcd *fusbh200; + unsigned long flags; + unsigned temp, size; + char *next; + struct fusbh200_qh *qh; + + hcd = bus_to_hcd(buf->bus); + fusbh200 = hcd_to_fusbh200 (hcd); + next = buf->output_buf; + size = buf->alloc_size; + + *next = 0; + + /* dumps a snapshot of the async schedule. + * usually empty except for long-term bulk reads, or head. + * one QH per line, and TDs we know about + */ + spin_lock_irqsave (&fusbh200->lock, flags); + for (qh = fusbh200->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh) + qh_lines (fusbh200, qh, &next, &size); + if (fusbh200->async_unlink && size > 0) { + temp = scnprintf(next, size, "\nunlink =\n"); + size -= temp; + next += temp; + + for (qh = fusbh200->async_unlink; size > 0 && qh; + qh = qh->unlink_next) + qh_lines (fusbh200, qh, &next, &size); + } + spin_unlock_irqrestore (&fusbh200->lock, flags); + + return strlen(buf->output_buf); +} + +#define DBG_SCHED_LIMIT 64 +static ssize_t fill_periodic_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fusbh200_hcd *fusbh200; + unsigned long flags; + union fusbh200_shadow p, *seen; + unsigned temp, size, seen_count; + char *next; + unsigned i; + __hc32 tag; + + if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC))) + return 0; + seen_count = 0; + + hcd = bus_to_hcd(buf->bus); + fusbh200 = hcd_to_fusbh200 (hcd); + next = buf->output_buf; + size = buf->alloc_size; + + temp = scnprintf (next, size, "size = %d\n", fusbh200->periodic_size); + size -= temp; + next += temp; + + /* dump a snapshot of the periodic schedule. + * iso changes, interrupt usually doesn't. + */ + spin_lock_irqsave (&fusbh200->lock, flags); + for (i = 0; i < fusbh200->periodic_size; i++) { + p = fusbh200->pshadow [i]; + if (likely (!p.ptr)) + continue; + tag = Q_NEXT_TYPE(fusbh200, fusbh200->periodic [i]); + + temp = scnprintf (next, size, "%4d: ", i); + size -= temp; + next += temp; + + do { + struct fusbh200_qh_hw *hw; + + switch (hc32_to_cpu(fusbh200, tag)) { + case Q_TYPE_QH: + hw = p.qh->hw; + temp = scnprintf (next, size, " qh%d-%04x/%p", + p.qh->period, + hc32_to_cpup(fusbh200, + &hw->hw_info2) + /* uframe masks */ + & (QH_CMASK | QH_SMASK), + p.qh); + size -= temp; + next += temp; + /* don't repeat what follows this qh */ + for (temp = 0; temp < seen_count; temp++) { + if (seen [temp].ptr != p.ptr) + continue; + if (p.qh->qh_next.ptr) { + temp = scnprintf (next, size, + " ..."); + size -= temp; + next += temp; + } + break; + } + /* show more info the first time around */ + if (temp == seen_count) { + u32 scratch = hc32_to_cpup(fusbh200, + &hw->hw_info1); + struct fusbh200_qtd *qtd; + char *type = ""; + + /* count tds, get ep direction */ + temp = 0; + list_for_each_entry (qtd, + &p.qh->qtd_list, + qtd_list) { + temp++; + switch (0x03 & (hc32_to_cpu( + fusbh200, + qtd->hw_token) >> 8)) { + case 0: type = "out"; continue; + case 1: type = "in"; continue; + } + } + + temp = scnprintf (next, size, + " (%c%d ep%d%s " + "[%d/%d] q%d p%d)", + speed_char (scratch), + scratch & 0x007f, + (scratch >> 8) & 0x000f, type, + p.qh->usecs, p.qh->c_usecs, + temp, + 0x7ff & (scratch >> 16)); + + if (seen_count < DBG_SCHED_LIMIT) + seen [seen_count++].qh = p.qh; + } else + temp = 0; + tag = Q_NEXT_TYPE(fusbh200, hw->hw_next); + p = p.qh->qh_next; + break; + case Q_TYPE_FSTN: + temp = scnprintf (next, size, + " fstn-%8x/%p", p.fstn->hw_prev, + p.fstn); + tag = Q_NEXT_TYPE(fusbh200, p.fstn->hw_next); + p = p.fstn->fstn_next; + break; + case Q_TYPE_ITD: + temp = scnprintf (next, size, + " itd/%p", p.itd); + tag = Q_NEXT_TYPE(fusbh200, p.itd->hw_next); + p = p.itd->itd_next; + break; + } + size -= temp; + next += temp; + } while (p.ptr); + + temp = scnprintf (next, size, "\n"); + size -= temp; + next += temp; + } + spin_unlock_irqrestore (&fusbh200->lock, flags); + kfree (seen); + + return buf->alloc_size - size; +} +#undef DBG_SCHED_LIMIT + +static const char *rh_state_string(struct fusbh200_hcd *fusbh200) +{ + switch (fusbh200->rh_state) { + case FUSBH200_RH_HALTED: + return "halted"; + case FUSBH200_RH_SUSPENDED: + return "suspended"; + case FUSBH200_RH_RUNNING: + return "running"; + case FUSBH200_RH_STOPPING: + return "stopping"; + } + return "?"; +} + +static ssize_t fill_registers_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fusbh200_hcd *fusbh200; + unsigned long flags; + unsigned temp, size, i; + char *next, scratch [80]; + static char fmt [] = "%*s\n"; + static char label [] = ""; + + hcd = bus_to_hcd(buf->bus); + fusbh200 = hcd_to_fusbh200 (hcd); + next = buf->output_buf; + size = buf->alloc_size; + + spin_lock_irqsave (&fusbh200->lock, flags); + + if (!HCD_HW_ACCESSIBLE(hcd)) { + size = scnprintf (next, size, + "bus %s, device %s\n" + "%s\n" + "SUSPENDED (no register access)\n", + hcd->self.controller->bus->name, + dev_name(hcd->self.controller), + hcd->product_desc); + goto done; + } + + /* Capability Registers */ + i = HC_VERSION(fusbh200, fusbh200_readl(fusbh200, &fusbh200->caps->hc_capbase)); + temp = scnprintf (next, size, + "bus %s, device %s\n" + "%s\n" + "EHCI %x.%02x, rh state %s\n", + hcd->self.controller->bus->name, + dev_name(hcd->self.controller), + hcd->product_desc, + i >> 8, i & 0x0ff, rh_state_string(fusbh200)); + size -= temp; + next += temp; + + // FIXME interpret both types of params + i = fusbh200_readl(fusbh200, &fusbh200->caps->hcs_params); + temp = scnprintf (next, size, "structural params 0x%08x\n", i); + size -= temp; + next += temp; + + i = fusbh200_readl(fusbh200, &fusbh200->caps->hcc_params); + temp = scnprintf (next, size, "capability params 0x%08x\n", i); + size -= temp; + next += temp; + + /* Operational Registers */ + temp = dbg_status_buf (scratch, sizeof scratch, label, + fusbh200_readl(fusbh200, &fusbh200->regs->status)); + temp = scnprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_command_buf (scratch, sizeof scratch, label, + fusbh200_readl(fusbh200, &fusbh200->regs->command)); + temp = scnprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_intr_buf (scratch, sizeof scratch, label, + fusbh200_readl(fusbh200, &fusbh200->regs->intr_enable)); + temp = scnprintf (next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = scnprintf (next, size, "uframe %04x\n", + fusbh200_read_frame_index(fusbh200)); + size -= temp; + next += temp; + + if (fusbh200->async_unlink) { + temp = scnprintf(next, size, "async unlink qh %p\n", + fusbh200->async_unlink); + size -= temp; + next += temp; + } + + temp = scnprintf (next, size, + "irq normal %ld err %ld iaa %ld (lost %ld)\n", + fusbh200->stats.normal, fusbh200->stats.error, fusbh200->stats.iaa, + fusbh200->stats.lost_iaa); + size -= temp; + next += temp; + + temp = scnprintf (next, size, "complete %ld unlink %ld\n", + fusbh200->stats.complete, fusbh200->stats.unlink); + size -= temp; + next += temp; + +done: + spin_unlock_irqrestore (&fusbh200->lock, flags); + + return buf->alloc_size - size; +} + +static struct debug_buffer *alloc_buffer(struct usb_bus *bus, + ssize_t (*fill_func)(struct debug_buffer *)) +{ + struct debug_buffer *buf; + + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); + + if (buf) { + buf->bus = bus; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + buf->alloc_size = PAGE_SIZE; + } + + return buf; +} + +static int fill_buffer(struct debug_buffer *buf) +{ + int ret = 0; + + if (!buf->output_buf) + buf->output_buf = vmalloc(buf->alloc_size); + + if (!buf->output_buf) { + ret = -ENOMEM; + goto out; + } + + ret = buf->fill_func(buf); + + if (ret >= 0) { + buf->count = ret; + ret = 0; + } + +out: + return ret; +} + +static ssize_t debug_output(struct file *file, char __user *user_buf, + size_t len, loff_t *offset) +{ + struct debug_buffer *buf = file->private_data; + int ret = 0; + + mutex_lock(&buf->mutex); + if (buf->count == 0) { + ret = fill_buffer(buf); + if (ret != 0) { + mutex_unlock(&buf->mutex); + goto out; + } + } + mutex_unlock(&buf->mutex); + + ret = simple_read_from_buffer(user_buf, len, offset, + buf->output_buf, buf->count); + +out: + return ret; + +} + +static int debug_close(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf = file->private_data; + + if (buf) { + vfree(buf->output_buf); + kfree(buf); + } + + return 0; +} +static int debug_async_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_periodic_open(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf; + buf = alloc_buffer(inode->i_private, fill_periodic_buffer); + if (!buf) + return -ENOMEM; + + buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE; + file->private_data = buf; + return 0; +} + +static int debug_registers_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_registers_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static inline void create_debug_files (struct fusbh200_hcd *fusbh200) +{ + struct usb_bus *bus = &fusbh200_to_hcd(fusbh200)->self; + + fusbh200->debug_dir = debugfs_create_dir(bus->bus_name, fusbh200_debug_root); + if (!fusbh200->debug_dir) + return; + + if (!debugfs_create_file("async", S_IRUGO, fusbh200->debug_dir, bus, + &debug_async_fops)) + goto file_error; + + if (!debugfs_create_file("periodic", S_IRUGO, fusbh200->debug_dir, bus, + &debug_periodic_fops)) + goto file_error; + + if (!debugfs_create_file("registers", S_IRUGO, fusbh200->debug_dir, bus, + &debug_registers_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(fusbh200->debug_dir); +} + +static inline void remove_debug_files (struct fusbh200_hcd *fusbh200) +{ + debugfs_remove_recursive(fusbh200->debug_dir); +} + +/*-------------------------------------------------------------------------*/ + +/* + * handshake - spin reading hc until handshake completes or fails + * @ptr: address of hc register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + * + * That last failure should_only happen in cases like physical cardbus eject + * before driver shutdown. But it also seems to be caused by bugs in cardbus + * bridge shutdown: shutting down the bridge before the devices using it. + */ +static int handshake (struct fusbh200_hcd *fusbh200, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = fusbh200_readl(fusbh200, ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay (1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* + * Force HC to halt state from unknown (EHCI spec section 2.3). + * Must be called with interrupts enabled and the lock not held. + */ +static int fusbh200_halt (struct fusbh200_hcd *fusbh200) +{ + u32 temp; + + spin_lock_irq(&fusbh200->lock); + + /* disable any irqs left enabled by previous code */ + fusbh200_writel(fusbh200, 0, &fusbh200->regs->intr_enable); + + /* + * This routine gets called during probe before fusbh200->command + * has been initialized, so we can't rely on its value. + */ + fusbh200->command &= ~CMD_RUN; + temp = fusbh200_readl(fusbh200, &fusbh200->regs->command); + temp &= ~(CMD_RUN | CMD_IAAD); + fusbh200_writel(fusbh200, temp, &fusbh200->regs->command); + + spin_unlock_irq(&fusbh200->lock); + synchronize_irq(fusbh200_to_hcd(fusbh200)->irq); + + return handshake(fusbh200, &fusbh200->regs->status, + STS_HALT, STS_HALT, 16 * 125); +} + +/* + * Reset a non-running (STS_HALT == 1) controller. + * Must be called with interrupts enabled and the lock not held. + */ +static int fusbh200_reset (struct fusbh200_hcd *fusbh200) +{ + int retval; + u32 command = fusbh200_readl(fusbh200, &fusbh200->regs->command); + + /* If the EHCI debug controller is active, special care must be + * taken before and after a host controller reset */ + if (fusbh200->debug && !dbgp_reset_prep(fusbh200_to_hcd(fusbh200))) + fusbh200->debug = NULL; + + command |= CMD_RESET; + dbg_cmd (fusbh200, "reset", command); + fusbh200_writel(fusbh200, command, &fusbh200->regs->command); + fusbh200->rh_state = FUSBH200_RH_HALTED; + fusbh200->next_statechange = jiffies; + retval = handshake (fusbh200, &fusbh200->regs->command, + CMD_RESET, 0, 250 * 1000); + + if (retval) + return retval; + + if (fusbh200->debug) + dbgp_external_startup(fusbh200_to_hcd(fusbh200)); + + fusbh200->port_c_suspend = fusbh200->suspended_ports = + fusbh200->resuming_ports = 0; + return retval; +} + +/* + * Idle the controller (turn off the schedules). + * Must be called with interrupts enabled and the lock not held. + */ +static void fusbh200_quiesce (struct fusbh200_hcd *fusbh200) +{ + u32 temp; + + if (fusbh200->rh_state != FUSBH200_RH_RUNNING) + return; + + /* wait for any schedule enables/disables to take effect */ + temp = (fusbh200->command << 10) & (STS_ASS | STS_PSS); + handshake(fusbh200, &fusbh200->regs->status, STS_ASS | STS_PSS, temp, 16 * 125); + + /* then disable anything that's still active */ + spin_lock_irq(&fusbh200->lock); + fusbh200->command &= ~(CMD_ASE | CMD_PSE); + fusbh200_writel(fusbh200, fusbh200->command, &fusbh200->regs->command); + spin_unlock_irq(&fusbh200->lock); + + /* hardware can take 16 microframes to turn off ... */ + handshake(fusbh200, &fusbh200->regs->status, STS_ASS | STS_PSS, 0, 16 * 125); +} + +/*-------------------------------------------------------------------------*/ + +static void end_unlink_async(struct fusbh200_hcd *fusbh200); +static void unlink_empty_async(struct fusbh200_hcd *fusbh200); +static void fusbh200_work(struct fusbh200_hcd *fusbh200); +static void start_unlink_intr(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh); +static void end_unlink_intr(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh); + +/*-------------------------------------------------------------------------*/ + +/* Set a bit in the USBCMD register */ +static void fusbh200_set_command_bit(struct fusbh200_hcd *fusbh200, u32 bit) +{ + fusbh200->command |= bit; + fusbh200_writel(fusbh200, fusbh200->command, &fusbh200->regs->command); + + /* unblock posted write */ + fusbh200_readl(fusbh200, &fusbh200->regs->command); +} + +/* Clear a bit in the USBCMD register */ +static void fusbh200_clear_command_bit(struct fusbh200_hcd *fusbh200, u32 bit) +{ + fusbh200->command &= ~bit; + fusbh200_writel(fusbh200, fusbh200->command, &fusbh200->regs->command); + + /* unblock posted write */ + fusbh200_readl(fusbh200, &fusbh200->regs->command); +} + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI timer support... Now using hrtimers. + * + * Lots of different events are triggered from fusbh200->hrtimer. Whenever + * the timer routine runs, it checks each possible event; events that are + * currently enabled and whose expiration time has passed get handled. + * The set of enabled events is stored as a collection of bitflags in + * fusbh200->enabled_hrtimer_events, and they are numbered in order of + * increasing delay values (ranging between 1 ms and 100 ms). + * + * Rather than implementing a sorted list or tree of all pending events, + * we keep track only of the lowest-numbered pending event, in + * fusbh200->next_hrtimer_event. Whenever fusbh200->hrtimer gets restarted, its + * expiration time is set to the timeout value for this event. + * + * As a result, events might not get handled right away; the actual delay + * could be anywhere up to twice the requested delay. This doesn't + * matter, because none of the events are especially time-critical. The + * ones that matter most all have a delay of 1 ms, so they will be + * handled after 2 ms at most, which is okay. In addition to this, we + * allow for an expiration range of 1 ms. + */ + +/* + * Delay lengths for the hrtimer event types. + * Keep this list sorted by delay length, in the same order as + * the event types indexed by enum fusbh200_hrtimer_event in fusbh200.h. + */ +static unsigned event_delays_ns[] = { + 1 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_POLL_ASS */ + 1 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_POLL_PSS */ + 1 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_POLL_DEAD */ + 1125 * NSEC_PER_USEC, /* FUSBH200_HRTIMER_UNLINK_INTR */ + 2 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_FREE_ITDS */ + 6 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_ASYNC_UNLINKS */ + 10 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_IAA_WATCHDOG */ + 10 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_DISABLE_PERIODIC */ + 15 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_DISABLE_ASYNC */ + 100 * NSEC_PER_MSEC, /* FUSBH200_HRTIMER_IO_WATCHDOG */ +}; + +/* Enable a pending hrtimer event */ +static void fusbh200_enable_event(struct fusbh200_hcd *fusbh200, unsigned event, + bool resched) +{ + ktime_t *timeout = &fusbh200->hr_timeouts[event]; + + if (resched) + *timeout = ktime_add(ktime_get(), + ktime_set(0, event_delays_ns[event])); + fusbh200->enabled_hrtimer_events |= (1 << event); + + /* Track only the lowest-numbered pending event */ + if (event < fusbh200->next_hrtimer_event) { + fusbh200->next_hrtimer_event = event; + hrtimer_start_range_ns(&fusbh200->hrtimer, *timeout, + NSEC_PER_MSEC, HRTIMER_MODE_ABS); + } +} + + +/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */ +static void fusbh200_poll_ASS(struct fusbh200_hcd *fusbh200) +{ + unsigned actual, want; + + /* Don't enable anything if the controller isn't running (e.g., died) */ + if (fusbh200->rh_state != FUSBH200_RH_RUNNING) + return; + + want = (fusbh200->command & CMD_ASE) ? STS_ASS : 0; + actual = fusbh200_readl(fusbh200, &fusbh200->regs->status) & STS_ASS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (fusbh200->ASS_poll_count++ < 20) { + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_POLL_ASS, true); + return; + } + fusbh200_dbg(fusbh200, "Waited too long for the async schedule status (%x/%x), giving up\n", + want, actual); + } + fusbh200->ASS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + if (fusbh200->async_count > 0) + fusbh200_set_command_bit(fusbh200, CMD_ASE); + + } else { /* Running */ + if (fusbh200->async_count == 0) { + + /* Turn off the schedule after a while */ + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_DISABLE_ASYNC, + true); + } + } +} + +/* Turn off the async schedule after a brief delay */ +static void fusbh200_disable_ASE(struct fusbh200_hcd *fusbh200) +{ + fusbh200_clear_command_bit(fusbh200, CMD_ASE); +} + + +/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ +static void fusbh200_poll_PSS(struct fusbh200_hcd *fusbh200) +{ + unsigned actual, want; + + /* Don't do anything if the controller isn't running (e.g., died) */ + if (fusbh200->rh_state != FUSBH200_RH_RUNNING) + return; + + want = (fusbh200->command & CMD_PSE) ? STS_PSS : 0; + actual = fusbh200_readl(fusbh200, &fusbh200->regs->status) & STS_PSS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (fusbh200->PSS_poll_count++ < 20) { + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_POLL_PSS, true); + return; + } + fusbh200_dbg(fusbh200, "Waited too long for the periodic schedule status (%x/%x), giving up\n", + want, actual); + } + fusbh200->PSS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + if (fusbh200->periodic_count > 0) + fusbh200_set_command_bit(fusbh200, CMD_PSE); + + } else { /* Running */ + if (fusbh200->periodic_count == 0) { + + /* Turn off the schedule after a while */ + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_DISABLE_PERIODIC, + true); + } + } +} + +/* Turn off the periodic schedule after a brief delay */ +static void fusbh200_disable_PSE(struct fusbh200_hcd *fusbh200) +{ + fusbh200_clear_command_bit(fusbh200, CMD_PSE); +} + + +/* Poll the STS_HALT status bit; see when a dead controller stops */ +static void fusbh200_handle_controller_death(struct fusbh200_hcd *fusbh200) +{ + if (!(fusbh200_readl(fusbh200, &fusbh200->regs->status) & STS_HALT)) { + + /* Give up after a few milliseconds */ + if (fusbh200->died_poll_count++ < 5) { + /* Try again later */ + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_POLL_DEAD, true); + return; + } + fusbh200_warn(fusbh200, "Waited too long for the controller to stop, giving up\n"); + } + + /* Clean up the mess */ + fusbh200->rh_state = FUSBH200_RH_HALTED; + fusbh200_writel(fusbh200, 0, &fusbh200->regs->intr_enable); + fusbh200_work(fusbh200); + end_unlink_async(fusbh200); + + /* Not in process context, so don't try to reset the controller */ +} + + +/* Handle unlinked interrupt QHs once they are gone from the hardware */ +static void fusbh200_handle_intr_unlinks(struct fusbh200_hcd *fusbh200) +{ + bool stopped = (fusbh200->rh_state < FUSBH200_RH_RUNNING); + + /* + * Process all the QHs on the intr_unlink list that were added + * before the current unlink cycle began. The list is in + * temporal order, so stop when we reach the first entry in the + * current cycle. But if the root hub isn't running then + * process all the QHs on the list. + */ + fusbh200->intr_unlinking = true; + while (fusbh200->intr_unlink) { + struct fusbh200_qh *qh = fusbh200->intr_unlink; + + if (!stopped && qh->unlink_cycle == fusbh200->intr_unlink_cycle) + break; + fusbh200->intr_unlink = qh->unlink_next; + qh->unlink_next = NULL; + end_unlink_intr(fusbh200, qh); + } + + /* Handle remaining entries later */ + if (fusbh200->intr_unlink) { + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_UNLINK_INTR, true); + ++fusbh200->intr_unlink_cycle; + } + fusbh200->intr_unlinking = false; +} + + +/* Start another free-iTDs/siTDs cycle */ +static void start_free_itds(struct fusbh200_hcd *fusbh200) +{ + if (!(fusbh200->enabled_hrtimer_events & BIT(FUSBH200_HRTIMER_FREE_ITDS))) { + fusbh200->last_itd_to_free = list_entry( + fusbh200->cached_itd_list.prev, + struct fusbh200_itd, itd_list); + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_FREE_ITDS, true); + } +} + +/* Wait for controller to stop using old iTDs and siTDs */ +static void end_free_itds(struct fusbh200_hcd *fusbh200) +{ + struct fusbh200_itd *itd, *n; + + if (fusbh200->rh_state < FUSBH200_RH_RUNNING) { + fusbh200->last_itd_to_free = NULL; + } + + list_for_each_entry_safe(itd, n, &fusbh200->cached_itd_list, itd_list) { + list_del(&itd->itd_list); + dma_pool_free(fusbh200->itd_pool, itd, itd->itd_dma); + if (itd == fusbh200->last_itd_to_free) + break; + } + + if (!list_empty(&fusbh200->cached_itd_list)) + start_free_itds(fusbh200); +} + + +/* Handle lost (or very late) IAA interrupts */ +static void fusbh200_iaa_watchdog(struct fusbh200_hcd *fusbh200) +{ + if (fusbh200->rh_state != FUSBH200_RH_RUNNING) + return; + + /* + * Lost IAA irqs wedge things badly; seen first with a vt8235. + * So we need this watchdog, but must protect it against both + * (a) SMP races against real IAA firing and retriggering, and + * (b) clean HC shutdown, when IAA watchdog was pending. + */ + if (fusbh200->async_iaa) { + u32 cmd, status; + + /* If we get here, IAA is *REALLY* late. It's barely + * conceivable that the system is so busy that CMD_IAAD + * is still legitimately set, so let's be sure it's + * clear before we read STS_IAA. (The HC should clear + * CMD_IAAD when it sets STS_IAA.) + */ + cmd = fusbh200_readl(fusbh200, &fusbh200->regs->command); + + /* + * If IAA is set here it either legitimately triggered + * after the watchdog timer expired (_way_ late, so we'll + * still count it as lost) ... or a silicon erratum: + * - VIA seems to set IAA without triggering the IRQ; + * - IAAD potentially cleared without setting IAA. + */ + status = fusbh200_readl(fusbh200, &fusbh200->regs->status); + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { + COUNT(fusbh200->stats.lost_iaa); + fusbh200_writel(fusbh200, STS_IAA, &fusbh200->regs->status); + } + + fusbh200_dbg(fusbh200, "IAA watchdog: status %x cmd %x\n", + status, cmd); + end_unlink_async(fusbh200); + } +} + + +/* Enable the I/O watchdog, if appropriate */ +static void turn_on_io_watchdog(struct fusbh200_hcd *fusbh200) +{ + /* Not needed if the controller isn't running or it's already enabled */ + if (fusbh200->rh_state != FUSBH200_RH_RUNNING || + (fusbh200->enabled_hrtimer_events & + BIT(FUSBH200_HRTIMER_IO_WATCHDOG))) + return; + + /* + * Isochronous transfers always need the watchdog. + * For other sorts we use it only if the flag is set. + */ + if (fusbh200->isoc_count > 0 || (fusbh200->need_io_watchdog && + fusbh200->async_count + fusbh200->intr_count > 0)) + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_IO_WATCHDOG, true); +} + + +/* + * Handler functions for the hrtimer event types. + * Keep this array in the same order as the event types indexed by + * enum fusbh200_hrtimer_event in fusbh200.h. + */ +static void (*event_handlers[])(struct fusbh200_hcd *) = { + fusbh200_poll_ASS, /* FUSBH200_HRTIMER_POLL_ASS */ + fusbh200_poll_PSS, /* FUSBH200_HRTIMER_POLL_PSS */ + fusbh200_handle_controller_death, /* FUSBH200_HRTIMER_POLL_DEAD */ + fusbh200_handle_intr_unlinks, /* FUSBH200_HRTIMER_UNLINK_INTR */ + end_free_itds, /* FUSBH200_HRTIMER_FREE_ITDS */ + unlink_empty_async, /* FUSBH200_HRTIMER_ASYNC_UNLINKS */ + fusbh200_iaa_watchdog, /* FUSBH200_HRTIMER_IAA_WATCHDOG */ + fusbh200_disable_PSE, /* FUSBH200_HRTIMER_DISABLE_PERIODIC */ + fusbh200_disable_ASE, /* FUSBH200_HRTIMER_DISABLE_ASYNC */ + fusbh200_work, /* FUSBH200_HRTIMER_IO_WATCHDOG */ +}; + +static enum hrtimer_restart fusbh200_hrtimer_func(struct hrtimer *t) +{ + struct fusbh200_hcd *fusbh200 = container_of(t, struct fusbh200_hcd, hrtimer); + ktime_t now; + unsigned long events; + unsigned long flags; + unsigned e; + + spin_lock_irqsave(&fusbh200->lock, flags); + + events = fusbh200->enabled_hrtimer_events; + fusbh200->enabled_hrtimer_events = 0; + fusbh200->next_hrtimer_event = FUSBH200_HRTIMER_NO_EVENT; + + /* + * Check each pending event. If its time has expired, handle + * the event; otherwise re-enable it. + */ + now = ktime_get(); + for_each_set_bit(e, &events, FUSBH200_HRTIMER_NUM_EVENTS) { + if (now.tv64 >= fusbh200->hr_timeouts[e].tv64) + event_handlers[e](fusbh200); + else + fusbh200_enable_event(fusbh200, e, false); + } + + spin_unlock_irqrestore(&fusbh200->lock, flags); + return HRTIMER_NORESTART; +} + +/*-------------------------------------------------------------------------*/ + +#define fusbh200_bus_suspend NULL +#define fusbh200_bus_resume NULL + +/*-------------------------------------------------------------------------*/ + +static int check_reset_complete ( + struct fusbh200_hcd *fusbh200, + int index, + u32 __iomem *status_reg, + int port_status +) { + if (!(port_status & PORT_CONNECT)) + return port_status; + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + /* with integrated TT, there's nobody to hand it to! */ + fusbh200_dbg (fusbh200, + "Failed to enable port %d on root hub TT\n", + index+1); + return port_status; + } else { + fusbh200_dbg(fusbh200, "port %d reset complete, port enabled\n", + index + 1); + } + + return port_status; +} + +/*-------------------------------------------------------------------------*/ + + +/* build "status change" packet (one or two bytes) from HC registers */ + +static int +fusbh200_hub_status_data (struct usb_hcd *hcd, char *buf) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + u32 temp, status; + u32 mask; + int retval = 1; + unsigned long flags; + + /* init status to no-changes */ + buf [0] = 0; + + /* Inform the core about resumes-in-progress by returning + * a non-zero value even if there are no status changes. + */ + status = fusbh200->resuming_ports; + + mask = PORT_CSC | PORT_PEC; + // PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND + + /* no hub change reports (bit 0) for now (power, ...) */ + + /* port N changes (bit N)? */ + spin_lock_irqsave (&fusbh200->lock, flags); + + temp = fusbh200_readl(fusbh200, &fusbh200->regs->port_status); + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + + if ((temp & mask) != 0 || test_bit(0, &fusbh200->port_c_suspend) + || (fusbh200->reset_done[0] && time_after_eq( + jiffies, fusbh200->reset_done[0]))) { + buf [0] |= 1 << 1; + status = STS_PCD; + } + /* FIXME autosuspend idle root hubs */ + spin_unlock_irqrestore (&fusbh200->lock, flags); + return status ? retval : 0; +} + +/*-------------------------------------------------------------------------*/ + +static void +fusbh200_hub_descriptor ( + struct fusbh200_hcd *fusbh200, + struct usb_hub_descriptor *desc +) { + int ports = HCS_N_PORTS (fusbh200->hcs_params); + u16 temp; + + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = 10; /* fusbh200 1.0, 2.3.9 says 20ms max */ + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); + + temp = 0x0008; /* per-port overcurrent reporting */ + temp |= 0x0002; /* no power switching */ + desc->wHubCharacteristics = cpu_to_le16(temp); +} + +/*-------------------------------------------------------------------------*/ + +static int fusbh200_hub_control ( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + int ports = HCS_N_PORTS (fusbh200->hcs_params); + u32 __iomem *status_reg = &fusbh200->regs->port_status; + u32 temp, temp1, status; + unsigned long flags; + int retval = 0; + unsigned selector; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave (&fusbh200->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = fusbh200_readl(fusbh200, status_reg); + temp &= ~PORT_RWC_BITS; + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_STAT_C_CONNECTION). + */ + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + fusbh200_writel(fusbh200, temp & ~PORT_PE, status_reg); + break; + case USB_PORT_FEAT_C_ENABLE: + fusbh200_writel(fusbh200, temp | PORT_PEC, status_reg); + break; + case USB_PORT_FEAT_SUSPEND: + if (temp & PORT_RESET) + goto error; + if (!(temp & PORT_SUSPEND)) + break; + if ((temp & PORT_PE) == 0) + goto error; + + /* resume signaling for 20 msec */ + fusbh200_writel(fusbh200, temp | PORT_RESUME, status_reg); + fusbh200->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + break; + case USB_PORT_FEAT_C_SUSPEND: + clear_bit(wIndex, &fusbh200->port_c_suspend); + break; + case USB_PORT_FEAT_C_CONNECTION: + fusbh200_writel(fusbh200, temp | PORT_CSC, status_reg); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + fusbh200_writel(fusbh200, temp | BMISR_OVC, &fusbh200->regs->bmisr); + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + fusbh200_readl(fusbh200, &fusbh200->regs->command); /* unblock posted write */ + break; + case GetHubDescriptor: + fusbh200_hub_descriptor (fusbh200, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset (buf, 0, 4); + //cpu_to_le32s ((u32 *) buf); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + status = 0; + temp = fusbh200_readl(fusbh200, status_reg); + + // wPortChange bits + if (temp & PORT_CSC) + status |= USB_PORT_STAT_C_CONNECTION << 16; + if (temp & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + + temp1 = fusbh200_readl(fusbh200, &fusbh200->regs->bmisr); + if (temp1 & BMISR_OVC) + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + + /* whoever resumes must GetPortStatus to complete it!! */ + if (temp & PORT_RESUME) { + + /* Remote Wakeup received? */ + if (!fusbh200->reset_done[wIndex]) { + /* resume signaling for 20 msec */ + fusbh200->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&fusbh200_to_hcd(fusbh200)->rh_timer, + fusbh200->reset_done[wIndex]); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + fusbh200->reset_done[wIndex])) { + clear_bit(wIndex, &fusbh200->suspended_ports); + set_bit(wIndex, &fusbh200->port_c_suspend); + fusbh200->reset_done[wIndex] = 0; + + /* stop resume signaling */ + temp = fusbh200_readl(fusbh200, status_reg); + fusbh200_writel(fusbh200, + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + clear_bit(wIndex, &fusbh200->resuming_ports); + retval = handshake(fusbh200, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + fusbh200_err(fusbh200, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); + } + } + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && time_after_eq(jiffies, + fusbh200->reset_done[wIndex])) { + status |= USB_PORT_STAT_C_RESET << 16; + fusbh200->reset_done [wIndex] = 0; + clear_bit(wIndex, &fusbh200->resuming_ports); + + /* force reset to complete */ + fusbh200_writel(fusbh200, temp & ~(PORT_RWC_BITS | PORT_RESET), + status_reg); + /* REVISIT: some hardware needs 550+ usec to clear + * this bit; seems too long to spin routinely... + */ + retval = handshake(fusbh200, status_reg, + PORT_RESET, 0, 1000); + if (retval != 0) { + fusbh200_err (fusbh200, "port %d reset error %d\n", + wIndex + 1, retval); + goto error; + } + + /* see what we found out */ + temp = check_reset_complete (fusbh200, wIndex, status_reg, + fusbh200_readl(fusbh200, status_reg)); + } + + if (!(temp & (PORT_RESUME|PORT_RESET))) { + fusbh200->reset_done[wIndex] = 0; + clear_bit(wIndex, &fusbh200->resuming_ports); + } + + /* transfer dedicated ports to the companion hc */ + if ((temp & PORT_CONNECT) && + test_bit(wIndex, &fusbh200->companion_ports)) { + temp &= ~PORT_RWC_BITS; + fusbh200_writel(fusbh200, temp, status_reg); + fusbh200_dbg(fusbh200, "port %d --> companion\n", wIndex + 1); + temp = fusbh200_readl(fusbh200, status_reg); + } + + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_CONNECT) { + status |= USB_PORT_STAT_CONNECTION; + status |= fusbh200_port_speed(fusbh200, temp); + } + if (temp & PORT_PE) + status |= USB_PORT_STAT_ENABLE; + + /* maybe the port was unsuspended without our knowledge */ + if (temp & (PORT_SUSPEND|PORT_RESUME)) { + status |= USB_PORT_STAT_SUSPEND; + } else if (test_bit(wIndex, &fusbh200->suspended_ports)) { + clear_bit(wIndex, &fusbh200->suspended_ports); + clear_bit(wIndex, &fusbh200->resuming_ports); + fusbh200->reset_done[wIndex] = 0; + if (temp & PORT_PE) + set_bit(wIndex, &fusbh200->port_c_suspend); + } + + temp1 = fusbh200_readl(fusbh200, &fusbh200->regs->bmisr); + if (temp1 & BMISR_OVC) + status |= USB_PORT_STAT_OVERCURRENT; + if (temp & PORT_RESET) + status |= USB_PORT_STAT_RESET; + if (test_bit(wIndex, &fusbh200->port_c_suspend)) + status |= USB_PORT_STAT_C_SUSPEND << 16; + + if (status & ~0xffff) /* only if wPortChange is interesting */ + dbg_port(fusbh200, "GetStatus", wIndex + 1, temp); + put_unaligned_le32(status, buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + selector = wIndex >> 8; + wIndex &= 0xff; + + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = fusbh200_readl(fusbh200, status_reg); + temp &= ~PORT_RWC_BITS; + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + if ((temp & PORT_PE) == 0 + || (temp & PORT_RESET) != 0) + goto error; + + /* After above check the port must be connected. + * Set appropriate bit thus could put phy into low power + * mode if we have hostpc feature + */ + fusbh200_writel(fusbh200, temp | PORT_SUSPEND, status_reg); + set_bit(wIndex, &fusbh200->suspended_ports); + break; + case USB_PORT_FEAT_RESET: + if (temp & PORT_RESUME) + goto error; + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ + fusbh200_dbg(fusbh200, "port %d reset\n", wIndex + 1); + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + fusbh200->reset_done [wIndex] = jiffies + + msecs_to_jiffies (50); + fusbh200_writel(fusbh200, temp, status_reg); + break; + + /* For downstream facing ports (these): one hub port is put + * into test mode according to USB2 11.24.2.13, then the hub + * must be reset (which for root hub now means rmmod+modprobe, + * or else system reboot). See EHCI 2.3.9 and 4.14 for info + * about the EHCI-specific stuff. + */ + case USB_PORT_FEAT_TEST: + if (!selector || selector > 5) + goto error; + spin_unlock_irqrestore(&fusbh200->lock, flags); + fusbh200_quiesce(fusbh200); + spin_lock_irqsave(&fusbh200->lock, flags); + + /* Put all enabled ports into suspend */ + temp = fusbh200_readl(fusbh200, status_reg) & ~PORT_RWC_BITS; + if (temp & PORT_PE) + fusbh200_writel(fusbh200, temp | PORT_SUSPEND, + status_reg); + + spin_unlock_irqrestore(&fusbh200->lock, flags); + fusbh200_halt(fusbh200); + spin_lock_irqsave(&fusbh200->lock, flags); + + temp = fusbh200_readl(fusbh200, status_reg); + temp |= selector << 16; + fusbh200_writel(fusbh200, temp, status_reg); + break; + + default: + goto error; + } + fusbh200_readl(fusbh200, &fusbh200->regs->command); /* unblock posted writes */ + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore (&fusbh200->lock, flags); + return retval; +} + +static void __maybe_unused fusbh200_relinquish_port(struct usb_hcd *hcd, + int portnum) +{ + return; +} + +static int __maybe_unused fusbh200_port_handed_over(struct usb_hcd *hcd, + int portnum) +{ + return 0; +} +/*-------------------------------------------------------------------------*/ +/* + * There's basically three types of memory: + * - data used only by the HCD ... kmalloc is fine + * - async and periodic schedules, shared by HC and HCD ... these + * need to use dma_pool or dma_alloc_coherent + * - driver buffers, read/written by HC ... single shot DMA mapped + * + * There's also "register" data (e.g. PCI or SOC), which is memory mapped. + * No memory seen by this driver is pageable. + */ + +/*-------------------------------------------------------------------------*/ + +/* Allocate the key transfer structures from the previously allocated pool */ + +static inline void fusbh200_qtd_init(struct fusbh200_hcd *fusbh200, struct fusbh200_qtd *qtd, + dma_addr_t dma) +{ + memset (qtd, 0, sizeof *qtd); + qtd->qtd_dma = dma; + qtd->hw_token = cpu_to_hc32(fusbh200, QTD_STS_HALT); + qtd->hw_next = FUSBH200_LIST_END(fusbh200); + qtd->hw_alt_next = FUSBH200_LIST_END(fusbh200); + INIT_LIST_HEAD (&qtd->qtd_list); +} + +static struct fusbh200_qtd *fusbh200_qtd_alloc (struct fusbh200_hcd *fusbh200, gfp_t flags) +{ + struct fusbh200_qtd *qtd; + dma_addr_t dma; + + qtd = dma_pool_alloc (fusbh200->qtd_pool, flags, &dma); + if (qtd != NULL) { + fusbh200_qtd_init(fusbh200, qtd, dma); + } + return qtd; +} + +static inline void fusbh200_qtd_free (struct fusbh200_hcd *fusbh200, struct fusbh200_qtd *qtd) +{ + dma_pool_free (fusbh200->qtd_pool, qtd, qtd->qtd_dma); +} + + +static void qh_destroy(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + /* clean qtds first, and know this is not linked */ + if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { + fusbh200_dbg (fusbh200, "unused qh not empty!\n"); + BUG (); + } + if (qh->dummy) + fusbh200_qtd_free (fusbh200, qh->dummy); + dma_pool_free(fusbh200->qh_pool, qh->hw, qh->qh_dma); + kfree(qh); +} + +static struct fusbh200_qh *fusbh200_qh_alloc (struct fusbh200_hcd *fusbh200, gfp_t flags) +{ + struct fusbh200_qh *qh; + dma_addr_t dma; + + qh = kzalloc(sizeof *qh, GFP_ATOMIC); + if (!qh) + goto done; + qh->hw = (struct fusbh200_qh_hw *) + dma_pool_alloc(fusbh200->qh_pool, flags, &dma); + if (!qh->hw) + goto fail; + memset(qh->hw, 0, sizeof *qh->hw); + qh->qh_dma = dma; + // INIT_LIST_HEAD (&qh->qh_list); + INIT_LIST_HEAD (&qh->qtd_list); + + /* dummy td enables safe urb queuing */ + qh->dummy = fusbh200_qtd_alloc (fusbh200, flags); + if (qh->dummy == NULL) { + fusbh200_dbg (fusbh200, "no dummy td\n"); + goto fail1; + } +done: + return qh; +fail1: + dma_pool_free(fusbh200->qh_pool, qh->hw, qh->qh_dma); +fail: + kfree(qh); + return NULL; +} + +/*-------------------------------------------------------------------------*/ + +/* The queue heads and transfer descriptors are managed from pools tied + * to each of the "per device" structures. + * This is the initialisation and cleanup code. + */ + +static void fusbh200_mem_cleanup (struct fusbh200_hcd *fusbh200) +{ + if (fusbh200->async) + qh_destroy(fusbh200, fusbh200->async); + fusbh200->async = NULL; + + if (fusbh200->dummy) + qh_destroy(fusbh200, fusbh200->dummy); + fusbh200->dummy = NULL; + + /* DMA consistent memory and pools */ + if (fusbh200->qtd_pool) + dma_pool_destroy (fusbh200->qtd_pool); + fusbh200->qtd_pool = NULL; + + if (fusbh200->qh_pool) { + dma_pool_destroy (fusbh200->qh_pool); + fusbh200->qh_pool = NULL; + } + + if (fusbh200->itd_pool) + dma_pool_destroy (fusbh200->itd_pool); + fusbh200->itd_pool = NULL; + + if (fusbh200->periodic) + dma_free_coherent (fusbh200_to_hcd(fusbh200)->self.controller, + fusbh200->periodic_size * sizeof (u32), + fusbh200->periodic, fusbh200->periodic_dma); + fusbh200->periodic = NULL; + + /* shadow periodic table */ + kfree(fusbh200->pshadow); + fusbh200->pshadow = NULL; +} + +/* remember to add cleanup code (above) if you add anything here */ +static int fusbh200_mem_init (struct fusbh200_hcd *fusbh200, gfp_t flags) +{ + int i; + + /* QTDs for control/bulk/intr transfers */ + fusbh200->qtd_pool = dma_pool_create ("fusbh200_qtd", + fusbh200_to_hcd(fusbh200)->self.controller, + sizeof (struct fusbh200_qtd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fusbh200->qtd_pool) { + goto fail; + } + + /* QHs for control/bulk/intr transfers */ + fusbh200->qh_pool = dma_pool_create ("fusbh200_qh", + fusbh200_to_hcd(fusbh200)->self.controller, + sizeof(struct fusbh200_qh_hw), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fusbh200->qh_pool) { + goto fail; + } + fusbh200->async = fusbh200_qh_alloc (fusbh200, flags); + if (!fusbh200->async) { + goto fail; + } + + /* ITD for high speed ISO transfers */ + fusbh200->itd_pool = dma_pool_create ("fusbh200_itd", + fusbh200_to_hcd(fusbh200)->self.controller, + sizeof (struct fusbh200_itd), + 64 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fusbh200->itd_pool) { + goto fail; + } + + /* Hardware periodic table */ + fusbh200->periodic = (__le32 *) + dma_alloc_coherent (fusbh200_to_hcd(fusbh200)->self.controller, + fusbh200->periodic_size * sizeof(__le32), + &fusbh200->periodic_dma, 0); + if (fusbh200->periodic == NULL) { + goto fail; + } + + for (i = 0; i < fusbh200->periodic_size; i++) + fusbh200->periodic[i] = FUSBH200_LIST_END(fusbh200); + + /* software shadow of hardware table */ + fusbh200->pshadow = kcalloc(fusbh200->periodic_size, sizeof(void *), flags); + if (fusbh200->pshadow != NULL) + return 0; + +fail: + fusbh200_dbg (fusbh200, "couldn't init memory\n"); + fusbh200_mem_cleanup (fusbh200); + return -ENOMEM; +} +/*-------------------------------------------------------------------------*/ +/* + * EHCI hardware queue manipulation ... the core. QH/QTD manipulation. + * + * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" + * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned + * buffers needed for the larger number). We use one QH per endpoint, queue + * multiple urbs (all three types) per endpoint. URBs may need several qtds. + * + * ISO traffic uses "ISO TD" (itd) records, and (along with + * interrupts) needs careful scheduling. Performance improvements can be + * an ongoing challenge. That's in "ehci-sched.c". + * + * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, + * or otherwise through transaction translators (TTs) in USB 2.0 hubs using + * (b) special fields in qh entries or (c) split iso entries. TTs will + * buffer low/full speed data so the host collects it at high speed. + */ + +/*-------------------------------------------------------------------------*/ + +/* fill a qtd, returning how much of the buffer we were able to queue up */ + +static int +qtd_fill(struct fusbh200_hcd *fusbh200, struct fusbh200_qtd *qtd, dma_addr_t buf, + size_t len, int token, int maxpacket) +{ + int i, count; + u64 addr = buf; + + /* one buffer entry per 4K ... first might be short or unaligned */ + qtd->hw_buf[0] = cpu_to_hc32(fusbh200, (u32)addr); + qtd->hw_buf_hi[0] = cpu_to_hc32(fusbh200, (u32)(addr >> 32)); + count = 0x1000 - (buf & 0x0fff); /* rest of that page */ + if (likely (len < count)) /* ... iff needed */ + count = len; + else { + buf += 0x1000; + buf &= ~0x0fff; + + /* per-qtd limit: from 16K to 20K (best alignment) */ + for (i = 1; count < len && i < 5; i++) { + addr = buf; + qtd->hw_buf[i] = cpu_to_hc32(fusbh200, (u32)addr); + qtd->hw_buf_hi[i] = cpu_to_hc32(fusbh200, + (u32)(addr >> 32)); + buf += 0x1000; + if ((count + 0x1000) < len) + count += 0x1000; + else + count = len; + } + + /* short packets may only terminate transfers */ + if (count != len) + count -= (count % maxpacket); + } + qtd->hw_token = cpu_to_hc32(fusbh200, (count << 16) | token); + qtd->length = count; + + return count; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +qh_update (struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh, struct fusbh200_qtd *qtd) +{ + struct fusbh200_qh_hw *hw = qh->hw; + + /* writes to an active overlay are unsafe */ + BUG_ON(qh->qh_state != QH_STATE_IDLE); + + hw->hw_qtd_next = QTD_NEXT(fusbh200, qtd->qtd_dma); + hw->hw_alt_next = FUSBH200_LIST_END(fusbh200); + + /* Except for control endpoints, we make hardware maintain data + * toggle (like OHCI) ... here (re)initialize the toggle in the QH, + * and set the pseudo-toggle in udev. Only usb_clear_halt() will + * ever clear it. + */ + if (!(hw->hw_info1 & cpu_to_hc32(fusbh200, QH_TOGGLE_CTL))) { + unsigned is_out, epnum; + + is_out = qh->is_out; + epnum = (hc32_to_cpup(fusbh200, &hw->hw_info1) >> 8) & 0x0f; + if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { + hw->hw_token &= ~cpu_to_hc32(fusbh200, QTD_TOGGLE); + usb_settoggle (qh->dev, epnum, is_out, 1); + } + } + + hw->hw_token &= cpu_to_hc32(fusbh200, QTD_TOGGLE | QTD_STS_PING); +} + +/* if it weren't for a common silicon quirk (writing the dummy into the qh + * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault + * recovery (including urb dequeue) would need software changes to a QH... + */ +static void +qh_refresh (struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + struct fusbh200_qtd *qtd; + + if (list_empty (&qh->qtd_list)) + qtd = qh->dummy; + else { + qtd = list_entry (qh->qtd_list.next, + struct fusbh200_qtd, qtd_list); + /* + * first qtd may already be partially processed. + * If we come here during unlink, the QH overlay region + * might have reference to the just unlinked qtd. The + * qtd is updated in qh_completions(). Update the QH + * overlay here. + */ + if (cpu_to_hc32(fusbh200, qtd->qtd_dma) == qh->hw->hw_current) { + qh->hw->hw_qtd_next = qtd->hw_next; + qtd = NULL; + } + } + + if (qtd) + qh_update (fusbh200, qh, qtd); +} + +/*-------------------------------------------------------------------------*/ + +static void qh_link_async(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh); + +static void fusbh200_clear_tt_buffer_complete(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200(hcd); + struct fusbh200_qh *qh = ep->hcpriv; + unsigned long flags; + + spin_lock_irqsave(&fusbh200->lock, flags); + qh->clearing_tt = 0; + if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) + && fusbh200->rh_state == FUSBH200_RH_RUNNING) + qh_link_async(fusbh200, qh); + spin_unlock_irqrestore(&fusbh200->lock, flags); +} + +static void fusbh200_clear_tt_buffer(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh, + struct urb *urb, u32 token) +{ + + /* If an async split transaction gets an error or is unlinked, + * the TT buffer may be left in an indeterminate state. We + * have to clear the TT buffer. + * + * Note: this routine is never called for Isochronous transfers. + */ + if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { + struct usb_device *tt = urb->dev->tt->hub; + + dev_dbg(&tt->dev, + "clear tt buffer port %d, a%d ep%d t%08x\n", + urb->dev->ttport, urb->dev->devnum, + usb_pipeendpoint(urb->pipe), token); + + if (urb->dev->tt->hub != + fusbh200_to_hcd(fusbh200)->self.root_hub) { + if (usb_hub_clear_tt_buffer(urb) == 0) + qh->clearing_tt = 1; + } + } +} + +static int qtd_copy_status ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + size_t length, + u32 token +) +{ + int status = -EINPROGRESS; + + /* count IN/OUT bytes, not SETUP (even short packets) */ + if (likely (QTD_PID (token) != 2)) + urb->actual_length += length - QTD_LENGTH (token); + + /* don't modify error codes */ + if (unlikely(urb->unlinked)) + return status; + + /* force cleanup after short read; not always an error */ + if (unlikely (IS_SHORT_READ (token))) + status = -EREMOTEIO; + + /* serious "can't proceed" faults reported by the hardware */ + if (token & QTD_STS_HALT) { + if (token & QTD_STS_BABBLE) { + /* FIXME "must" disable babbling device's port too */ + status = -EOVERFLOW; + /* CERR nonzero + halt --> stall */ + } else if (QTD_CERR(token)) { + status = -EPIPE; + + /* In theory, more than one of the following bits can be set + * since they are sticky and the transaction is retried. + * Which to test first is rather arbitrary. + */ + } else if (token & QTD_STS_MMF) { + /* fs/ls interrupt xfer missed the complete-split */ + status = -EPROTO; + } else if (token & QTD_STS_DBE) { + status = (QTD_PID (token) == 1) /* IN ? */ + ? -ENOSR /* hc couldn't read data */ + : -ECOMM; /* hc couldn't write data */ + } else if (token & QTD_STS_XACT) { + /* timeout, bad CRC, wrong PID, etc */ + fusbh200_dbg(fusbh200, "devpath %s ep%d%s 3strikes\n", + urb->dev->devpath, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out"); + status = -EPROTO; + } else { /* unknown */ + status = -EPROTO; + } + + fusbh200_dbg(fusbh200, + "dev%d ep%d%s qtd token %08x --> status %d\n", + usb_pipedevice (urb->pipe), + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + token, status); + } + + return status; +} + +static void +fusbh200_urb_done(struct fusbh200_hcd *fusbh200, struct urb *urb, int status) +__releases(fusbh200->lock) +__acquires(fusbh200->lock) +{ + if (likely (urb->hcpriv != NULL)) { + struct fusbh200_qh *qh = (struct fusbh200_qh *) urb->hcpriv; + + /* S-mask in a QH means it's an interrupt urb */ + if ((qh->hw->hw_info2 & cpu_to_hc32(fusbh200, QH_SMASK)) != 0) { + + /* ... update hc-wide periodic stats (for usbfs) */ + fusbh200_to_hcd(fusbh200)->self.bandwidth_int_reqs--; + } + } + + if (unlikely(urb->unlinked)) { + COUNT(fusbh200->stats.unlink); + } else { + /* report non-error and short read status as zero */ + if (status == -EINPROGRESS || status == -EREMOTEIO) + status = 0; + COUNT(fusbh200->stats.complete); + } + +#ifdef FUSBH200_URB_TRACE + fusbh200_dbg (fusbh200, + "%s %s urb %p ep%d%s status %d len %d/%d\n", + __func__, urb->dev->devpath, urb, + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + status, + urb->actual_length, urb->transfer_buffer_length); +#endif + + /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(fusbh200_to_hcd(fusbh200), urb); + spin_unlock (&fusbh200->lock); + usb_hcd_giveback_urb(fusbh200_to_hcd(fusbh200), urb, status); + spin_lock (&fusbh200->lock); +} + +static int qh_schedule (struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh); + +/* + * Process and free completed qtds for a qh, returning URBs to drivers. + * Chases up to qh->hw_current. Returns number of completions called, + * indicating how much "real" work we did. + */ +static unsigned +qh_completions (struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + struct fusbh200_qtd *last, *end = qh->dummy; + struct list_head *entry, *tmp; + int last_status; + int stopped; + unsigned count = 0; + u8 state; + struct fusbh200_qh_hw *hw = qh->hw; + + if (unlikely (list_empty (&qh->qtd_list))) + return count; + + /* completions (or tasks on other cpus) must never clobber HALT + * till we've gone through and cleaned everything up, even when + * they add urbs to this qh's queue or mark them for unlinking. + * + * NOTE: unlinking expects to be done in queue order. + * + * It's a bug for qh->qh_state to be anything other than + * QH_STATE_IDLE, unless our caller is scan_async() or + * scan_intr(). + */ + state = qh->qh_state; + qh->qh_state = QH_STATE_COMPLETING; + stopped = (state == QH_STATE_IDLE); + + rescan: + last = NULL; + last_status = -EINPROGRESS; + qh->needs_rescan = 0; + + /* remove de-activated QTDs from front of queue. + * after faults (including short reads), cleanup this urb + * then let the queue advance. + * if queue is stopped, handles unlinks. + */ + list_for_each_safe (entry, tmp, &qh->qtd_list) { + struct fusbh200_qtd *qtd; + struct urb *urb; + u32 token = 0; + + qtd = list_entry (entry, struct fusbh200_qtd, qtd_list); + urb = qtd->urb; + + /* clean up any state from previous QTD ...*/ + if (last) { + if (likely (last->urb != urb)) { + fusbh200_urb_done(fusbh200, last->urb, last_status); + count++; + last_status = -EINPROGRESS; + } + fusbh200_qtd_free (fusbh200, last); + last = NULL; + } + + /* ignore urbs submitted during completions we reported */ + if (qtd == end) + break; + + /* hardware copies qtd out of qh overlay */ + rmb (); + token = hc32_to_cpu(fusbh200, qtd->hw_token); + + /* always clean up qtds the hc de-activated */ + retry_xacterr: + if ((token & QTD_STS_ACTIVE) == 0) { + + /* Report Data Buffer Error: non-fatal but useful */ + if (token & QTD_STS_DBE) + fusbh200_dbg(fusbh200, + "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n", + urb, + usb_endpoint_num(&urb->ep->desc), + usb_endpoint_dir_in(&urb->ep->desc) ? "in" : "out", + urb->transfer_buffer_length, + qtd, + qh); + + /* on STALL, error, and short reads this urb must + * complete and all its qtds must be recycled. + */ + if ((token & QTD_STS_HALT) != 0) { + + /* retry transaction errors until we + * reach the software xacterr limit + */ + if ((token & QTD_STS_XACT) && + QTD_CERR(token) == 0 && + ++qh->xacterrs < QH_XACTERR_MAX && + !urb->unlinked) { + fusbh200_dbg(fusbh200, + "detected XactErr len %zu/%zu retry %d\n", + qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs); + + /* reset the token in the qtd and the + * qh overlay (which still contains + * the qtd) so that we pick up from + * where we left off + */ + token &= ~QTD_STS_HALT; + token |= QTD_STS_ACTIVE | + (FUSBH200_TUNE_CERR << 10); + qtd->hw_token = cpu_to_hc32(fusbh200, + token); + wmb(); + hw->hw_token = cpu_to_hc32(fusbh200, + token); + goto retry_xacterr; + } + stopped = 1; + + /* magic dummy for some short reads; qh won't advance. + * that silicon quirk can kick in with this dummy too. + * + * other short reads won't stop the queue, including + * control transfers (status stage handles that) or + * most other single-qtd reads ... the queue stops if + * URB_SHORT_NOT_OK was set so the driver submitting + * the urbs could clean it up. + */ + } else if (IS_SHORT_READ (token) + && !(qtd->hw_alt_next + & FUSBH200_LIST_END(fusbh200))) { + stopped = 1; + } + + /* stop scanning when we reach qtds the hc is using */ + } else if (likely (!stopped + && fusbh200->rh_state >= FUSBH200_RH_RUNNING)) { + break; + + /* scan the whole queue for unlinks whenever it stops */ + } else { + stopped = 1; + + /* cancel everything if we halt, suspend, etc */ + if (fusbh200->rh_state < FUSBH200_RH_RUNNING) + last_status = -ESHUTDOWN; + + /* this qtd is active; skip it unless a previous qtd + * for its urb faulted, or its urb was canceled. + */ + else if (last_status == -EINPROGRESS && !urb->unlinked) + continue; + + /* qh unlinked; token in overlay may be most current */ + if (state == QH_STATE_IDLE + && cpu_to_hc32(fusbh200, qtd->qtd_dma) + == hw->hw_current) { + token = hc32_to_cpu(fusbh200, hw->hw_token); + + /* An unlink may leave an incomplete + * async transaction in the TT buffer. + * We have to clear it. + */ + fusbh200_clear_tt_buffer(fusbh200, qh, urb, token); + } + } + + /* unless we already know the urb's status, collect qtd status + * and update count of bytes transferred. in common short read + * cases with only one data qtd (including control transfers), + * queue processing won't halt. but with two or more qtds (for + * example, with a 32 KB transfer), when the first qtd gets a + * short read the second must be removed by hand. + */ + if (last_status == -EINPROGRESS) { + last_status = qtd_copy_status(fusbh200, urb, + qtd->length, token); + if (last_status == -EREMOTEIO + && (qtd->hw_alt_next + & FUSBH200_LIST_END(fusbh200))) + last_status = -EINPROGRESS; + + /* As part of low/full-speed endpoint-halt processing + * we must clear the TT buffer (11.17.5). + */ + if (unlikely(last_status != -EINPROGRESS && + last_status != -EREMOTEIO)) { + /* The TT's in some hubs malfunction when they + * receive this request following a STALL (they + * stop sending isochronous packets). Since a + * STALL can't leave the TT buffer in a busy + * state (if you believe Figures 11-48 - 11-51 + * in the USB 2.0 spec), we won't clear the TT + * buffer in this case. Strictly speaking this + * is a violation of the spec. + */ + if (last_status != -EPIPE) + fusbh200_clear_tt_buffer(fusbh200, qh, urb, + token); + } + } + + /* if we're removing something not at the queue head, + * patch the hardware queue pointer. + */ + if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { + last = list_entry (qtd->qtd_list.prev, + struct fusbh200_qtd, qtd_list); + last->hw_next = qtd->hw_next; + } + + /* remove qtd; it's recycled after possible urb completion */ + list_del (&qtd->qtd_list); + last = qtd; + + /* reinit the xacterr counter for the next qtd */ + qh->xacterrs = 0; + } + + /* last urb's completion might still need calling */ + if (likely (last != NULL)) { + fusbh200_urb_done(fusbh200, last->urb, last_status); + count++; + fusbh200_qtd_free (fusbh200, last); + } + + /* Do we need to rescan for URBs dequeued during a giveback? */ + if (unlikely(qh->needs_rescan)) { + /* If the QH is already unlinked, do the rescan now. */ + if (state == QH_STATE_IDLE) + goto rescan; + + /* Otherwise we have to wait until the QH is fully unlinked. + * Our caller will start an unlink if qh->needs_rescan is + * set. But if an unlink has already started, nothing needs + * to be done. + */ + if (state != QH_STATE_LINKED) + qh->needs_rescan = 0; + } + + /* restore original state; caller must unlink or relink */ + qh->qh_state = state; + + /* be sure the hardware's done with the qh before refreshing + * it after fault cleanup, or recovering from silicon wrongly + * overlaying the dummy qtd (which reduces DMA chatter). + */ + if (stopped != 0 || hw->hw_qtd_next == FUSBH200_LIST_END(fusbh200)) { + switch (state) { + case QH_STATE_IDLE: + qh_refresh(fusbh200, qh); + break; + case QH_STATE_LINKED: + /* We won't refresh a QH that's linked (after the HC + * stopped the queue). That avoids a race: + * - HC reads first part of QH; + * - CPU updates that first part and the token; + * - HC reads rest of that QH, including token + * Result: HC gets an inconsistent image, and then + * DMAs to/from the wrong memory (corrupting it). + * + * That should be rare for interrupt transfers, + * except maybe high bandwidth ... + */ + + /* Tell the caller to start an unlink */ + qh->needs_rescan = 1; + break; + /* otherwise, unlink already started */ + } + } + + return count; +} + +/*-------------------------------------------------------------------------*/ + +// high bandwidth multiplier, as encoded in highspeed endpoint descriptors +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) +// ... and packet size, for any kind of endpoint descriptor +#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) + +/* + * reverse of qh_urb_transaction: free a list of TDs. + * used for cleanup after errors, before HC sees an URB's TDs. + */ +static void qtd_list_free ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + struct list_head *qtd_list +) { + struct list_head *entry, *temp; + + list_for_each_safe (entry, temp, qtd_list) { + struct fusbh200_qtd *qtd; + + qtd = list_entry (entry, struct fusbh200_qtd, qtd_list); + list_del (&qtd->qtd_list); + fusbh200_qtd_free (fusbh200, qtd); + } +} + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head * +qh_urb_transaction ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + struct list_head *head, + gfp_t flags +) { + struct fusbh200_qtd *qtd, *qtd_prev; + dma_addr_t buf; + int len, this_sg_len, maxpacket; + int is_input; + u32 token; + int i; + struct scatterlist *sg; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = fusbh200_qtd_alloc (fusbh200, flags); + if (unlikely (!qtd)) + return NULL; + list_add_tail (&qtd->qtd_list, head); + qtd->urb = urb; + + token = QTD_STS_ACTIVE; + token |= (FUSBH200_TUNE_CERR << 10); + /* for split transactions, SplitXState initialized to zero */ + + len = urb->transfer_buffer_length; + is_input = usb_pipein (urb->pipe); + if (usb_pipecontrol (urb->pipe)) { + /* SETUP pid */ + qtd_fill(fusbh200, qtd, urb->setup_dma, + sizeof (struct usb_ctrlrequest), + token | (2 /* "setup" */ << 8), 8); + + /* ... and always at least one more pid */ + token ^= QTD_TOGGLE; + qtd_prev = qtd; + qtd = fusbh200_qtd_alloc (fusbh200, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fusbh200, qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + + /* for zero length DATA stages, STATUS is always IN */ + if (len == 0) + token |= (1 /* "in" */ << 8); + } + + /* + * data transfer stage: buffer setup + */ + i = urb->num_mapped_sgs; + if (len > 0 && i > 0) { + sg = urb->sg; + buf = sg_dma_address(sg); + + /* urb->transfer_buffer_length may be smaller than the + * size of the scatterlist (or vice versa) + */ + this_sg_len = min_t(int, sg_dma_len(sg), len); + } else { + sg = NULL; + buf = urb->transfer_dma; + this_sg_len = len; + } + + if (is_input) + token |= (1 /* "in" */ << 8); + /* else it's already initted to "out" pid (0 << 8) */ + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + this_qtd_len = qtd_fill(fusbh200, qtd, buf, this_sg_len, token, + maxpacket); + this_sg_len -= this_qtd_len; + len -= this_qtd_len; + buf += this_qtd_len; + + /* + * short reads advance to a "magic" dummy instead of the next + * qtd ... that forces the queue to stop, for manual cleanup. + * (this will usually be overridden later.) + */ + if (is_input) + qtd->hw_alt_next = fusbh200->async->hw->hw_alt_next; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= QTD_TOGGLE; + + if (likely(this_sg_len <= 0)) { + if (--i <= 0 || len <= 0) + break; + sg = sg_next(sg); + buf = sg_dma_address(sg); + this_sg_len = min_t(int, sg_dma_len(sg), len); + } + + qtd_prev = qtd; + qtd = fusbh200_qtd_alloc (fusbh200, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fusbh200, qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + } + + /* + * unless the caller requires manual cleanup after short reads, + * have the alt_next mechanism keep the queue running after the + * last data qtd (the only one, for control and most other cases). + */ + if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 + || usb_pipecontrol (urb->pipe))) + qtd->hw_alt_next = FUSBH200_LIST_END(fusbh200); + + /* + * control requests may need a terminating data "status" ack; + * other OUT ones may need a terminating short packet + * (zero length). + */ + if (likely (urb->transfer_buffer_length != 0)) { + int one_more = 0; + + if (usb_pipecontrol (urb->pipe)) { + one_more = 1; + token ^= 0x0100; /* "in" <--> "out" */ + token |= QTD_TOGGLE; /* force DATA1 */ + } else if (usb_pipeout(urb->pipe) + && (urb->transfer_flags & URB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = fusbh200_qtd_alloc (fusbh200, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fusbh200, qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill(fusbh200, qtd, 0, 0, token, 0); + } + } + + /* by default, enable interrupt on urb completion */ + if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT))) + qtd->hw_token |= cpu_to_hc32(fusbh200, QTD_IOC); + return head; + +cleanup: + qtd_list_free (fusbh200, urb, head); + return NULL; +} + +/*-------------------------------------------------------------------------*/ + +// Would be best to create all qh's from config descriptors, +// when each interface/altsetting is established. Unlink +// any previous qh and cancel its urbs first; endpoints are +// implicitly reset then (data toggle too). +// That'd mean updating how usbcore talks to HCDs. (2.7?) + + +/* + * Each QH holds a qtd list; a QH is used for everything except iso. + * + * For interrupt urbs, the scheduler must set the microframe scheduling + * mask(s) each time the QH gets scheduled. For highspeed, that's + * just one microframe in the s-mask. For split interrupt transactions + * there are additional complications: c-mask, maybe FSTNs. + */ +static struct fusbh200_qh * +qh_make ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + gfp_t flags +) { + struct fusbh200_qh *qh = fusbh200_qh_alloc (fusbh200, flags); + u32 info1 = 0, info2 = 0; + int is_input, type; + int maxp = 0; + struct usb_tt *tt = urb->dev->tt; + struct fusbh200_qh_hw *hw; + + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + info1 |= usb_pipeendpoint (urb->pipe) << 8; + info1 |= usb_pipedevice (urb->pipe) << 0; + + is_input = usb_pipein (urb->pipe); + type = usb_pipetype (urb->pipe); + maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input); + + /* 1024 byte maxpacket is a hardware ceiling. High bandwidth + * acts like up to 3KB, but is built from smaller packets. + */ + if (max_packet(maxp) > 1024) { + fusbh200_dbg(fusbh200, "bogus qh maxpacket %d\n", max_packet(maxp)); + goto done; + } + + /* Compute interrupt scheduling parameters just once, and save. + * - allowing for high bandwidth, how many nsec/uframe are used? + * - split transactions need a second CSPLIT uframe; same question + * - splits also need a schedule gap (for full/low speed I/O) + * - qh has a polling interval + * + * For control/bulk requests, the HC or TT handles these. + */ + if (type == PIPE_INTERRUPT) { + qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + is_input, 0, + hb_mult(maxp) * max_packet(maxp))); + qh->start = NO_FRAME; + + if (urb->dev->speed == USB_SPEED_HIGH) { + qh->c_usecs = 0; + qh->gap_uf = 0; + + qh->period = urb->interval >> 3; + if (qh->period == 0 && urb->interval != 1) { + /* NOTE interval 2 or 4 uframes could work. + * But interval 1 scheduling is simpler, and + * includes high bandwidth. + */ + urb->interval = 1; + } else if (qh->period > fusbh200->periodic_size) { + qh->period = fusbh200->periodic_size; + urb->interval = qh->period << 3; + } + } else { + int think_time; + + /* gap is f(FS/LS transfer times) */ + qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, + is_input, 0, maxp) / (125 * 1000); + + /* FIXME this just approximates SPLIT/CSPLIT times */ + if (is_input) { // SPLIT, gap, CSPLIT+DATA + qh->c_usecs = qh->usecs + HS_USECS (0); + qh->usecs = HS_USECS (1); + } else { // SPLIT+DATA, gap, CSPLIT + qh->usecs += HS_USECS (1); + qh->c_usecs = HS_USECS (0); + } + + think_time = tt ? tt->think_time : 0; + qh->tt_usecs = NS_TO_US (think_time + + usb_calc_bus_time (urb->dev->speed, + is_input, 0, max_packet (maxp))); + qh->period = urb->interval; + if (qh->period > fusbh200->periodic_size) { + qh->period = fusbh200->periodic_size; + urb->interval = qh->period; + } + } + } + + /* support for tt scheduling, and access to toggles */ + qh->dev = urb->dev; + + /* using TT? */ + switch (urb->dev->speed) { + case USB_SPEED_LOW: + info1 |= QH_LOW_SPEED; + /* FALL THROUGH */ + + case USB_SPEED_FULL: + /* EPS 0 means "full" */ + if (type != PIPE_INTERRUPT) + info1 |= (FUSBH200_TUNE_RL_TT << 28); + if (type == PIPE_CONTROL) { + info1 |= QH_CONTROL_EP; /* for TT */ + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ + } + info1 |= maxp << 16; + + info2 |= (FUSBH200_TUNE_MULT_TT << 30); + + /* Some Freescale processors have an erratum in which the + * port number in the queue head was 0..N-1 instead of 1..N. + */ + if (fusbh200_has_fsl_portno_bug(fusbh200)) + info2 |= (urb->dev->ttport-1) << 23; + else + info2 |= urb->dev->ttport << 23; + + /* set the address of the TT; for TDI's integrated + * root hub tt, leave it zeroed. + */ + if (tt && tt->hub != fusbh200_to_hcd(fusbh200)->self.root_hub) + info2 |= tt->hub->devnum << 16; + + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ + + break; + + case USB_SPEED_HIGH: /* no TT involved */ + info1 |= QH_HIGH_SPEED; + if (type == PIPE_CONTROL) { + info1 |= (FUSBH200_TUNE_RL_HS << 28); + info1 |= 64 << 16; /* usb2 fixed maxpacket */ + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ + info2 |= (FUSBH200_TUNE_MULT_HS << 30); + } else if (type == PIPE_BULK) { + info1 |= (FUSBH200_TUNE_RL_HS << 28); + /* The USB spec says that high speed bulk endpoints + * always use 512 byte maxpacket. But some device + * vendors decided to ignore that, and MSFT is happy + * to help them do so. So now people expect to use + * such nonconformant devices with Linux too; sigh. + */ + info1 |= max_packet(maxp) << 16; + info2 |= (FUSBH200_TUNE_MULT_HS << 30); + } else { /* PIPE_INTERRUPT */ + info1 |= max_packet (maxp) << 16; + info2 |= hb_mult (maxp) << 30; + } + break; + default: + fusbh200_dbg(fusbh200, "bogus dev %p speed %d\n", urb->dev, + urb->dev->speed); +done: + qh_destroy(fusbh200, qh); + return NULL; + } + + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ + + /* init as live, toggle clear, advance to dummy */ + qh->qh_state = QH_STATE_IDLE; + hw = qh->hw; + hw->hw_info1 = cpu_to_hc32(fusbh200, info1); + hw->hw_info2 = cpu_to_hc32(fusbh200, info2); + qh->is_out = !is_input; + usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); + qh_refresh (fusbh200, qh); + return qh; +} + +/*-------------------------------------------------------------------------*/ + +static void enable_async(struct fusbh200_hcd *fusbh200) +{ + if (fusbh200->async_count++) + return; + + /* Stop waiting to turn off the async schedule */ + fusbh200->enabled_hrtimer_events &= ~BIT(FUSBH200_HRTIMER_DISABLE_ASYNC); + + /* Don't start the schedule until ASS is 0 */ + fusbh200_poll_ASS(fusbh200); + turn_on_io_watchdog(fusbh200); +} + +static void disable_async(struct fusbh200_hcd *fusbh200) +{ + if (--fusbh200->async_count) + return; + + /* The async schedule and async_unlink list are supposed to be empty */ + WARN_ON(fusbh200->async->qh_next.qh || fusbh200->async_unlink); + + /* Don't turn off the schedule until ASS is 1 */ + fusbh200_poll_ASS(fusbh200); +} + +/* move qh (and its qtds) onto async queue; maybe enable queue. */ + +static void qh_link_async (struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + __hc32 dma = QH_NEXT(fusbh200, qh->qh_dma); + struct fusbh200_qh *head; + + /* Don't link a QH if there's a Clear-TT-Buffer pending */ + if (unlikely(qh->clearing_tt)) + return; + + WARN_ON(qh->qh_state != QH_STATE_IDLE); + + /* clear halt and/or toggle; and maybe recover from silicon quirk */ + qh_refresh(fusbh200, qh); + + /* splice right after start */ + head = fusbh200->async; + qh->qh_next = head->qh_next; + qh->hw->hw_next = head->hw->hw_next; + wmb (); + + head->qh_next.qh = qh; + head->hw->hw_next = dma; + + qh->xacterrs = 0; + qh->qh_state = QH_STATE_LINKED; + /* qtd completions reported later by interrupt */ + + enable_async(fusbh200); +} + +/*-------------------------------------------------------------------------*/ + +/* + * For control/bulk/interrupt, return QH with these TDs appended. + * Allocates and initializes the QH if necessary. + * Returns null if it can't allocate a QH it needs to. + * If the QH has TDs (urbs) already, that's great. + */ +static struct fusbh200_qh *qh_append_tds ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + struct list_head *qtd_list, + int epnum, + void **ptr +) +{ + struct fusbh200_qh *qh = NULL; + __hc32 qh_addr_mask = cpu_to_hc32(fusbh200, 0x7f); + + qh = (struct fusbh200_qh *) *ptr; + if (unlikely (qh == NULL)) { + /* can't sleep here, we have fusbh200->lock... */ + qh = qh_make (fusbh200, urb, GFP_ATOMIC); + *ptr = qh; + } + if (likely (qh != NULL)) { + struct fusbh200_qtd *qtd; + + if (unlikely (list_empty (qtd_list))) + qtd = NULL; + else + qtd = list_entry (qtd_list->next, struct fusbh200_qtd, + qtd_list); + + /* control qh may need patching ... */ + if (unlikely (epnum == 0)) { + + /* usb_reset_device() briefly reverts to address 0 */ + if (usb_pipedevice (urb->pipe) == 0) + qh->hw->hw_info1 &= ~qh_addr_mask; + } + + /* just one way to queue requests: swap with the dummy qtd. + * only hc or qh_refresh() ever modify the overlay. + */ + if (likely (qtd != NULL)) { + struct fusbh200_qtd *dummy; + dma_addr_t dma; + __hc32 token; + + /* to avoid racing the HC, use the dummy td instead of + * the first td of our list (becomes new dummy). both + * tds stay deactivated until we're done, when the + * HC is allowed to fetch the old dummy (4.10.2). + */ + token = qtd->hw_token; + qtd->hw_token = HALT_BIT(fusbh200); + + dummy = qh->dummy; + + dma = dummy->qtd_dma; + *dummy = *qtd; + dummy->qtd_dma = dma; + + list_del (&qtd->qtd_list); + list_add (&dummy->qtd_list, qtd_list); + list_splice_tail(qtd_list, &qh->qtd_list); + + fusbh200_qtd_init(fusbh200, qtd, qtd->qtd_dma); + qh->dummy = qtd; + + /* hc must see the new dummy at list end */ + dma = qtd->qtd_dma; + qtd = list_entry (qh->qtd_list.prev, + struct fusbh200_qtd, qtd_list); + qtd->hw_next = QTD_NEXT(fusbh200, dma); + + /* let the hc process these next qtds */ + wmb (); + dummy->hw_token = token; + + urb->hcpriv = qh; + } + } + return qh; +} + +/*-------------------------------------------------------------------------*/ + +static int +submit_async ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + struct list_head *qtd_list, + gfp_t mem_flags +) { + int epnum; + unsigned long flags; + struct fusbh200_qh *qh = NULL; + int rc; + + epnum = urb->ep->desc.bEndpointAddress; + +#ifdef FUSBH200_URB_TRACE + { + struct fusbh200_qtd *qtd; + qtd = list_entry(qtd_list->next, struct fusbh200_qtd, qtd_list); + fusbh200_dbg(fusbh200, + "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", + __func__, urb->dev->devpath, urb, + epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", + urb->transfer_buffer_length, + qtd, urb->ep->hcpriv); + } +#endif + + spin_lock_irqsave (&fusbh200->lock, flags); + if (unlikely(!HCD_HW_ACCESSIBLE(fusbh200_to_hcd(fusbh200)))) { + rc = -ESHUTDOWN; + goto done; + } + rc = usb_hcd_link_urb_to_ep(fusbh200_to_hcd(fusbh200), urb); + if (unlikely(rc)) + goto done; + + qh = qh_append_tds(fusbh200, urb, qtd_list, epnum, &urb->ep->hcpriv); + if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(fusbh200_to_hcd(fusbh200), urb); + rc = -ENOMEM; + goto done; + } + + /* Control/bulk operations through TTs don't need scheduling, + * the HC and TT handle it when the TT has a buffer ready. + */ + if (likely (qh->qh_state == QH_STATE_IDLE)) + qh_link_async(fusbh200, qh); + done: + spin_unlock_irqrestore (&fusbh200->lock, flags); + if (unlikely (qh == NULL)) + qtd_list_free (fusbh200, urb, qtd_list); + return rc; +} + +/*-------------------------------------------------------------------------*/ + +static void single_unlink_async(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + struct fusbh200_qh *prev; + + /* Add to the end of the list of QHs waiting for the next IAAD */ + qh->qh_state = QH_STATE_UNLINK; + if (fusbh200->async_unlink) + fusbh200->async_unlink_last->unlink_next = qh; + else + fusbh200->async_unlink = qh; + fusbh200->async_unlink_last = qh; + + /* Unlink it from the schedule */ + prev = fusbh200->async; + while (prev->qh_next.qh != qh) + prev = prev->qh_next.qh; + + prev->hw->hw_next = qh->hw->hw_next; + prev->qh_next = qh->qh_next; + if (fusbh200->qh_scan_next == qh) + fusbh200->qh_scan_next = qh->qh_next.qh; +} + +static void start_iaa_cycle(struct fusbh200_hcd *fusbh200, bool nested) +{ + /* + * Do nothing if an IAA cycle is already running or + * if one will be started shortly. + */ + if (fusbh200->async_iaa || fusbh200->async_unlinking) + return; + + /* Do all the waiting QHs at once */ + fusbh200->async_iaa = fusbh200->async_unlink; + fusbh200->async_unlink = NULL; + + /* If the controller isn't running, we don't have to wait for it */ + if (unlikely(fusbh200->rh_state < FUSBH200_RH_RUNNING)) { + if (!nested) /* Avoid recursion */ + end_unlink_async(fusbh200); + + /* Otherwise start a new IAA cycle */ + } else if (likely(fusbh200->rh_state == FUSBH200_RH_RUNNING)) { + /* Make sure the unlinks are all visible to the hardware */ + wmb(); + + fusbh200_writel(fusbh200, fusbh200->command | CMD_IAAD, + &fusbh200->regs->command); + fusbh200_readl(fusbh200, &fusbh200->regs->command); + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_IAA_WATCHDOG, true); + } +} + +/* the async qh for the qtds being unlinked are now gone from the HC */ + +static void end_unlink_async(struct fusbh200_hcd *fusbh200) +{ + struct fusbh200_qh *qh; + + /* Process the idle QHs */ + restart: + fusbh200->async_unlinking = true; + while (fusbh200->async_iaa) { + qh = fusbh200->async_iaa; + fusbh200->async_iaa = qh->unlink_next; + qh->unlink_next = NULL; + + qh->qh_state = QH_STATE_IDLE; + qh->qh_next.qh = NULL; + + qh_completions(fusbh200, qh); + if (!list_empty(&qh->qtd_list) && + fusbh200->rh_state == FUSBH200_RH_RUNNING) + qh_link_async(fusbh200, qh); + disable_async(fusbh200); + } + fusbh200->async_unlinking = false; + + /* Start a new IAA cycle if any QHs are waiting for it */ + if (fusbh200->async_unlink) { + start_iaa_cycle(fusbh200, true); + if (unlikely(fusbh200->rh_state < FUSBH200_RH_RUNNING)) + goto restart; + } +} + +static void unlink_empty_async(struct fusbh200_hcd *fusbh200) +{ + struct fusbh200_qh *qh, *next; + bool stopped = (fusbh200->rh_state < FUSBH200_RH_RUNNING); + bool check_unlinks_later = false; + + /* Unlink all the async QHs that have been empty for a timer cycle */ + next = fusbh200->async->qh_next.qh; + while (next) { + qh = next; + next = qh->qh_next.qh; + + if (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED) { + if (!stopped && qh->unlink_cycle == + fusbh200->async_unlink_cycle) + check_unlinks_later = true; + else + single_unlink_async(fusbh200, qh); + } + } + + /* Start a new IAA cycle if any QHs are waiting for it */ + if (fusbh200->async_unlink) + start_iaa_cycle(fusbh200, false); + + /* QHs that haven't been empty for long enough will be handled later */ + if (check_unlinks_later) { + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_ASYNC_UNLINKS, true); + ++fusbh200->async_unlink_cycle; + } +} + +/* makes sure the async qh will become idle */ +/* caller must own fusbh200->lock */ + +static void start_unlink_async(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + /* + * If the QH isn't linked then there's nothing we can do + * unless we were called during a giveback, in which case + * qh_completions() has to deal with it. + */ + if (qh->qh_state != QH_STATE_LINKED) { + if (qh->qh_state == QH_STATE_COMPLETING) + qh->needs_rescan = 1; + return; + } + + single_unlink_async(fusbh200, qh); + start_iaa_cycle(fusbh200, false); +} + +/*-------------------------------------------------------------------------*/ + +static void scan_async (struct fusbh200_hcd *fusbh200) +{ + struct fusbh200_qh *qh; + bool check_unlinks_later = false; + + fusbh200->qh_scan_next = fusbh200->async->qh_next.qh; + while (fusbh200->qh_scan_next) { + qh = fusbh200->qh_scan_next; + fusbh200->qh_scan_next = qh->qh_next.qh; + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; + + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why fusbh200->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then fusbh200->qh_scan_next is adjusted + * in single_unlink_async(). + */ + temp = qh_completions(fusbh200, qh); + if (qh->needs_rescan) { + start_unlink_async(fusbh200, qh); + } else if (list_empty(&qh->qtd_list) + && qh->qh_state == QH_STATE_LINKED) { + qh->unlink_cycle = fusbh200->async_unlink_cycle; + check_unlinks_later = true; + } else if (temp != 0) + goto rescan; + } + } + + /* + * Unlink empty entries, reducing DMA usage as well + * as HCD schedule-scanning costs. Delay for any qh + * we just scanned, there's a not-unusual case that it + * doesn't stay idle for long. + */ + if (check_unlinks_later && fusbh200->rh_state == FUSBH200_RH_RUNNING && + !(fusbh200->enabled_hrtimer_events & + BIT(FUSBH200_HRTIMER_ASYNC_UNLINKS))) { + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_ASYNC_UNLINKS, true); + ++fusbh200->async_unlink_cycle; + } +} +/*-------------------------------------------------------------------------*/ +/* + * EHCI scheduled transaction support: interrupt, iso, split iso + * These are called "periodic" transactions in the EHCI spec. + * + * Note that for interrupt transfers, the QH/QTD manipulation is shared + * with the "asynchronous" transaction support (control/bulk transfers). + * The only real difference is in how interrupt transfers are scheduled. + * + * For ISO, we make an "iso_stream" head to serve the same role as a QH. + * It keeps track of every ITD (or SITD) that's linked, and holds enough + * pre-calculated schedule data to make appending to the queue be quick. + */ + +static int fusbh200_get_frame (struct usb_hcd *hcd); + +/*-------------------------------------------------------------------------*/ + +/* + * periodic_next_shadow - return "next" pointer on shadow list + * @periodic: host pointer to qh/itd + * @tag: hardware tag for type of this record + */ +static union fusbh200_shadow * +periodic_next_shadow(struct fusbh200_hcd *fusbh200, union fusbh200_shadow *periodic, + __hc32 tag) +{ + switch (hc32_to_cpu(fusbh200, tag)) { + case Q_TYPE_QH: + return &periodic->qh->qh_next; + case Q_TYPE_FSTN: + return &periodic->fstn->fstn_next; + default: + return &periodic->itd->itd_next; + } +} + +static __hc32 * +shadow_next_periodic(struct fusbh200_hcd *fusbh200, union fusbh200_shadow *periodic, + __hc32 tag) +{ + switch (hc32_to_cpu(fusbh200, tag)) { + /* our fusbh200_shadow.qh is actually software part */ + case Q_TYPE_QH: + return &periodic->qh->hw->hw_next; + /* others are hw parts */ + default: + return periodic->hw_next; + } +} + +/* caller must hold fusbh200->lock */ +static void periodic_unlink (struct fusbh200_hcd *fusbh200, unsigned frame, void *ptr) +{ + union fusbh200_shadow *prev_p = &fusbh200->pshadow[frame]; + __hc32 *hw_p = &fusbh200->periodic[frame]; + union fusbh200_shadow here = *prev_p; + + /* find predecessor of "ptr"; hw and shadow lists are in sync */ + while (here.ptr && here.ptr != ptr) { + prev_p = periodic_next_shadow(fusbh200, prev_p, + Q_NEXT_TYPE(fusbh200, *hw_p)); + hw_p = shadow_next_periodic(fusbh200, &here, + Q_NEXT_TYPE(fusbh200, *hw_p)); + here = *prev_p; + } + /* an interrupt entry (at list end) could have been shared */ + if (!here.ptr) + return; + + /* update shadow and hardware lists ... the old "next" pointers + * from ptr may still be in use, the caller updates them. + */ + *prev_p = *periodic_next_shadow(fusbh200, &here, + Q_NEXT_TYPE(fusbh200, *hw_p)); + + *hw_p = *shadow_next_periodic(fusbh200, &here, + Q_NEXT_TYPE(fusbh200, *hw_p)); +} + +/* how many of the uframe's 125 usecs are allocated? */ +static unsigned short +periodic_usecs (struct fusbh200_hcd *fusbh200, unsigned frame, unsigned uframe) +{ + __hc32 *hw_p = &fusbh200->periodic [frame]; + union fusbh200_shadow *q = &fusbh200->pshadow [frame]; + unsigned usecs = 0; + struct fusbh200_qh_hw *hw; + + while (q->ptr) { + switch (hc32_to_cpu(fusbh200, Q_NEXT_TYPE(fusbh200, *hw_p))) { + case Q_TYPE_QH: + hw = q->qh->hw; + /* is it in the S-mask? */ + if (hw->hw_info2 & cpu_to_hc32(fusbh200, 1 << uframe)) + usecs += q->qh->usecs; + /* ... or C-mask? */ + if (hw->hw_info2 & cpu_to_hc32(fusbh200, + 1 << (8 + uframe))) + usecs += q->qh->c_usecs; + hw_p = &hw->hw_next; + q = &q->qh->qh_next; + break; + // case Q_TYPE_FSTN: + default: + /* for "save place" FSTNs, count the relevant INTR + * bandwidth from the previous frame + */ + if (q->fstn->hw_prev != FUSBH200_LIST_END(fusbh200)) { + fusbh200_dbg (fusbh200, "ignoring FSTN cost ...\n"); + } + hw_p = &q->fstn->hw_next; + q = &q->fstn->fstn_next; + break; + case Q_TYPE_ITD: + if (q->itd->hw_transaction[uframe]) + usecs += q->itd->stream->usecs; + hw_p = &q->itd->hw_next; + q = &q->itd->itd_next; + break; + } + } + if (usecs > fusbh200->uframe_periodic_max) + fusbh200_err (fusbh200, "uframe %d sched overrun: %d usecs\n", + frame * 8 + uframe, usecs); + return usecs; +} + +/*-------------------------------------------------------------------------*/ + +static int same_tt (struct usb_device *dev1, struct usb_device *dev2) +{ + if (!dev1->tt || !dev2->tt) + return 0; + if (dev1->tt != dev2->tt) + return 0; + if (dev1->tt->multi) + return dev1->ttport == dev2->ttport; + else + return 1; +} + +/* return true iff the device's transaction translator is available + * for a periodic transfer starting at the specified frame, using + * all the uframes in the mask. + */ +static int tt_no_collision ( + struct fusbh200_hcd *fusbh200, + unsigned period, + struct usb_device *dev, + unsigned frame, + u32 uf_mask +) +{ + if (period == 0) /* error */ + return 0; + + /* note bandwidth wastage: split never follows csplit + * (different dev or endpoint) until the next uframe. + * calling convention doesn't make that distinction. + */ + for (; frame < fusbh200->periodic_size; frame += period) { + union fusbh200_shadow here; + __hc32 type; + struct fusbh200_qh_hw *hw; + + here = fusbh200->pshadow [frame]; + type = Q_NEXT_TYPE(fusbh200, fusbh200->periodic [frame]); + while (here.ptr) { + switch (hc32_to_cpu(fusbh200, type)) { + case Q_TYPE_ITD: + type = Q_NEXT_TYPE(fusbh200, here.itd->hw_next); + here = here.itd->itd_next; + continue; + case Q_TYPE_QH: + hw = here.qh->hw; + if (same_tt (dev, here.qh->dev)) { + u32 mask; + + mask = hc32_to_cpu(fusbh200, + hw->hw_info2); + /* "knows" no gap is needed */ + mask |= mask >> 8; + if (mask & uf_mask) + break; + } + type = Q_NEXT_TYPE(fusbh200, hw->hw_next); + here = here.qh->qh_next; + continue; + // case Q_TYPE_FSTN: + default: + fusbh200_dbg (fusbh200, + "periodic frame %d bogus type %d\n", + frame, type); + } + + /* collision or error */ + return 0; + } + } + + /* no collision */ + return 1; +} + +/*-------------------------------------------------------------------------*/ + +static void enable_periodic(struct fusbh200_hcd *fusbh200) +{ + if (fusbh200->periodic_count++) + return; + + /* Stop waiting to turn off the periodic schedule */ + fusbh200->enabled_hrtimer_events &= ~BIT(FUSBH200_HRTIMER_DISABLE_PERIODIC); + + /* Don't start the schedule until PSS is 0 */ + fusbh200_poll_PSS(fusbh200); + turn_on_io_watchdog(fusbh200); +} + +static void disable_periodic(struct fusbh200_hcd *fusbh200) +{ + if (--fusbh200->periodic_count) + return; + + /* Don't turn off the schedule until PSS is 1 */ + fusbh200_poll_PSS(fusbh200); +} + +/*-------------------------------------------------------------------------*/ + +/* periodic schedule slots have iso tds (normal or split) first, then a + * sparse tree for active interrupt transfers. + * + * this just links in a qh; caller guarantees uframe masks are set right. + * no FSTN support (yet; fusbh200 0.96+) + */ +static void qh_link_periodic(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + unsigned i; + unsigned period = qh->period; + + dev_dbg (&qh->dev->dev, + "link qh%d-%04x/%p start %d [%d/%d us]\n", + period, hc32_to_cpup(fusbh200, &qh->hw->hw_info2) + & (QH_CMASK | QH_SMASK), + qh, qh->start, qh->usecs, qh->c_usecs); + + /* high bandwidth, or otherwise every microframe */ + if (period == 0) + period = 1; + + for (i = qh->start; i < fusbh200->periodic_size; i += period) { + union fusbh200_shadow *prev = &fusbh200->pshadow[i]; + __hc32 *hw_p = &fusbh200->periodic[i]; + union fusbh200_shadow here = *prev; + __hc32 type = 0; + + /* skip the iso nodes at list head */ + while (here.ptr) { + type = Q_NEXT_TYPE(fusbh200, *hw_p); + if (type == cpu_to_hc32(fusbh200, Q_TYPE_QH)) + break; + prev = periodic_next_shadow(fusbh200, prev, type); + hw_p = shadow_next_periodic(fusbh200, &here, type); + here = *prev; + } + + /* sorting each branch by period (slow-->fast) + * enables sharing interior tree nodes + */ + while (here.ptr && qh != here.qh) { + if (qh->period > here.qh->period) + break; + prev = &here.qh->qh_next; + hw_p = &here.qh->hw->hw_next; + here = *prev; + } + /* link in this qh, unless some earlier pass did that */ + if (qh != here.qh) { + qh->qh_next = here; + if (here.qh) + qh->hw->hw_next = *hw_p; + wmb (); + prev->qh = qh; + *hw_p = QH_NEXT (fusbh200, qh->qh_dma); + } + } + qh->qh_state = QH_STATE_LINKED; + qh->xacterrs = 0; + + /* update per-qh bandwidth for usbfs */ + fusbh200_to_hcd(fusbh200)->self.bandwidth_allocated += qh->period + ? ((qh->usecs + qh->c_usecs) / qh->period) + : (qh->usecs * 8); + + list_add(&qh->intr_node, &fusbh200->intr_qh_list); + + /* maybe enable periodic schedule processing */ + ++fusbh200->intr_count; + enable_periodic(fusbh200); +} + +static void qh_unlink_periodic(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + unsigned i; + unsigned period; + + /* + * If qh is for a low/full-speed device, simply unlinking it + * could interfere with an ongoing split transaction. To unlink + * it safely would require setting the QH_INACTIVATE bit and + * waiting at least one frame, as described in EHCI 4.12.2.5. + * + * We won't bother with any of this. Instead, we assume that the + * only reason for unlinking an interrupt QH while the current URB + * is still active is to dequeue all the URBs (flush the whole + * endpoint queue). + * + * If rebalancing the periodic schedule is ever implemented, this + * approach will no longer be valid. + */ + + /* high bandwidth, or otherwise part of every microframe */ + if ((period = qh->period) == 0) + period = 1; + + for (i = qh->start; i < fusbh200->periodic_size; i += period) + periodic_unlink (fusbh200, i, qh); + + /* update per-qh bandwidth for usbfs */ + fusbh200_to_hcd(fusbh200)->self.bandwidth_allocated -= qh->period + ? ((qh->usecs + qh->c_usecs) / qh->period) + : (qh->usecs * 8); + + dev_dbg (&qh->dev->dev, + "unlink qh%d-%04x/%p start %d [%d/%d us]\n", + qh->period, + hc32_to_cpup(fusbh200, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), + qh, qh->start, qh->usecs, qh->c_usecs); + + /* qh->qh_next still "live" to HC */ + qh->qh_state = QH_STATE_UNLINK; + qh->qh_next.ptr = NULL; + + if (fusbh200->qh_scan_next == qh) + fusbh200->qh_scan_next = list_entry(qh->intr_node.next, + struct fusbh200_qh, intr_node); + list_del(&qh->intr_node); +} + +static void start_unlink_intr(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + /* If the QH isn't linked then there's nothing we can do + * unless we were called during a giveback, in which case + * qh_completions() has to deal with it. + */ + if (qh->qh_state != QH_STATE_LINKED) { + if (qh->qh_state == QH_STATE_COMPLETING) + qh->needs_rescan = 1; + return; + } + + qh_unlink_periodic (fusbh200, qh); + + /* Make sure the unlinks are visible before starting the timer */ + wmb(); + + /* + * The EHCI spec doesn't say how long it takes the controller to + * stop accessing an unlinked interrupt QH. The timer delay is + * 9 uframes; presumably that will be long enough. + */ + qh->unlink_cycle = fusbh200->intr_unlink_cycle; + + /* New entries go at the end of the intr_unlink list */ + if (fusbh200->intr_unlink) + fusbh200->intr_unlink_last->unlink_next = qh; + else + fusbh200->intr_unlink = qh; + fusbh200->intr_unlink_last = qh; + + if (fusbh200->intr_unlinking) + ; /* Avoid recursive calls */ + else if (fusbh200->rh_state < FUSBH200_RH_RUNNING) + fusbh200_handle_intr_unlinks(fusbh200); + else if (fusbh200->intr_unlink == qh) { + fusbh200_enable_event(fusbh200, FUSBH200_HRTIMER_UNLINK_INTR, true); + ++fusbh200->intr_unlink_cycle; + } +} + +static void end_unlink_intr(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + struct fusbh200_qh_hw *hw = qh->hw; + int rc; + + qh->qh_state = QH_STATE_IDLE; + hw->hw_next = FUSBH200_LIST_END(fusbh200); + + qh_completions(fusbh200, qh); + + /* reschedule QH iff another request is queued */ + if (!list_empty(&qh->qtd_list) && fusbh200->rh_state == FUSBH200_RH_RUNNING) { + rc = qh_schedule(fusbh200, qh); + + /* An error here likely indicates handshake failure + * or no space left in the schedule. Neither fault + * should happen often ... + * + * FIXME kill the now-dysfunctional queued urbs + */ + if (rc != 0) + fusbh200_err(fusbh200, "can't reschedule qh %p, err %d\n", + qh, rc); + } + + /* maybe turn off periodic schedule */ + --fusbh200->intr_count; + disable_periodic(fusbh200); +} + +/*-------------------------------------------------------------------------*/ + +static int check_period ( + struct fusbh200_hcd *fusbh200, + unsigned frame, + unsigned uframe, + unsigned period, + unsigned usecs +) { + int claimed; + + /* complete split running into next frame? + * given FSTN support, we could sometimes check... + */ + if (uframe >= 8) + return 0; + + /* convert "usecs we need" to "max already claimed" */ + usecs = fusbh200->uframe_periodic_max - usecs; + + /* we "know" 2 and 4 uframe intervals were rejected; so + * for period 0, check _every_ microframe in the schedule. + */ + if (unlikely (period == 0)) { + do { + for (uframe = 0; uframe < 7; uframe++) { + claimed = periodic_usecs (fusbh200, frame, uframe); + if (claimed > usecs) + return 0; + } + } while ((frame += 1) < fusbh200->periodic_size); + + /* just check the specified uframe, at that period */ + } else { + do { + claimed = periodic_usecs (fusbh200, frame, uframe); + if (claimed > usecs) + return 0; + } while ((frame += period) < fusbh200->periodic_size); + } + + // success! + return 1; +} + +static int check_intr_schedule ( + struct fusbh200_hcd *fusbh200, + unsigned frame, + unsigned uframe, + const struct fusbh200_qh *qh, + __hc32 *c_maskp +) +{ + int retval = -ENOSPC; + u8 mask = 0; + + if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ + goto done; + + if (!check_period (fusbh200, frame, uframe, qh->period, qh->usecs)) + goto done; + if (!qh->c_usecs) { + retval = 0; + *c_maskp = 0; + goto done; + } + + /* Make sure this tt's buffer is also available for CSPLITs. + * We pessimize a bit; probably the typical full speed case + * doesn't need the second CSPLIT. + * + * NOTE: both SPLIT and CSPLIT could be checked in just + * one smart pass... + */ + mask = 0x03 << (uframe + qh->gap_uf); + *c_maskp = cpu_to_hc32(fusbh200, mask << 8); + + mask |= 1 << uframe; + if (tt_no_collision (fusbh200, qh->period, qh->dev, frame, mask)) { + if (!check_period (fusbh200, frame, uframe + qh->gap_uf + 1, + qh->period, qh->c_usecs)) + goto done; + if (!check_period (fusbh200, frame, uframe + qh->gap_uf, + qh->period, qh->c_usecs)) + goto done; + retval = 0; + } +done: + return retval; +} + +/* "first fit" scheduling policy used the first time through, + * or when the previous schedule slot can't be re-used. + */ +static int qh_schedule(struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) +{ + int status; + unsigned uframe; + __hc32 c_mask; + unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ + struct fusbh200_qh_hw *hw = qh->hw; + + qh_refresh(fusbh200, qh); + hw->hw_next = FUSBH200_LIST_END(fusbh200); + frame = qh->start; + + /* reuse the previous schedule slots, if we can */ + if (frame < qh->period) { + uframe = ffs(hc32_to_cpup(fusbh200, &hw->hw_info2) & QH_SMASK); + status = check_intr_schedule (fusbh200, frame, --uframe, + qh, &c_mask); + } else { + uframe = 0; + c_mask = 0; + status = -ENOSPC; + } + + /* else scan the schedule to find a group of slots such that all + * uframes have enough periodic bandwidth available. + */ + if (status) { + /* "normal" case, uframing flexible except with splits */ + if (qh->period) { + int i; + + for (i = qh->period; status && i > 0; --i) { + frame = ++fusbh200->random_frame % qh->period; + for (uframe = 0; uframe < 8; uframe++) { + status = check_intr_schedule (fusbh200, + frame, uframe, qh, + &c_mask); + if (status == 0) + break; + } + } + + /* qh->period == 0 means every uframe */ + } else { + frame = 0; + status = check_intr_schedule (fusbh200, 0, 0, qh, &c_mask); + } + if (status) + goto done; + qh->start = frame; + + /* reset S-frame and (maybe) C-frame masks */ + hw->hw_info2 &= cpu_to_hc32(fusbh200, ~(QH_CMASK | QH_SMASK)); + hw->hw_info2 |= qh->period + ? cpu_to_hc32(fusbh200, 1 << uframe) + : cpu_to_hc32(fusbh200, QH_SMASK); + hw->hw_info2 |= c_mask; + } else + fusbh200_dbg (fusbh200, "reused qh %p schedule\n", qh); + + /* stuff into the periodic schedule */ + qh_link_periodic(fusbh200, qh); +done: + return status; +} + +static int intr_submit ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + struct list_head *qtd_list, + gfp_t mem_flags +) { + unsigned epnum; + unsigned long flags; + struct fusbh200_qh *qh; + int status; + struct list_head empty; + + /* get endpoint and transfer/schedule data */ + epnum = urb->ep->desc.bEndpointAddress; + + spin_lock_irqsave (&fusbh200->lock, flags); + + if (unlikely(!HCD_HW_ACCESSIBLE(fusbh200_to_hcd(fusbh200)))) { + status = -ESHUTDOWN; + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(fusbh200_to_hcd(fusbh200), urb); + if (unlikely(status)) + goto done_not_linked; + + /* get qh and force any scheduling errors */ + INIT_LIST_HEAD (&empty); + qh = qh_append_tds(fusbh200, urb, &empty, epnum, &urb->ep->hcpriv); + if (qh == NULL) { + status = -ENOMEM; + goto done; + } + if (qh->qh_state == QH_STATE_IDLE) { + if ((status = qh_schedule (fusbh200, qh)) != 0) + goto done; + } + + /* then queue the urb's tds to the qh */ + qh = qh_append_tds(fusbh200, urb, qtd_list, epnum, &urb->ep->hcpriv); + BUG_ON (qh == NULL); + + /* ... update usbfs periodic stats */ + fusbh200_to_hcd(fusbh200)->self.bandwidth_int_reqs++; + +done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(fusbh200_to_hcd(fusbh200), urb); +done_not_linked: + spin_unlock_irqrestore (&fusbh200->lock, flags); + if (status) + qtd_list_free (fusbh200, urb, qtd_list); + + return status; +} + +static void scan_intr(struct fusbh200_hcd *fusbh200) +{ + struct fusbh200_qh *qh; + + list_for_each_entry_safe(qh, fusbh200->qh_scan_next, &fusbh200->intr_qh_list, + intr_node) { + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; + + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why fusbh200->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then fusbh200->qh_scan_next is adjusted + * in qh_unlink_periodic(). + */ + temp = qh_completions(fusbh200, qh); + if (unlikely(qh->needs_rescan || + (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED))) + start_unlink_intr(fusbh200, qh); + else if (temp != 0) + goto rescan; + } + } +} + +/*-------------------------------------------------------------------------*/ + +/* fusbh200_iso_stream ops work with both ITD and SITD */ + +static struct fusbh200_iso_stream * +iso_stream_alloc (gfp_t mem_flags) +{ + struct fusbh200_iso_stream *stream; + + stream = kzalloc(sizeof *stream, mem_flags); + if (likely (stream != NULL)) { + INIT_LIST_HEAD(&stream->td_list); + INIT_LIST_HEAD(&stream->free_list); + stream->next_uframe = -1; + } + return stream; +} + +static void +iso_stream_init ( + struct fusbh200_hcd *fusbh200, + struct fusbh200_iso_stream *stream, + struct usb_device *dev, + int pipe, + unsigned interval +) +{ + u32 buf1; + unsigned epnum, maxp; + int is_input; + long bandwidth; + unsigned multi; + + /* + * this might be a "high bandwidth" highspeed endpoint, + * as encoded in the ep descriptor's wMaxPacket field + */ + epnum = usb_pipeendpoint (pipe); + is_input = usb_pipein (pipe) ? USB_DIR_IN : 0; + maxp = usb_maxpacket(dev, pipe, !is_input); + if (is_input) { + buf1 = (1 << 11); + } else { + buf1 = 0; + } + + maxp = max_packet(maxp); + multi = hb_mult(maxp); + buf1 |= maxp; + maxp *= multi; + + stream->buf0 = cpu_to_hc32(fusbh200, (epnum << 8) | dev->devnum); + stream->buf1 = cpu_to_hc32(fusbh200, buf1); + stream->buf2 = cpu_to_hc32(fusbh200, multi); + + /* usbfs wants to report the average usecs per frame tied up + * when transfers on this endpoint are scheduled ... + */ + if (dev->speed == USB_SPEED_FULL) { + interval <<= 3; + stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed, + is_input, 1, maxp)); + stream->usecs /= 8; + } else { + stream->highspeed = 1; + stream->usecs = HS_USECS_ISO (maxp); + } + bandwidth = stream->usecs * 8; + bandwidth /= interval; + + stream->bandwidth = bandwidth; + stream->udev = dev; + stream->bEndpointAddress = is_input | epnum; + stream->interval = interval; + stream->maxp = maxp; +} + +static struct fusbh200_iso_stream * +iso_stream_find (struct fusbh200_hcd *fusbh200, struct urb *urb) +{ + unsigned epnum; + struct fusbh200_iso_stream *stream; + struct usb_host_endpoint *ep; + unsigned long flags; + + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipein(urb->pipe)) + ep = urb->dev->ep_in[epnum]; + else + ep = urb->dev->ep_out[epnum]; + + spin_lock_irqsave (&fusbh200->lock, flags); + stream = ep->hcpriv; + + if (unlikely (stream == NULL)) { + stream = iso_stream_alloc(GFP_ATOMIC); + if (likely (stream != NULL)) { + ep->hcpriv = stream; + stream->ep = ep; + iso_stream_init(fusbh200, stream, urb->dev, urb->pipe, + urb->interval); + } + + /* if dev->ep [epnum] is a QH, hw is set */ + } else if (unlikely (stream->hw != NULL)) { + fusbh200_dbg (fusbh200, "dev %s ep%d%s, not iso??\n", + urb->dev->devpath, epnum, + usb_pipein(urb->pipe) ? "in" : "out"); + stream = NULL; + } + + spin_unlock_irqrestore (&fusbh200->lock, flags); + return stream; +} + +/*-------------------------------------------------------------------------*/ + +/* fusbh200_iso_sched ops can be ITD-only or SITD-only */ + +static struct fusbh200_iso_sched * +iso_sched_alloc (unsigned packets, gfp_t mem_flags) +{ + struct fusbh200_iso_sched *iso_sched; + int size = sizeof *iso_sched; + + size += packets * sizeof (struct fusbh200_iso_packet); + iso_sched = kzalloc(size, mem_flags); + if (likely (iso_sched != NULL)) { + INIT_LIST_HEAD (&iso_sched->td_list); + } + return iso_sched; +} + +static inline void +itd_sched_init( + struct fusbh200_hcd *fusbh200, + struct fusbh200_iso_sched *iso_sched, + struct fusbh200_iso_stream *stream, + struct urb *urb +) +{ + unsigned i; + dma_addr_t dma = urb->transfer_dma; + + /* how many uframes are needed for these transfers */ + iso_sched->span = urb->number_of_packets * stream->interval; + + /* figure out per-uframe itd fields that we'll need later + * when we fit new itds into the schedule. + */ + for (i = 0; i < urb->number_of_packets; i++) { + struct fusbh200_iso_packet *uframe = &iso_sched->packet [i]; + unsigned length; + dma_addr_t buf; + u32 trans; + + length = urb->iso_frame_desc [i].length; + buf = dma + urb->iso_frame_desc [i].offset; + + trans = FUSBH200_ISOC_ACTIVE; + trans |= buf & 0x0fff; + if (unlikely (((i + 1) == urb->number_of_packets)) + && !(urb->transfer_flags & URB_NO_INTERRUPT)) + trans |= FUSBH200_ITD_IOC; + trans |= length << 16; + uframe->transaction = cpu_to_hc32(fusbh200, trans); + + /* might need to cross a buffer page within a uframe */ + uframe->bufp = (buf & ~(u64)0x0fff); + buf += length; + if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff)))) + uframe->cross = 1; + } +} + +static void +iso_sched_free ( + struct fusbh200_iso_stream *stream, + struct fusbh200_iso_sched *iso_sched +) +{ + if (!iso_sched) + return; + // caller must hold fusbh200->lock! + list_splice (&iso_sched->td_list, &stream->free_list); + kfree (iso_sched); +} + +static int +itd_urb_transaction ( + struct fusbh200_iso_stream *stream, + struct fusbh200_hcd *fusbh200, + struct urb *urb, + gfp_t mem_flags +) +{ + struct fusbh200_itd *itd; + dma_addr_t itd_dma; + int i; + unsigned num_itds; + struct fusbh200_iso_sched *sched; + unsigned long flags; + + sched = iso_sched_alloc (urb->number_of_packets, mem_flags); + if (unlikely (sched == NULL)) + return -ENOMEM; + + itd_sched_init(fusbh200, sched, stream, urb); + + if (urb->interval < 8) + num_itds = 1 + (sched->span + 7) / 8; + else + num_itds = urb->number_of_packets; + + /* allocate/init ITDs */ + spin_lock_irqsave (&fusbh200->lock, flags); + for (i = 0; i < num_itds; i++) { + + /* + * Use iTDs from the free list, but not iTDs that may + * still be in use by the hardware. + */ + if (likely(!list_empty(&stream->free_list))) { + itd = list_first_entry(&stream->free_list, + struct fusbh200_itd, itd_list); + if (itd->frame == fusbh200->now_frame) + goto alloc_itd; + list_del (&itd->itd_list); + itd_dma = itd->itd_dma; + } else { + alloc_itd: + spin_unlock_irqrestore (&fusbh200->lock, flags); + itd = dma_pool_alloc (fusbh200->itd_pool, mem_flags, + &itd_dma); + spin_lock_irqsave (&fusbh200->lock, flags); + if (!itd) { + iso_sched_free(stream, sched); + spin_unlock_irqrestore(&fusbh200->lock, flags); + return -ENOMEM; + } + } + + memset (itd, 0, sizeof *itd); + itd->itd_dma = itd_dma; + list_add (&itd->itd_list, &sched->td_list); + } + spin_unlock_irqrestore (&fusbh200->lock, flags); + + /* temporarily store schedule info in hcpriv */ + urb->hcpriv = sched; + urb->error_count = 0; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static inline int +itd_slot_ok ( + struct fusbh200_hcd *fusbh200, + u32 mod, + u32 uframe, + u8 usecs, + u32 period +) +{ + uframe %= period; + do { + /* can't commit more than uframe_periodic_max usec */ + if (periodic_usecs (fusbh200, uframe >> 3, uframe & 0x7) + > (fusbh200->uframe_periodic_max - usecs)) + return 0; + + /* we know urb->interval is 2^N uframes */ + uframe += period; + } while (uframe < mod); + return 1; +} + +/* + * This scheduler plans almost as far into the future as it has actual + * periodic schedule slots. (Affected by TUNE_FLS, which defaults to + * "as small as possible" to be cache-friendlier.) That limits the size + * transfers you can stream reliably; avoid more than 64 msec per urb. + * Also avoid queue depths of less than fusbh200's worst irq latency (affected + * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter, + * and other factors); or more than about 230 msec total (for portability, + * given FUSBH200_TUNE_FLS and the slop). Or, write a smarter scheduler! + */ + +#define SCHEDULE_SLOP 80 /* microframes */ + +static int +iso_stream_schedule ( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + struct fusbh200_iso_stream *stream +) +{ + u32 now, next, start, period, span; + int status; + unsigned mod = fusbh200->periodic_size << 3; + struct fusbh200_iso_sched *sched = urb->hcpriv; + + period = urb->interval; + span = sched->span; + + if (span > mod - SCHEDULE_SLOP) { + fusbh200_dbg (fusbh200, "iso request %p too long\n", urb); + status = -EFBIG; + goto fail; + } + + now = fusbh200_read_frame_index(fusbh200) & (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. + */ + 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 && fusbh200->fs_i_thresh) + next = now + fusbh200->i_thresh; + else + next = now; + + /* 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. + */ + 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) { + fusbh200_dbg(fusbh200, "request %p would overflow (%d+%d >= %d)\n", + urb, start - now - period, period, + mod); + status = -EFBIG; + goto fail; + } + } + + /* need to schedule; when's the next (u)frame we could start? + * this is bigger than fusbh200->i_thresh allows; scheduling itself + * isn't free, the slop 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 */ + + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; + /* check schedule: enough space? */ + if (itd_slot_ok(fusbh200, mod, start, + stream->usecs, period)) + done = 1; + } while (start > next && !done); + + /* no room in the schedule */ + if (!done) { + fusbh200_dbg(fusbh200, "iso resched full %p (now %d max %d)\n", + urb, now, now + mod); + status = -ENOSPC; + goto fail; + } + } + + /* Tried to schedule too far into the future? */ + if (unlikely(start - now + span - period + >= mod - 2 * SCHEDULE_SLOP)) { + fusbh200_dbg(fusbh200, "request %p would overflow (%d+%d >= %d)\n", + urb, start - now, span - period, + mod - 2 * SCHEDULE_SLOP); + status = -EFBIG; + goto fail; + } + + stream->next_uframe = start & (mod - 1); + + /* report high speed start in uframes; full speed, in frames */ + urb->start_frame = stream->next_uframe; + if (!stream->highspeed) + urb->start_frame >>= 3; + + /* Make sure scan_isoc() sees these */ + if (fusbh200->isoc_count == 0) + fusbh200->next_frame = now >> 3; + return 0; + + fail: + iso_sched_free(stream, sched); + urb->hcpriv = NULL; + return status; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +itd_init(struct fusbh200_hcd *fusbh200, struct fusbh200_iso_stream *stream, + struct fusbh200_itd *itd) +{ + int i; + + /* it's been recently zeroed */ + itd->hw_next = FUSBH200_LIST_END(fusbh200); + itd->hw_bufp [0] = stream->buf0; + itd->hw_bufp [1] = stream->buf1; + itd->hw_bufp [2] = stream->buf2; + + for (i = 0; i < 8; i++) + itd->index[i] = -1; + + /* All other fields are filled when scheduling */ +} + +static inline void +itd_patch( + struct fusbh200_hcd *fusbh200, + struct fusbh200_itd *itd, + struct fusbh200_iso_sched *iso_sched, + unsigned index, + u16 uframe +) +{ + struct fusbh200_iso_packet *uf = &iso_sched->packet [index]; + unsigned pg = itd->pg; + + // BUG_ON (pg == 6 && uf->cross); + + uframe &= 0x07; + itd->index [uframe] = index; + + itd->hw_transaction[uframe] = uf->transaction; + itd->hw_transaction[uframe] |= cpu_to_hc32(fusbh200, pg << 12); + itd->hw_bufp[pg] |= cpu_to_hc32(fusbh200, uf->bufp & ~(u32)0); + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fusbh200, (u32)(uf->bufp >> 32)); + + /* iso_frame_desc[].offset must be strictly increasing */ + if (unlikely (uf->cross)) { + u64 bufp = uf->bufp + 4096; + + itd->pg = ++pg; + itd->hw_bufp[pg] |= cpu_to_hc32(fusbh200, bufp & ~(u32)0); + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fusbh200, (u32)(bufp >> 32)); + } +} + +static inline void +itd_link (struct fusbh200_hcd *fusbh200, unsigned frame, struct fusbh200_itd *itd) +{ + union fusbh200_shadow *prev = &fusbh200->pshadow[frame]; + __hc32 *hw_p = &fusbh200->periodic[frame]; + union fusbh200_shadow here = *prev; + __hc32 type = 0; + + /* skip any iso nodes which might belong to previous microframes */ + while (here.ptr) { + type = Q_NEXT_TYPE(fusbh200, *hw_p); + if (type == cpu_to_hc32(fusbh200, Q_TYPE_QH)) + break; + prev = periodic_next_shadow(fusbh200, prev, type); + hw_p = shadow_next_periodic(fusbh200, &here, type); + here = *prev; + } + + itd->itd_next = here; + itd->hw_next = *hw_p; + prev->itd = itd; + itd->frame = frame; + wmb (); + *hw_p = cpu_to_hc32(fusbh200, itd->itd_dma | Q_TYPE_ITD); +} + +/* fit urb's itds into the selected schedule slot; activate as needed */ +static void itd_link_urb( + struct fusbh200_hcd *fusbh200, + struct urb *urb, + unsigned mod, + struct fusbh200_iso_stream *stream +) +{ + int packet; + unsigned next_uframe, uframe, frame; + struct fusbh200_iso_sched *iso_sched = urb->hcpriv; + struct fusbh200_itd *itd; + + next_uframe = stream->next_uframe & (mod - 1); + + if (unlikely (list_empty(&stream->td_list))) { + fusbh200_to_hcd(fusbh200)->self.bandwidth_allocated + += stream->bandwidth; + fusbh200_dbg(fusbh200, + "schedule devp %s ep%d%s-iso period %d start %d.%d\n", + urb->dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + urb->interval, + next_uframe >> 3, next_uframe & 0x7); + } + + /* fill iTDs uframe by uframe */ + for (packet = 0, itd = NULL; packet < urb->number_of_packets; ) { + if (itd == NULL) { + /* ASSERT: we have all necessary itds */ + // BUG_ON (list_empty (&iso_sched->td_list)); + + /* ASSERT: no itds for this endpoint in this uframe */ + + itd = list_entry (iso_sched->td_list.next, + struct fusbh200_itd, itd_list); + list_move_tail (&itd->itd_list, &stream->td_list); + itd->stream = stream; + itd->urb = urb; + itd_init (fusbh200, stream, itd); + } + + uframe = next_uframe & 0x07; + frame = next_uframe >> 3; + + itd_patch(fusbh200, itd, iso_sched, packet, uframe); + + next_uframe += stream->interval; + next_uframe &= mod - 1; + packet++; + + /* link completed itds into the schedule */ + if (((next_uframe >> 3) != frame) + || packet == urb->number_of_packets) { + itd_link(fusbh200, frame & (fusbh200->periodic_size - 1), itd); + itd = NULL; + } + } + stream->next_uframe = next_uframe; + + /* don't need that schedule data any more */ + iso_sched_free (stream, iso_sched); + urb->hcpriv = NULL; + + ++fusbh200->isoc_count; + enable_periodic(fusbh200); +} + +#define ISO_ERRS (FUSBH200_ISOC_BUF_ERR | FUSBH200_ISOC_BABBLE | FUSBH200_ISOC_XACTERR) + +/* Process and recycle a completed ITD. Return true iff its urb completed, + * and hence its completion callback probably added things to the hardware + * schedule. + * + * Note that we carefully avoid recycling this descriptor until after any + * completion callback runs, so that it won't be reused quickly. That is, + * assuming (a) no more than two urbs per frame on this endpoint, and also + * (b) only this endpoint's completions submit URBs. It seems some silicon + * corrupts things if you reuse completed descriptors very quickly... + */ +static bool itd_complete(struct fusbh200_hcd *fusbh200, struct fusbh200_itd *itd) +{ + struct urb *urb = itd->urb; + struct usb_iso_packet_descriptor *desc; + u32 t; + unsigned uframe; + int urb_index = -1; + struct fusbh200_iso_stream *stream = itd->stream; + struct usb_device *dev; + bool retval = false; + + /* for each uframe with a packet */ + for (uframe = 0; uframe < 8; uframe++) { + if (likely (itd->index[uframe] == -1)) + continue; + urb_index = itd->index[uframe]; + desc = &urb->iso_frame_desc [urb_index]; + + t = hc32_to_cpup(fusbh200, &itd->hw_transaction [uframe]); + itd->hw_transaction [uframe] = 0; + + /* report transfer status */ + if (unlikely (t & ISO_ERRS)) { + urb->error_count++; + if (t & FUSBH200_ISOC_BUF_ERR) + desc->status = usb_pipein (urb->pipe) + ? -ENOSR /* hc couldn't read */ + : -ECOMM; /* hc couldn't write */ + else if (t & FUSBH200_ISOC_BABBLE) + desc->status = -EOVERFLOW; + else /* (t & FUSBH200_ISOC_XACTERR) */ + desc->status = -EPROTO; + + /* HC need not update length with this error */ + if (!(t & FUSBH200_ISOC_BABBLE)) { + desc->actual_length = fusbh200_itdlen(urb, desc, t); + urb->actual_length += desc->actual_length; + } + } else if (likely ((t & FUSBH200_ISOC_ACTIVE) == 0)) { + desc->status = 0; + desc->actual_length = fusbh200_itdlen(urb, desc, t); + urb->actual_length += desc->actual_length; + } else { + /* URB was too late */ + desc->status = -EXDEV; + } + } + + /* handle completion now? */ + if (likely ((urb_index + 1) != urb->number_of_packets)) + goto done; + + /* ASSERT: it's really the last itd for this urb + list_for_each_entry (itd, &stream->td_list, itd_list) + BUG_ON (itd->urb == urb); + */ + + /* give urb back to the driver; completion often (re)submits */ + dev = urb->dev; + fusbh200_urb_done(fusbh200, urb, 0); + retval = true; + urb = NULL; + + --fusbh200->isoc_count; + disable_periodic(fusbh200); + + if (unlikely(list_is_singular(&stream->td_list))) { + fusbh200_to_hcd(fusbh200)->self.bandwidth_allocated + -= stream->bandwidth; + fusbh200_dbg(fusbh200, + "deschedule devp %s ep%d%s-iso\n", + dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); + } + +done: + itd->urb = NULL; + + /* Add to the end of the free list for later reuse */ + list_move_tail(&itd->itd_list, &stream->free_list); + + /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */ + if (list_empty(&stream->td_list)) { + list_splice_tail_init(&stream->free_list, + &fusbh200->cached_itd_list); + start_free_itds(fusbh200); + } + + return retval; +} + +/*-------------------------------------------------------------------------*/ + +static int itd_submit (struct fusbh200_hcd *fusbh200, struct urb *urb, + gfp_t mem_flags) +{ + int status = -EINVAL; + unsigned long flags; + struct fusbh200_iso_stream *stream; + + /* Get iso_stream head */ + stream = iso_stream_find (fusbh200, urb); + if (unlikely (stream == NULL)) { + fusbh200_dbg (fusbh200, "can't get iso stream\n"); + return -ENOMEM; + } + if (unlikely (urb->interval != stream->interval && + fusbh200_port_speed(fusbh200, 0) == USB_PORT_STAT_HIGH_SPEED)) { + fusbh200_dbg (fusbh200, "can't change iso interval %d --> %d\n", + stream->interval, urb->interval); + goto done; + } + +#ifdef FUSBH200_URB_TRACE + fusbh200_dbg (fusbh200, + "%s %s urb %p ep%d%s len %d, %d pkts %d uframes [%p]\n", + __func__, urb->dev->devpath, urb, + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + urb->transfer_buffer_length, + urb->number_of_packets, urb->interval, + stream); +#endif + + /* allocate ITDs w/o locking anything */ + status = itd_urb_transaction (stream, fusbh200, urb, mem_flags); + if (unlikely (status < 0)) { + fusbh200_dbg (fusbh200, "can't init itds\n"); + goto done; + } + + /* schedule ... need to lock */ + spin_lock_irqsave (&fusbh200->lock, flags); + if (unlikely(!HCD_HW_ACCESSIBLE(fusbh200_to_hcd(fusbh200)))) { + status = -ESHUTDOWN; + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(fusbh200_to_hcd(fusbh200), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(fusbh200, urb, stream); + if (likely (status == 0)) + itd_link_urb (fusbh200, urb, fusbh200->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(fusbh200_to_hcd(fusbh200), urb); + done_not_linked: + spin_unlock_irqrestore (&fusbh200->lock, flags); + done: + return status; +} + +/*-------------------------------------------------------------------------*/ + +static void scan_isoc(struct fusbh200_hcd *fusbh200) +{ + unsigned uf, now_frame, frame; + unsigned fmask = fusbh200->periodic_size - 1; + bool modified, live; + + /* + * When running, scan from last scan point up to "now" + * else clean up by scanning everything that's left. + * Touches as few pages as possible: cache-friendly. + */ + if (fusbh200->rh_state >= FUSBH200_RH_RUNNING) { + uf = fusbh200_read_frame_index(fusbh200); + now_frame = (uf >> 3) & fmask; + live = true; + } else { + now_frame = (fusbh200->next_frame - 1) & fmask; + live = false; + } + fusbh200->now_frame = now_frame; + + frame = fusbh200->next_frame; + for (;;) { + union fusbh200_shadow q, *q_p; + __hc32 type, *hw_p; + +restart: + /* scan each element in frame's queue for completions */ + q_p = &fusbh200->pshadow [frame]; + hw_p = &fusbh200->periodic [frame]; + q.ptr = q_p->ptr; + type = Q_NEXT_TYPE(fusbh200, *hw_p); + modified = false; + + while (q.ptr != NULL) { + switch (hc32_to_cpu(fusbh200, type)) { + case Q_TYPE_ITD: + /* If this ITD is still active, leave it for + * later processing ... check the next entry. + * No need to check for activity unless the + * frame is current. + */ + if (frame == now_frame && live) { + rmb(); + for (uf = 0; uf < 8; uf++) { + if (q.itd->hw_transaction[uf] & + ITD_ACTIVE(fusbh200)) + break; + } + if (uf < 8) { + q_p = &q.itd->itd_next; + hw_p = &q.itd->hw_next; + type = Q_NEXT_TYPE(fusbh200, + q.itd->hw_next); + q = *q_p; + break; + } + } + + /* Take finished ITDs out of the schedule + * and process them: recycle, maybe report + * URB completion. HC won't cache the + * pointer for much longer, if at all. + */ + *q_p = q.itd->itd_next; + *hw_p = q.itd->hw_next; + type = Q_NEXT_TYPE(fusbh200, q.itd->hw_next); + wmb(); + modified = itd_complete (fusbh200, q.itd); + q = *q_p; + break; + default: + fusbh200_dbg(fusbh200, "corrupt type %d frame %d shadow %p\n", + type, frame, q.ptr); + // BUG (); + /* FALL THROUGH */ + case Q_TYPE_QH: + case Q_TYPE_FSTN: + /* End of the iTDs and siTDs */ + q.ptr = NULL; + break; + } + + /* assume completion callbacks modify the queue */ + if (unlikely(modified && fusbh200->isoc_count > 0)) + goto restart; + } + + /* Stop when we have reached the current frame */ + if (frame == now_frame) + break; + frame = (frame + 1) & fmask; + } + fusbh200->next_frame = now_frame; +} +/*-------------------------------------------------------------------------*/ +/* + * Display / Set uframe_periodic_max + */ +static ssize_t show_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fusbh200_hcd *fusbh200; + int n; + + fusbh200 = hcd_to_fusbh200(bus_to_hcd(dev_get_drvdata(dev))); + n = scnprintf(buf, PAGE_SIZE, "%d\n", fusbh200->uframe_periodic_max); + return n; +} + + +static ssize_t store_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fusbh200_hcd *fusbh200; + unsigned uframe_periodic_max; + unsigned frame, uframe; + unsigned short allocated_max; + unsigned long flags; + ssize_t ret; + + fusbh200 = hcd_to_fusbh200(bus_to_hcd(dev_get_drvdata(dev))); + if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) + return -EINVAL; + + if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { + fusbh200_info(fusbh200, "rejecting invalid request for " + "uframe_periodic_max=%u\n", uframe_periodic_max); + return -EINVAL; + } + + ret = -EINVAL; + + /* + * lock, so that our checking does not race with possible periodic + * bandwidth allocation through submitting new urbs. + */ + spin_lock_irqsave (&fusbh200->lock, flags); + + /* + * for request to decrease max periodic bandwidth, we have to check + * every microframe in the schedule to see whether the decrease is + * possible. + */ + if (uframe_periodic_max < fusbh200->uframe_periodic_max) { + allocated_max = 0; + + for (frame = 0; frame < fusbh200->periodic_size; ++frame) + for (uframe = 0; uframe < 7; ++uframe) + allocated_max = max(allocated_max, + periodic_usecs (fusbh200, frame, uframe)); + + if (allocated_max > uframe_periodic_max) { + fusbh200_info(fusbh200, + "cannot decrease uframe_periodic_max becase " + "periodic bandwidth is already allocated " + "(%u > %u)\n", + allocated_max, uframe_periodic_max); + goto out_unlock; + } + } + + /* increasing is always ok */ + + fusbh200_info(fusbh200, "setting max periodic bandwidth to %u%% " + "(== %u usec/uframe)\n", + 100*uframe_periodic_max/125, uframe_periodic_max); + + if (uframe_periodic_max != 100) + fusbh200_warn(fusbh200, "max periodic bandwidth set is non-standard\n"); + + fusbh200->uframe_periodic_max = uframe_periodic_max; + ret = count; + +out_unlock: + spin_unlock_irqrestore (&fusbh200->lock, flags); + return ret; +} +static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max); + + +static inline int create_sysfs_files(struct fusbh200_hcd *fusbh200) +{ + struct device *controller = fusbh200_to_hcd(fusbh200)->self.controller; + int i = 0; + + if (i) + goto out; + + i = device_create_file(controller, &dev_attr_uframe_periodic_max); +out: + return i; +} + +static inline void remove_sysfs_files(struct fusbh200_hcd *fusbh200) +{ + struct device *controller = fusbh200_to_hcd(fusbh200)->self.controller; + + device_remove_file(controller, &dev_attr_uframe_periodic_max); +} +/*-------------------------------------------------------------------------*/ + +/* On some systems, leaving remote wakeup enabled prevents system shutdown. + * The firmware seems to think that powering off is a wakeup event! + * This routine turns off remote wakeup and everything else, on all ports. + */ +static void fusbh200_turn_off_all_ports(struct fusbh200_hcd *fusbh200) +{ + u32 __iomem *status_reg = &fusbh200->regs->port_status; + + fusbh200_writel(fusbh200, PORT_RWC_BITS, status_reg); +} + +/* + * Halt HC, turn off all ports, and let the BIOS use the companion controllers. + * Must be called with interrupts enabled and the lock not held. + */ +static void fusbh200_silence_controller(struct fusbh200_hcd *fusbh200) +{ + fusbh200_halt(fusbh200); + + spin_lock_irq(&fusbh200->lock); + fusbh200->rh_state = FUSBH200_RH_HALTED; + fusbh200_turn_off_all_ports(fusbh200); + spin_unlock_irq(&fusbh200->lock); +} + +/* fusbh200_shutdown kick in for silicon on any bus (not just pci, etc). + * This forcibly disables dma and IRQs, helping kexec and other cases + * where the next system software may expect clean state. + */ +static void fusbh200_shutdown(struct usb_hcd *hcd) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200(hcd); + + spin_lock_irq(&fusbh200->lock); + fusbh200->shutdown = true; + fusbh200->rh_state = FUSBH200_RH_STOPPING; + fusbh200->enabled_hrtimer_events = 0; + spin_unlock_irq(&fusbh200->lock); + + fusbh200_silence_controller(fusbh200); + + hrtimer_cancel(&fusbh200->hrtimer); +} + +/*-------------------------------------------------------------------------*/ + +/* + * fusbh200_work is called from some interrupts, timers, and so on. + * it calls driver completion functions, after dropping fusbh200->lock. + */ +static void fusbh200_work (struct fusbh200_hcd *fusbh200) +{ + /* another CPU may drop fusbh200->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (fusbh200->scanning) { + fusbh200->need_rescan = true; + return; + } + fusbh200->scanning = true; + + rescan: + fusbh200->need_rescan = false; + if (fusbh200->async_count) + scan_async(fusbh200); + if (fusbh200->intr_count > 0) + scan_intr(fusbh200); + if (fusbh200->isoc_count > 0) + scan_isoc(fusbh200); + if (fusbh200->need_rescan) + goto rescan; + fusbh200->scanning = false; + + /* the IO watchdog guards against hardware or driver bugs that + * misplace IRQs, and should let us run completely without IRQs. + * such lossage has been observed on both VT6202 and VT8235. + */ + turn_on_io_watchdog(fusbh200); +} + +/* + * Called when the fusbh200_hcd module is removed. + */ +static void fusbh200_stop (struct usb_hcd *hcd) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + + fusbh200_dbg (fusbh200, "stop\n"); + + /* no more interrupts ... */ + + spin_lock_irq(&fusbh200->lock); + fusbh200->enabled_hrtimer_events = 0; + spin_unlock_irq(&fusbh200->lock); + + fusbh200_quiesce(fusbh200); + fusbh200_silence_controller(fusbh200); + fusbh200_reset (fusbh200); + + hrtimer_cancel(&fusbh200->hrtimer); + remove_sysfs_files(fusbh200); + remove_debug_files (fusbh200); + + /* root hub is shut down separately (first, when possible) */ + spin_lock_irq (&fusbh200->lock); + end_free_itds(fusbh200); + spin_unlock_irq (&fusbh200->lock); + fusbh200_mem_cleanup (fusbh200); + + fusbh200_dbg(fusbh200, "irq normal %ld err %ld iaa %ld (lost %ld)\n", + fusbh200->stats.normal, fusbh200->stats.error, fusbh200->stats.iaa, + fusbh200->stats.lost_iaa); + fusbh200_dbg (fusbh200, "complete %ld unlink %ld\n", + fusbh200->stats.complete, fusbh200->stats.unlink); + + dbg_status (fusbh200, "fusbh200_stop completed", + fusbh200_readl(fusbh200, &fusbh200->regs->status)); +} + +/* one-time init, only for memory state */ +static int hcd_fusbh200_init(struct usb_hcd *hcd) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200(hcd); + u32 temp; + int retval; + u32 hcc_params; + struct fusbh200_qh_hw *hw; + + spin_lock_init(&fusbh200->lock); + + /* + * keep io watchdog by default, those good HCDs could turn off it later + */ + fusbh200->need_io_watchdog = 1; + + hrtimer_init(&fusbh200->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + fusbh200->hrtimer.function = fusbh200_hrtimer_func; + fusbh200->next_hrtimer_event = FUSBH200_HRTIMER_NO_EVENT; + + hcc_params = fusbh200_readl(fusbh200, &fusbh200->caps->hcc_params); + + /* + * by default set standard 80% (== 100 usec/uframe) max periodic + * bandwidth as required by USB 2.0 + */ + fusbh200->uframe_periodic_max = 100; + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + fusbh200->periodic_size = DEFAULT_I_TDPS; + INIT_LIST_HEAD(&fusbh200->intr_qh_list); + INIT_LIST_HEAD(&fusbh200->cached_itd_list); + + if (HCC_PGM_FRAMELISTLEN(hcc_params)) { + /* periodic schedule size can be smaller than default */ + switch (FUSBH200_TUNE_FLS) { + case 0: fusbh200->periodic_size = 1024; break; + case 1: fusbh200->periodic_size = 512; break; + case 2: fusbh200->periodic_size = 256; break; + default: BUG(); + } + } + if ((retval = fusbh200_mem_init(fusbh200, GFP_KERNEL)) < 0) + return retval; + + /* controllers may cache some of the periodic schedule ... */ + fusbh200->i_thresh = 2; + + /* + * dedicate a qh for the async ring head, since we couldn't unlink + * a 'real' qh without stopping the async schedule [4.8]. use it + * as the 'reclamation list head' too. + * its dummy is used in hw_alt_next of many tds, to prevent the qh + * from automatically advancing to the next td after short reads. + */ + fusbh200->async->qh_next.qh = NULL; + hw = fusbh200->async->hw; + hw->hw_next = QH_NEXT(fusbh200, fusbh200->async->qh_dma); + hw->hw_info1 = cpu_to_hc32(fusbh200, QH_HEAD); + hw->hw_token = cpu_to_hc32(fusbh200, QTD_STS_HALT); + hw->hw_qtd_next = FUSBH200_LIST_END(fusbh200); + fusbh200->async->qh_state = QH_STATE_LINKED; + hw->hw_alt_next = QTD_NEXT(fusbh200, fusbh200->async->dummy->qtd_dma); + + /* clear interrupt enables, set irq latency */ + if (log2_irq_thresh < 0 || log2_irq_thresh > 6) + log2_irq_thresh = 0; + temp = 1 << (16 + log2_irq_thresh); + if (HCC_CANPARK(hcc_params)) { + /* HW default park == 3, on hardware that supports it (like + * NVidia and ALI silicon), maximizes throughput on the async + * schedule by avoiding QH fetches between transfers. + * + * With fast usb storage devices and NForce2, "park" seems to + * make problems: throughput reduction (!), data errors... + */ + if (park) { + park = min(park, (unsigned) 3); + temp |= CMD_PARK; + temp |= park << 8; + } + fusbh200_dbg(fusbh200, "park %d\n", park); + } + if (HCC_PGM_FRAMELISTLEN(hcc_params)) { + /* periodic schedule size can be smaller than default */ + temp &= ~(3 << 2); + temp |= (FUSBH200_TUNE_FLS << 2); + } + fusbh200->command = temp; + + /* Accept arbitrarily long scatter-gather lists */ + if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + hcd->self.sg_tablesize = ~0; + return 0; +} + +/* start HC running; it's halted, hcd_fusbh200_init() has been run (once) */ +static int fusbh200_run (struct usb_hcd *hcd) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + u32 temp; + u32 hcc_params; + + hcd->uses_new_polling = 1; + + /* EHCI spec section 4.1 */ + + fusbh200_writel(fusbh200, fusbh200->periodic_dma, &fusbh200->regs->frame_list); + fusbh200_writel(fusbh200, (u32)fusbh200->async->qh_dma, &fusbh200->regs->async_next); + + /* + * hcc_params controls whether fusbh200->regs->segment must (!!!) + * be used; it constrains QH/ITD/SITD and QTD locations. + * pci_pool consistent memory always uses segment zero. + * streaming mappings for I/O buffers, like pci_map_single(), + * can return segments above 4GB, if the device allows. + * + * NOTE: the dma mask is visible through dma_supported(), so + * drivers can pass this info along ... like NETIF_F_HIGHDMA, + * Scsi_Host.highmem_io, and so forth. It's readonly to all + * host side drivers though. + */ + hcc_params = fusbh200_readl(fusbh200, &fusbh200->caps->hcc_params); + + // Philips, Intel, and maybe others need CMD_RUN before the + // root hub will detect new devices (why?); NEC doesn't + fusbh200->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); + fusbh200->command |= CMD_RUN; + fusbh200_writel(fusbh200, fusbh200->command, &fusbh200->regs->command); + dbg_cmd (fusbh200, "init", fusbh200->command); + + /* + * Start, enabling full USB 2.0 functionality ... usb 1.1 devices + * are explicitly handed to companion controller(s), so no TT is + * involved with the root hub. (Except where one is integrated, + * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. After we set CF, + * a short delay lets the hardware catch up; new resets shouldn't + * be started before the port switching actions could complete. + */ + down_write(&ehci_cf_port_reset_rwsem); + fusbh200->rh_state = FUSBH200_RH_RUNNING; + fusbh200_readl(fusbh200, &fusbh200->regs->command); /* unblock posted writes */ + msleep(5); + up_write(&ehci_cf_port_reset_rwsem); + fusbh200->last_periodic_enable = ktime_get_real(); + + temp = HC_VERSION(fusbh200, fusbh200_readl(fusbh200, &fusbh200->caps->hc_capbase)); + fusbh200_info (fusbh200, + "USB %x.%x started, EHCI %x.%02x\n", + ((fusbh200->sbrn & 0xf0)>>4), (fusbh200->sbrn & 0x0f), + temp >> 8, temp & 0xff); + + fusbh200_writel(fusbh200, INTR_MASK, + &fusbh200->regs->intr_enable); /* Turn On Interrupts */ + + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + create_debug_files(fusbh200); + create_sysfs_files(fusbh200); + + return 0; +} + +static int fusbh200_setup(struct usb_hcd *hcd) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200(hcd); + int retval; + + fusbh200->regs = (void __iomem *)fusbh200->caps + + HC_LENGTH(fusbh200, fusbh200_readl(fusbh200, &fusbh200->caps->hc_capbase)); + dbg_hcs_params(fusbh200, "reset"); + dbg_hcc_params(fusbh200, "reset"); + + /* cache this readonly data; minimize chip reads */ + fusbh200->hcs_params = fusbh200_readl(fusbh200, &fusbh200->caps->hcs_params); + + fusbh200->sbrn = HCD_USB2; + + /* data structure init */ + retval = hcd_fusbh200_init(hcd); + if (retval) + return retval; + + retval = fusbh200_halt(fusbh200); + if (retval) + return retval; + + fusbh200_reset(fusbh200); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static irqreturn_t fusbh200_irq (struct usb_hcd *hcd) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + u32 status, masked_status, pcd_status = 0, cmd; + int bh; + + spin_lock (&fusbh200->lock); + + status = fusbh200_readl(fusbh200, &fusbh200->regs->status); + + /* e.g. cardbus physical eject */ + if (status == ~(u32) 0) { + fusbh200_dbg (fusbh200, "device removed\n"); + goto dead; + } + + /* + * We don't use STS_FLR, but some controllers don't like it to + * remain on, so mask it out along with the other status bits. + */ + masked_status = status & (INTR_MASK | STS_FLR); + + /* Shared IRQ? */ + if (!masked_status || unlikely(fusbh200->rh_state == FUSBH200_RH_HALTED)) { + spin_unlock(&fusbh200->lock); + return IRQ_NONE; + } + + /* clear (just) interrupts */ + fusbh200_writel(fusbh200, masked_status, &fusbh200->regs->status); + cmd = fusbh200_readl(fusbh200, &fusbh200->regs->command); + bh = 0; + + /* normal [4.15.1.2] or error [4.15.1.1] completion */ + if (likely ((status & (STS_INT|STS_ERR)) != 0)) { + if (likely ((status & STS_ERR) == 0)) + COUNT (fusbh200->stats.normal); + else + COUNT (fusbh200->stats.error); + bh = 1; + } + + /* complete the unlinking of some qh [4.15.2.3] */ + if (status & STS_IAA) { + + /* Turn off the IAA watchdog */ + fusbh200->enabled_hrtimer_events &= ~BIT(FUSBH200_HRTIMER_IAA_WATCHDOG); + + /* + * Mild optimization: Allow another IAAD to reset the + * hrtimer, if one occurs before the next expiration. + * In theory we could always cancel the hrtimer, but + * tests show that about half the time it will be reset + * for some other event anyway. + */ + if (fusbh200->next_hrtimer_event == FUSBH200_HRTIMER_IAA_WATCHDOG) + ++fusbh200->next_hrtimer_event; + + /* guard against (alleged) silicon errata */ + if (cmd & CMD_IAAD) + fusbh200_dbg(fusbh200, "IAA with IAAD still set?\n"); + if (fusbh200->async_iaa) { + COUNT(fusbh200->stats.iaa); + end_unlink_async(fusbh200); + } else + fusbh200_dbg(fusbh200, "IAA with nothing unlinked?\n"); + } + + /* remote wakeup [4.3.1] */ + if (status & STS_PCD) { + int pstatus; + u32 __iomem *status_reg = &fusbh200->regs->port_status; + + /* kick root hub later */ + pcd_status = status; + + /* resume root hub? */ + if (fusbh200->rh_state == FUSBH200_RH_SUSPENDED) + usb_hcd_resume_root_hub(hcd); + + pstatus = fusbh200_readl(fusbh200, status_reg); + + if (test_bit(0, &fusbh200->suspended_ports) && + ((pstatus & PORT_RESUME) || + !(pstatus & PORT_SUSPEND)) && + (pstatus & PORT_PE) && + fusbh200->reset_done[0] == 0) { + + /* start 20 msec resume signaling from this port, + * and make khubd collect PORT_STAT_C_SUSPEND to + * stop that signaling. Use 5 ms extra for safety, + * like usb_port_resume() does. + */ + fusbh200->reset_done[0] = jiffies + msecs_to_jiffies(25); + set_bit(0, &fusbh200->resuming_ports); + fusbh200_dbg (fusbh200, "port 1 remote wakeup\n"); + mod_timer(&hcd->rh_timer, fusbh200->reset_done[0]); + } + } + + /* PCI errors [4.15.2.4] */ + if (unlikely ((status & STS_FATAL) != 0)) { + fusbh200_err(fusbh200, "fatal error\n"); + dbg_cmd(fusbh200, "fatal", cmd); + dbg_status(fusbh200, "fatal", status); +dead: + usb_hc_died(hcd); + + /* Don't let the controller do anything more */ + fusbh200->shutdown = true; + fusbh200->rh_state = FUSBH200_RH_STOPPING; + fusbh200->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE); + fusbh200_writel(fusbh200, fusbh200->command, &fusbh200->regs->command); + fusbh200_writel(fusbh200, 0, &fusbh200->regs->intr_enable); + fusbh200_handle_controller_death(fusbh200); + + /* Handle completions when the controller stops */ + bh = 0; + } + + if (bh) + fusbh200_work (fusbh200); + spin_unlock (&fusbh200->lock); + if (pcd_status) + usb_hcd_poll_rh_status(hcd); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + * + * urb + dev is in hcd.self.controller.urb_list + * we're queueing TDs onto software and hardware lists + * + * hcd-specific init for hcpriv hasn't been done yet + * + * NOTE: control, bulk, and interrupt share the same code to append TDs + * to a (possibly active) QH, and the same QH scanning code. + */ +static int fusbh200_urb_enqueue ( + struct usb_hcd *hcd, + struct urb *urb, + gfp_t mem_flags +) { + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + struct list_head qtd_list; + + INIT_LIST_HEAD (&qtd_list); + + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + /* qh_completions() code doesn't handle all the fault cases + * in multi-TD control transfers. Even 1KB is rare anyway. + */ + if (urb->transfer_buffer_length > (16 * 1024)) + return -EMSGSIZE; + /* FALLTHROUGH */ + /* case PIPE_BULK: */ + default: + if (!qh_urb_transaction (fusbh200, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return submit_async(fusbh200, urb, &qtd_list, mem_flags); + + case PIPE_INTERRUPT: + if (!qh_urb_transaction (fusbh200, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return intr_submit(fusbh200, urb, &qtd_list, mem_flags); + + case PIPE_ISOCHRONOUS: + return itd_submit (fusbh200, urb, mem_flags); + } +} + +/* remove from hardware lists + * completions normally happen asynchronously + */ + +static int fusbh200_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + struct fusbh200_qh *qh; + unsigned long flags; + int rc; + + spin_lock_irqsave (&fusbh200->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + + switch (usb_pipetype (urb->pipe)) { + // case PIPE_CONTROL: + // case PIPE_BULK: + default: + qh = (struct fusbh200_qh *) urb->hcpriv; + if (!qh) + break; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + start_unlink_async(fusbh200, qh); + break; + case QH_STATE_UNLINK: + case QH_STATE_UNLINK_WAIT: + /* already started */ + break; + case QH_STATE_IDLE: + /* QH might be waiting for a Clear-TT-Buffer */ + qh_completions(fusbh200, qh); + break; + } + break; + + case PIPE_INTERRUPT: + qh = (struct fusbh200_qh *) urb->hcpriv; + if (!qh) + break; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + start_unlink_intr(fusbh200, qh); + break; + case QH_STATE_IDLE: + qh_completions (fusbh200, qh); + break; + default: + fusbh200_dbg (fusbh200, "bogus qh %p state %d\n", + qh, qh->qh_state); + goto done; + } + break; + + case PIPE_ISOCHRONOUS: + // itd... + + // wait till next completion, do it then. + // completion irqs can wait up to 1024 msec, + break; + } +done: + spin_unlock_irqrestore (&fusbh200->lock, flags); + return rc; +} + +/*-------------------------------------------------------------------------*/ + +// bulk qh holds the data toggle + +static void +fusbh200_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + unsigned long flags; + struct fusbh200_qh *qh, *tmp; + + /* ASSERT: any requests/urbs are being unlinked */ + /* ASSERT: nobody can be submitting urbs for this any more */ + +rescan: + spin_lock_irqsave (&fusbh200->lock, flags); + qh = ep->hcpriv; + if (!qh) + goto done; + + /* endpoints can be iso streams. for now, we don't + * accelerate iso completions ... so spin a while. + */ + if (qh->hw == NULL) { + struct fusbh200_iso_stream *stream = ep->hcpriv; + + if (!list_empty(&stream->td_list)) + goto idle_timeout; + + /* BUG_ON(!list_empty(&stream->free_list)); */ + kfree(stream); + goto done; + } + + if (fusbh200->rh_state < FUSBH200_RH_RUNNING) + qh->qh_state = QH_STATE_IDLE; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + for (tmp = fusbh200->async->qh_next.qh; + tmp && tmp != qh; + tmp = tmp->qh_next.qh) + continue; + /* periodic qh self-unlinks on empty, and a COMPLETING qh + * may already be unlinked. + */ + if (tmp) + start_unlink_async(fusbh200, qh); + /* FALL THROUGH */ + case QH_STATE_UNLINK: /* wait for hw to finish? */ + case QH_STATE_UNLINK_WAIT: +idle_timeout: + spin_unlock_irqrestore (&fusbh200->lock, flags); + schedule_timeout_uninterruptible(1); + goto rescan; + case QH_STATE_IDLE: /* fully unlinked */ + if (qh->clearing_tt) + goto idle_timeout; + if (list_empty (&qh->qtd_list)) { + qh_destroy(fusbh200, qh); + break; + } + /* else FALL THROUGH */ + default: + /* caller was supposed to have unlinked any requests; + * that's not our job. just leak this memory. + */ + fusbh200_err (fusbh200, "qh %p (#%02x) state %d%s\n", + qh, ep->desc.bEndpointAddress, qh->qh_state, + list_empty (&qh->qtd_list) ? "" : "(has tds)"); + break; + } + done: + ep->hcpriv = NULL; + spin_unlock_irqrestore (&fusbh200->lock, flags); +} + +static void +fusbh200_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200(hcd); + struct fusbh200_qh *qh; + int eptype = usb_endpoint_type(&ep->desc); + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + unsigned long flags; + + if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) + return; + + spin_lock_irqsave(&fusbh200->lock, flags); + qh = ep->hcpriv; + + /* For Bulk and Interrupt endpoints we maintain the toggle state + * in the hardware; the toggle bits in udev aren't used at all. + * When an endpoint is reset by usb_clear_halt() we must reset + * the toggle bit in the QH. + */ + if (qh) { + usb_settoggle(qh->dev, epnum, is_out, 0); + if (!list_empty(&qh->qtd_list)) { + WARN_ONCE(1, "clear_halt for a busy endpoint\n"); + } else if (qh->qh_state == QH_STATE_LINKED || + qh->qh_state == QH_STATE_COMPLETING) { + + /* The toggle value in the QH can't be updated + * while the QH is active. Unlink it now; + * re-linking will call qh_refresh(). + */ + if (eptype == USB_ENDPOINT_XFER_BULK) + start_unlink_async(fusbh200, qh); + else + start_unlink_intr(fusbh200, qh); + } + } + spin_unlock_irqrestore(&fusbh200->lock, flags); +} + +static int fusbh200_get_frame (struct usb_hcd *hcd) +{ + struct fusbh200_hcd *fusbh200 = hcd_to_fusbh200 (hcd); + return (fusbh200_read_frame_index(fusbh200) >> 3) % fusbh200->periodic_size; +} + +/*-------------------------------------------------------------------------*/ + +/* + * 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 fusbh200 driver exclusive access to those. + */ +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_LICENSE ("GPL"); + +static const struct hc_driver fusbh200_fusbh200_hc_driver = { + .description = hcd_name, + .product_desc = "Faraday USB2.0 Host Controller", + .hcd_priv_size = sizeof(struct fusbh200_hcd), + + /* + * generic hardware linkage + */ + .irq = fusbh200_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = hcd_fusbh200_init, + .start = fusbh200_run, + .stop = fusbh200_stop, + .shutdown = fusbh200_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = fusbh200_urb_enqueue, + .urb_dequeue = fusbh200_urb_dequeue, + .endpoint_disable = fusbh200_endpoint_disable, + .endpoint_reset = fusbh200_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = fusbh200_get_frame, + + /* + * root hub support + */ + .hub_status_data = fusbh200_hub_status_data, + .hub_control = fusbh200_hub_control, + .bus_suspend = fusbh200_bus_suspend, + .bus_resume = fusbh200_bus_resume, + + .relinquish_port = fusbh200_relinquish_port, + .port_handed_over = fusbh200_port_handed_over, + + .clear_tt_buffer_complete = fusbh200_clear_tt_buffer_complete, +}; + +static void fusbh200_init(struct fusbh200_hcd *fusbh200) +{ + u32 reg; + + reg = fusbh200_readl(fusbh200, &fusbh200->regs->bmcsr); + reg |= BMCSR_INT_POLARITY; + reg &= ~BMCSR_VBUS_OFF; + fusbh200_writel(fusbh200, reg, &fusbh200->regs->bmcsr); + + reg = fusbh200_readl(fusbh200, &fusbh200->regs->bmier); + fusbh200_writel(fusbh200, reg | BMIER_OVC_EN | BMIER_VBUS_ERR_EN, + &fusbh200->regs->bmier); +} + +/** + * fusbh200_hcd_probe - initialize faraday FUSBH200 HCDs + * + * 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. + */ +static int fusbh200_hcd_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_hcd *hcd; + struct resource *res; + int irq; + int retval = -ENODEV; + struct fusbh200_hcd *fusbh200; + + if (usb_disabled()) + return -ENODEV; + + pdev->dev.power.power_state = PMSG_ON; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, + "Found HC with no IRQ. Check %s setup!\n", + dev_name(dev)); + return -ENODEV; + } + + irq = res->start; + + hcd = usb_create_hcd(&fusbh200_fusbh200_hc_driver, dev, + dev_name(dev)); + if (!hcd) { + dev_err(dev, "failed to create hcd with err %d\n", retval); + retval = -ENOMEM; + goto fail_create_hcd; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(dev)); + retval = -ENODEV; + goto fail_request_resource; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + hcd->has_tt = 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + fusbh200_fusbh200_hc_driver.description)) { + dev_dbg(dev, "controller already in use\n"); + retval = -EBUSY; + goto fail_request_resource; + } + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(dev)); + retval = -ENODEV; + goto fail_request_resource; + } + + hcd->regs = ioremap_nocache(res->start, resource_size(res)); + if (hcd->regs == NULL) { + dev_dbg(dev, "error mapping memory\n"); + retval = -EFAULT; + goto fail_ioremap; + } + + fusbh200 = hcd_to_fusbh200(hcd); + + fusbh200->caps = hcd->regs; + + retval = fusbh200_setup(hcd); + if (retval) + goto fail_add_hcd; + + fusbh200_init(fusbh200); + + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval) { + dev_err(dev, "failed to add hcd with err %d\n", retval); + goto fail_add_hcd; + } + device_wakeup_enable(hcd->self.controller); + + return retval; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +fail_request_resource: + usb_put_hcd(hcd); +fail_create_hcd: + dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); + return retval; +} + +/** + * fusbh200_hcd_remove - shutdown processing for EHCI HCDs + * @dev: USB Host Controller being removed + * + * Reverses the effect of fotg2xx_usb_hcd_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + */ +static int fusbh200_hcd_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_hcd *hcd = dev_get_drvdata(dev); + + if (!hcd) + return 0; + + 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 fusbh200_hcd_fusbh200_driver = { + .driver = { + .name = "fusbh200", + }, + .probe = fusbh200_hcd_probe, + .remove = fusbh200_hcd_remove, +}; + +static int __init fusbh200_hcd_init(void) +{ + int retval = 0; + + if (usb_disabled()) + return -ENODEV; + + printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); + set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || + test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) + printk(KERN_WARNING "Warning! fusbh200_hcd should always be loaded" + " before uhci_hcd and ohci_hcd, not after\n"); + + pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd\n", + hcd_name, + sizeof(struct fusbh200_qh), sizeof(struct fusbh200_qtd), + sizeof(struct fusbh200_itd)); + + fusbh200_debug_root = debugfs_create_dir("fusbh200", usb_debug_root); + if (!fusbh200_debug_root) { + retval = -ENOENT; + goto err_debug; + } + + retval = platform_driver_register(&fusbh200_hcd_fusbh200_driver); + if (retval < 0) + goto clean; + return retval; + + platform_driver_unregister(&fusbh200_hcd_fusbh200_driver); +clean: + debugfs_remove(fusbh200_debug_root); + fusbh200_debug_root = NULL; +err_debug: + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + return retval; +} +module_init(fusbh200_hcd_init); + +static void __exit fusbh200_hcd_cleanup(void) +{ + platform_driver_unregister(&fusbh200_hcd_fusbh200_driver); + debugfs_remove(fusbh200_debug_root); + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); +} +module_exit(fusbh200_hcd_cleanup); diff --git a/drivers/usb/host/fusbh200.h b/drivers/usb/host/fusbh200.h new file mode 100644 index 00000000000..6b719e066c3 --- /dev/null +++ b/drivers/usb/host/fusbh200.h @@ -0,0 +1,731 @@ +#ifndef __LINUX_FUSBH200_H +#define __LINUX_FUSBH200_H + +/* definitions used for the EHCI driver */ + +/* + * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to + * __leXX (normally) or __beXX (given FUSBH200_BIG_ENDIAN_DESC), depending on + * the host controller implementation. + * + * To facilitate the strongest possible byte-order checking from "sparse" + * and so on, we use __leXX unless that's not practical. + */ +#define __hc32 __le32 +#define __hc16 __le16 + +/* statistics can be kept for tuning/monitoring */ +struct fusbh200_stats { + /* irq usage */ + unsigned long normal; + unsigned long error; + unsigned long iaa; + unsigned long lost_iaa; + + /* termination of urbs from core */ + unsigned long complete; + unsigned long unlink; +}; + +/* fusbh200_hcd->lock guards shared data against other CPUs: + * fusbh200_hcd: async, unlink, periodic (and shadow), ... + * usb_host_endpoint: hcpriv + * fusbh200_qh: qh_next, qtd_list + * fusbh200_qtd: qtd_list + * + * Also, hold this lock when talking to HC registers or + * when updating hw_* fields in shared qh/qtd/... structures. + */ + +#define FUSBH200_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */ + +/* + * fusbh200_rh_state values of FUSBH200_RH_RUNNING or above mean that the + * controller may be doing DMA. Lower values mean there's no DMA. + */ +enum fusbh200_rh_state { + FUSBH200_RH_HALTED, + FUSBH200_RH_SUSPENDED, + FUSBH200_RH_RUNNING, + FUSBH200_RH_STOPPING +}; + +/* + * Timer events, ordered by increasing delay length. + * Always update event_delays_ns[] and event_handlers[] (defined in + * ehci-timer.c) in parallel with this list. + */ +enum fusbh200_hrtimer_event { + FUSBH200_HRTIMER_POLL_ASS, /* Poll for async schedule off */ + FUSBH200_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ + FUSBH200_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ + FUSBH200_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ + FUSBH200_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ + FUSBH200_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ + FUSBH200_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ + FUSBH200_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ + FUSBH200_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ + FUSBH200_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */ + FUSBH200_HRTIMER_NUM_EVENTS /* Must come last */ +}; +#define FUSBH200_HRTIMER_NO_EVENT 99 + +struct fusbh200_hcd { /* one per controller */ + /* timing support */ + enum fusbh200_hrtimer_event next_hrtimer_event; + unsigned enabled_hrtimer_events; + ktime_t hr_timeouts[FUSBH200_HRTIMER_NUM_EVENTS]; + struct hrtimer hrtimer; + + int PSS_poll_count; + int ASS_poll_count; + int died_poll_count; + + /* glue to PCI and HCD framework */ + struct fusbh200_caps __iomem *caps; + struct fusbh200_regs __iomem *regs; + struct fusbh200_dbg_port __iomem *debug; + + __u32 hcs_params; /* cached register copy */ + spinlock_t lock; + enum fusbh200_rh_state rh_state; + + /* general schedule support */ + bool scanning:1; + bool need_rescan:1; + bool intr_unlinking:1; + bool async_unlinking:1; + bool shutdown:1; + struct fusbh200_qh *qh_scan_next; + + /* async schedule support */ + struct fusbh200_qh *async; + struct fusbh200_qh *dummy; /* For AMD quirk use */ + struct fusbh200_qh *async_unlink; + struct fusbh200_qh *async_unlink_last; + struct fusbh200_qh *async_iaa; + unsigned async_unlink_cycle; + unsigned async_count; /* async activity count */ + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ + unsigned periodic_size; + __hc32 *periodic; /* hw periodic table */ + dma_addr_t periodic_dma; + struct list_head intr_qh_list; + unsigned i_thresh; /* uframes HC might cache */ + + union fusbh200_shadow *pshadow; /* mirror hw periodic table */ + struct fusbh200_qh *intr_unlink; + struct fusbh200_qh *intr_unlink_last; + unsigned intr_unlink_cycle; + unsigned now_frame; /* frame from HC hardware */ + unsigned next_frame; /* scan periodic, start here */ + unsigned intr_count; /* intr activity count */ + unsigned isoc_count; /* isoc activity count */ + unsigned periodic_count; /* periodic activity count */ + unsigned uframe_periodic_max; /* max periodic time per uframe */ + + + /* list of itds completed while now_frame was still active */ + struct list_head cached_itd_list; + struct fusbh200_itd *last_itd_to_free; + + /* per root hub port */ + unsigned long reset_done [FUSBH200_MAX_ROOT_PORTS]; + + /* bit vectors (one bit per port) */ + unsigned long bus_suspended; /* which ports were + already suspended at the start of a bus suspend */ + unsigned long companion_ports; /* which ports are + dedicated to the companion controller */ + unsigned long owned_ports; /* which ports are + owned by the companion during a bus suspend */ + unsigned long port_c_suspend; /* which ports have + the change-suspend feature turned on */ + unsigned long suspended_ports; /* which ports are + suspended */ + unsigned long resuming_ports; /* which ports have + started to resume */ + + /* per-HC memory pools (could be per-bus, but ...) */ + struct dma_pool *qh_pool; /* qh per active urb */ + struct dma_pool *qtd_pool; /* one or more per qh */ + struct dma_pool *itd_pool; /* itd per iso urb */ + + unsigned random_frame; + unsigned long next_statechange; + ktime_t last_periodic_enable; + u32 command; + + /* SILICON QUIRKS */ + unsigned need_io_watchdog:1; + unsigned fs_i_thresh:1; /* Intel iso scheduling */ + + u8 sbrn; /* packed release number */ + + /* irq statistics */ + struct fusbh200_stats stats; +# define COUNT(x) do { (x)++; } while (0) + + /* debug files */ + struct dentry *debug_dir; +}; + +/* convert between an HCD pointer and the corresponding FUSBH200_HCD */ +static inline struct fusbh200_hcd *hcd_to_fusbh200 (struct usb_hcd *hcd) +{ + return (struct fusbh200_hcd *) (hcd->hcd_priv); +} +static inline struct usb_hcd *fusbh200_to_hcd (struct fusbh200_hcd *fusbh200) +{ + return container_of ((void *) fusbh200, struct usb_hcd, hcd_priv); +} + +/*-------------------------------------------------------------------------*/ + +/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ + +/* Section 2.2 Host Controller Capability Registers */ +struct fusbh200_caps { + /* these fields are specified as 8 and 16 bit registers, + * but some hosts can't perform 8 or 16 bit PCI accesses. + * some hosts treat caplength and hciversion as parts of a 32-bit + * register, others treat them as two separate registers, this + * affects the memory map for big endian controllers. + */ + u32 hc_capbase; +#define HC_LENGTH(fusbh200, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \ + (fusbh200_big_endian_capbase(fusbh200) ? 24 : 0))) +#define HC_VERSION(fusbh200, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \ + (fusbh200_big_endian_capbase(fusbh200) ? 0 : 16))) + u32 hcs_params; /* HCSPARAMS - offset 0x4 */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ + + u32 hcc_params; /* HCCPARAMS - offset 0x8 */ +#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ +#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ + u8 portroute[8]; /* nibbles for routing - offset 0xC */ +}; + + +/* Section 2.3 Host Controller Operational Registers */ +struct fusbh200_regs { + + /* USBCMD: offset 0x00 */ + u32 command; + +/* EHCI 1.1 addendum */ +/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ +#define CMD_PARK (1<<11) /* enable "park" on async qh */ +#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ +#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ +#define CMD_ASE (1<<5) /* async schedule enable */ +#define CMD_PSE (1<<4) /* periodic schedule enable */ +/* 3:2 is periodic frame list size */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ + + /* USBSTS: offset 0x04 */ + u32 status; +#define STS_ASS (1<<15) /* Async Schedule Status */ +#define STS_PSS (1<<14) /* Periodic Schedule Status */ +#define STS_RECL (1<<13) /* Reclamation */ +#define STS_HALT (1<<12) /* Not running (any reason) */ +/* some bits reserved */ + /* these STS_* flags are also intr_enable bits (USBINTR) */ +#define STS_IAA (1<<5) /* Interrupted on async advance */ +#define STS_FATAL (1<<4) /* such as some PCI access errors */ +#define STS_FLR (1<<3) /* frame list rolled over */ +#define STS_PCD (1<<2) /* port change detect */ +#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ +#define STS_INT (1<<0) /* "normal" completion (short, ...) */ + + /* USBINTR: offset 0x08 */ + u32 intr_enable; + + /* FRINDEX: offset 0x0C */ + u32 frame_index; /* current microframe number */ + /* CTRLDSSEGMENT: offset 0x10 */ + u32 segment; /* address bits 63:32 if needed */ + /* PERIODICLISTBASE: offset 0x14 */ + u32 frame_list; /* points to periodic list */ + /* ASYNCLISTADDR: offset 0x18 */ + u32 async_next; /* address of next async queue head */ + + u32 reserved1; + /* PORTSC: offset 0x20 */ + u32 port_status; +/* 31:23 reserved */ +#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_PEC (1<<3) /* port enable change */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +#define PORT_RWC_BITS (PORT_CSC | PORT_PEC) + + u32 reserved2[3]; + + /* BMCSR: offset 0x30 */ + u32 bmcsr; /* Bus Moniter Control/Status Register */ +#define BMCSR_HOST_SPD_TYP (3<<9) +#define BMCSR_VBUS_OFF (1<<4) +#define BMCSR_INT_POLARITY (1<<3) + + /* BMISR: offset 0x34 */ + u32 bmisr; /* Bus Moniter Interrupt Status Register*/ +#define BMISR_OVC (1<<1) + + /* BMIER: offset 0x38 */ + u32 bmier; /* Bus Moniter Interrupt Enable Register */ +#define BMIER_OVC_EN (1<<1) +#define BMIER_VBUS_ERR_EN (1<<0) +}; + +/* Appendix C, Debug port ... intended for use with special "debug devices" + * that can help if there's no serial console. (nonstandard enumeration.) + */ +struct fusbh200_dbg_port { + u32 control; +#define DBGP_OWNER (1<<30) +#define DBGP_ENABLED (1<<28) +#define DBGP_DONE (1<<16) +#define DBGP_INUSE (1<<10) +#define DBGP_ERRCODE(x) (((x)>>7)&0x07) +# define DBGP_ERR_BAD 1 +# define DBGP_ERR_SIGNAL 2 +#define DBGP_ERROR (1<<6) +#define DBGP_GO (1<<5) +#define DBGP_OUT (1<<4) +#define DBGP_LEN(x) (((x)>>0)&0x0f) + u32 pids; +#define DBGP_PID_GET(x) (((x)>>16)&0xff) +#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) + u32 data03; + u32 data47; + u32 address; +#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) +}; + +#ifdef CONFIG_EARLY_PRINTK_DBGP +#include <linux/init.h> +extern int __init early_dbgp_init(char *s); +extern struct console early_dbgp_console; +#endif /* CONFIG_EARLY_PRINTK_DBGP */ + +struct usb_hcd; + +static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) +{ + return 1; /* Shouldn't this be 0? */ +} + +static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) +{ + return -1; +} + +#ifdef CONFIG_EARLY_PRINTK_DBGP +/* Call backs from fusbh200 host driver to fusbh200 debug driver */ +extern int dbgp_external_startup(struct usb_hcd *); +extern int dbgp_reset_prep(struct usb_hcd *hcd); +#else +static inline int dbgp_reset_prep(struct usb_hcd *hcd) +{ + return xen_dbgp_reset_prep(hcd); +} +static inline int dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_external_startup(hcd); +} +#endif + +/*-------------------------------------------------------------------------*/ + +#define QTD_NEXT(fusbh200, dma) cpu_to_hc32(fusbh200, (u32)dma) + +/* + * EHCI Specification 0.95 Section 3.5 + * QTD: describe data transfer components (buffer, direction, ...) + * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". + * + * These are associated only with "QH" (Queue Head) structures, + * used with control, bulk, and interrupt transfers. + */ +struct fusbh200_qtd { + /* first part defined by EHCI spec */ + __hc32 hw_next; /* see EHCI 3.5.1 */ + __hc32 hw_alt_next; /* see EHCI 3.5.2 */ + __hc32 hw_token; /* see EHCI 3.5.3 */ +#define QTD_TOGGLE (1 << 31) /* data toggle */ +#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) +#define QTD_IOC (1 << 15) /* interrupt on complete */ +#define QTD_CERR(tok) (((tok)>>10) & 0x3) +#define QTD_PID(tok) (((tok)>>8) & 0x3) +#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ +#define QTD_STS_HALT (1 << 6) /* halted on error */ +#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ +#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ +#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ +#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ +#define QTD_STS_STS (1 << 1) /* split transaction state */ +#define QTD_STS_PING (1 << 0) /* issue PING? */ + +#define ACTIVE_BIT(fusbh200) cpu_to_hc32(fusbh200, QTD_STS_ACTIVE) +#define HALT_BIT(fusbh200) cpu_to_hc32(fusbh200, QTD_STS_HALT) +#define STATUS_BIT(fusbh200) cpu_to_hc32(fusbh200, QTD_STS_STS) + + __hc32 hw_buf [5]; /* see EHCI 3.5.4 */ + __hc32 hw_buf_hi [5]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t qtd_dma; /* qtd address */ + struct list_head qtd_list; /* sw qtd list */ + struct urb *urb; /* qtd's urb */ + size_t length; /* length of buffer */ +} __attribute__ ((aligned (32))); + +/* mask NakCnt+T in qh->hw_alt_next */ +#define QTD_MASK(fusbh200) cpu_to_hc32 (fusbh200, ~0x1f) + +#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) + +/*-------------------------------------------------------------------------*/ + +/* type tag from {qh,itd,fstn}->hw_next */ +#define Q_NEXT_TYPE(fusbh200,dma) ((dma) & cpu_to_hc32(fusbh200, 3 << 1)) + +/* + * Now the following defines are not converted using the + * cpu_to_le32() macro anymore, since we have to support + * "dynamic" switching between be and le support, so that the driver + * can be used on one system with SoC EHCI controller using big-endian + * descriptors as well as a normal little-endian PCI EHCI controller. + */ +/* values for that type tag */ +#define Q_TYPE_ITD (0 << 1) +#define Q_TYPE_QH (1 << 1) +#define Q_TYPE_SITD (2 << 1) +#define Q_TYPE_FSTN (3 << 1) + +/* next async queue entry, or pointer to interrupt/periodic QH */ +#define QH_NEXT(fusbh200,dma) (cpu_to_hc32(fusbh200, (((u32)dma)&~0x01f)|Q_TYPE_QH)) + +/* for periodic/async schedules and qtd lists, mark end of list */ +#define FUSBH200_LIST_END(fusbh200) cpu_to_hc32(fusbh200, 1) /* "null pointer" to hw */ + +/* + * Entries in periodic shadow table are pointers to one of four kinds + * of data structure. That's dictated by the hardware; a type tag is + * encoded in the low bits of the hardware's periodic schedule. Use + * Q_NEXT_TYPE to get the tag. + * + * For entries in the async schedule, the type tag always says "qh". + */ +union fusbh200_shadow { + struct fusbh200_qh *qh; /* Q_TYPE_QH */ + struct fusbh200_itd *itd; /* Q_TYPE_ITD */ + struct fusbh200_fstn *fstn; /* Q_TYPE_FSTN */ + __hc32 *hw_next; /* (all types) */ + void *ptr; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.6 + * QH: describes control/bulk/interrupt endpoints + * See Fig 3-7 "Queue Head Structure Layout". + * + * These appear in both the async and (for interrupt) periodic schedules. + */ + +/* first part defined by EHCI spec */ +struct fusbh200_qh_hw { + __hc32 hw_next; /* see EHCI 3.6.1 */ + __hc32 hw_info1; /* see EHCI 3.6.2 */ +#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */ +#define QH_HEAD (1 << 15) /* Head of async reclamation list */ +#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */ +#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */ +#define QH_LOW_SPEED (1 << 12) +#define QH_FULL_SPEED (0 << 12) +#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */ + __hc32 hw_info2; /* see EHCI 3.6.2 */ +#define QH_SMASK 0x000000ff +#define QH_CMASK 0x0000ff00 +#define QH_HUBADDR 0x007f0000 +#define QH_HUBPORT 0x3f800000 +#define QH_MULT 0xc0000000 + __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */ + + /* qtd overlay (hardware parts of a struct fusbh200_qtd) */ + __hc32 hw_qtd_next; + __hc32 hw_alt_next; + __hc32 hw_token; + __hc32 hw_buf [5]; + __hc32 hw_buf_hi [5]; +} __attribute__ ((aligned(32))); + +struct fusbh200_qh { + struct fusbh200_qh_hw *hw; /* Must come first */ + /* the rest is HCD-private */ + dma_addr_t qh_dma; /* address of qh */ + union fusbh200_shadow qh_next; /* ptr to qh; or periodic */ + struct list_head qtd_list; /* sw qtd list */ + struct list_head intr_node; /* list of intr QHs */ + struct fusbh200_qtd *dummy; + struct fusbh200_qh *unlink_next; /* next on unlink list */ + + unsigned unlink_cycle; + + u8 needs_rescan; /* Dequeue during giveback */ + u8 qh_state; +#define QH_STATE_LINKED 1 /* HC sees this */ +#define QH_STATE_UNLINK 2 /* HC may still see this */ +#define QH_STATE_IDLE 3 /* HC doesn't see this */ +#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */ +#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ + + u8 xacterrs; /* XactErr retry counter */ +#define QH_XACTERR_MAX 32 /* XactErr retry limit */ + + /* periodic schedule info */ + u8 usecs; /* intr bandwidth */ + u8 gap_uf; /* uframes split/csplit gap */ + u8 c_usecs; /* ... split completion bw */ + u16 tt_usecs; /* tt downstream bandwidth */ + unsigned short period; /* polling interval */ + unsigned short start; /* where polling starts */ +#define NO_FRAME ((unsigned short)~0) /* pick new start */ + + struct usb_device *dev; /* access to TT */ + unsigned is_out:1; /* bulk or intr OUT */ + unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ +}; + +/*-------------------------------------------------------------------------*/ + +/* description of one iso transaction (up to 3 KB data if highspeed) */ +struct fusbh200_iso_packet { + /* These will be copied to iTD when scheduling */ + u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ + __hc32 transaction; /* itd->hw_transaction[i] |= */ + u8 cross; /* buf crosses pages */ + /* for full speed OUT splits */ + u32 buf1; +}; + +/* temporary schedule data for packets from iso urbs (both speeds) + * each packet is one logical usb transaction to the device (not TT), + * beginning at stream->next_uframe + */ +struct fusbh200_iso_sched { + struct list_head td_list; + unsigned span; + struct fusbh200_iso_packet packet [0]; +}; + +/* + * fusbh200_iso_stream - groups all (s)itds for this endpoint. + * acts like a qh would, if EHCI had them for ISO. + */ +struct fusbh200_iso_stream { + /* first field matches fusbh200_hq, but is NULL */ + struct fusbh200_qh_hw *hw; + + u8 bEndpointAddress; + u8 highspeed; + struct list_head td_list; /* queued itds */ + struct list_head free_list; /* list of unused itds */ + struct usb_device *udev; + struct usb_host_endpoint *ep; + + /* output of (re)scheduling */ + int next_uframe; + __hc32 splits; + + /* the rest is derived from the endpoint descriptor, + * trusting urb->interval == f(epdesc->bInterval) and + * including the extra info for hw_bufp[0..2] + */ + u8 usecs, c_usecs; + u16 interval; + u16 tt_usecs; + u16 maxp; + u16 raw_mask; + unsigned bandwidth; + + /* This is used to initialize iTD's hw_bufp fields */ + __hc32 buf0; + __hc32 buf1; + __hc32 buf2; + + /* this is used to initialize sITD's tt info */ + __hc32 address; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.3 + * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" + * + * Schedule records for high speed iso xfers + */ +struct fusbh200_itd { + /* first part defined by EHCI spec */ + __hc32 hw_next; /* see EHCI 3.3.1 */ + __hc32 hw_transaction [8]; /* see EHCI 3.3.2 */ +#define FUSBH200_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ +#define FUSBH200_ISOC_BUF_ERR (1<<30) /* Data buffer error */ +#define FUSBH200_ISOC_BABBLE (1<<29) /* babble detected */ +#define FUSBH200_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ +#define FUSBH200_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff) +#define FUSBH200_ITD_IOC (1 << 15) /* interrupt on complete */ + +#define ITD_ACTIVE(fusbh200) cpu_to_hc32(fusbh200, FUSBH200_ISOC_ACTIVE) + + __hc32 hw_bufp [7]; /* see EHCI 3.3.3 */ + __hc32 hw_bufp_hi [7]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t itd_dma; /* for this itd */ + union fusbh200_shadow itd_next; /* ptr to periodic q entry */ + + struct urb *urb; + struct fusbh200_iso_stream *stream; /* endpoint's queue */ + struct list_head itd_list; /* list of stream's itds */ + + /* any/all hw_transactions here may be used by that urb */ + unsigned frame; /* where scheduled */ + unsigned pg; + unsigned index[8]; /* in urb->iso_frame_desc */ +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.96 Section 3.7 + * Periodic Frame Span Traversal Node (FSTN) + * + * Manages split interrupt transactions (using TT) that span frame boundaries + * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN + * makes the HC jump (back) to a QH to scan for fs/ls QH completions until + * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. + */ +struct fusbh200_fstn { + __hc32 hw_next; /* any periodic q entry */ + __hc32 hw_prev; /* qh or FUSBH200_LIST_END */ + + /* the rest is HCD-private */ + dma_addr_t fstn_dma; + union fusbh200_shadow fstn_next; /* ptr to periodic q entry */ +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* Prepare the PORTSC wakeup flags during controller suspend/resume */ + +#define fusbh200_prepare_ports_for_controller_suspend(fusbh200, do_wakeup) \ + fusbh200_adjust_port_wakeup_flags(fusbh200, true, do_wakeup); + +#define fusbh200_prepare_ports_for_controller_resume(fusbh200) \ + fusbh200_adjust_port_wakeup_flags(fusbh200, false, false); + +/*-------------------------------------------------------------------------*/ + +/* + * Some EHCI controllers have a Transaction Translator built into the + * root hub. This is a non-standard feature. Each controller will need + * to add code to the following inline functions, and call them as + * needed (mostly in root hub code). + */ + +static inline unsigned int +fusbh200_get_speed(struct fusbh200_hcd *fusbh200, unsigned int portsc) +{ + return (readl(&fusbh200->regs->bmcsr) + & BMCSR_HOST_SPD_TYP) >> 9; +} + +/* Returns the speed of a device attached to a port on the root hub. */ +static inline unsigned int +fusbh200_port_speed(struct fusbh200_hcd *fusbh200, unsigned int portsc) +{ + switch (fusbh200_get_speed(fusbh200, portsc)) { + case 0: + return 0; + case 1: + return USB_PORT_STAT_LOW_SPEED; + case 2: + default: + return USB_PORT_STAT_HIGH_SPEED; + } +} + +/*-------------------------------------------------------------------------*/ + +#define fusbh200_has_fsl_portno_bug(e) (0) + +/* + * While most USB host controllers implement their registers in + * little-endian format, a minority (celleb companion chip) implement + * them in big endian format. + * + * This attempts to support either format at compile time without a + * runtime penalty, or both formats with the additional overhead + * of checking a flag bit. + * + */ + +#define fusbh200_big_endian_mmio(e) 0 +#define fusbh200_big_endian_capbase(e) 0 + +static inline unsigned int fusbh200_readl(const struct fusbh200_hcd *fusbh200, + __u32 __iomem * regs) +{ + return readl(regs); +} + +static inline void fusbh200_writel(const struct fusbh200_hcd *fusbh200, + const unsigned int val, __u32 __iomem *regs) +{ + writel(val, regs); +} + +/* cpu to fusbh200 */ +static inline __hc32 cpu_to_hc32 (const struct fusbh200_hcd *fusbh200, const u32 x) +{ + return cpu_to_le32(x); +} + +/* fusbh200 to cpu */ +static inline u32 hc32_to_cpu (const struct fusbh200_hcd *fusbh200, const __hc32 x) +{ + return le32_to_cpu(x); +} + +static inline u32 hc32_to_cpup (const struct fusbh200_hcd *fusbh200, const __hc32 *x) +{ + return le32_to_cpup(x); +} + +/*-------------------------------------------------------------------------*/ + +static inline unsigned fusbh200_read_frame_index(struct fusbh200_hcd *fusbh200) +{ + return fusbh200_readl(fusbh200, &fusbh200->regs->frame_index); +} + +#define fusbh200_itdlen(urb, desc, t) ({ \ + usb_pipein((urb)->pipe) ? \ + (desc)->length - FUSBH200_ITD_LENGTH(t) : \ + FUSBH200_ITD_LENGTH(t); \ +}) +/*-------------------------------------------------------------------------*/ + +#endif /* __LINUX_FUSBH200_H */ diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 104730dabd2..d0d8fadf706 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -54,7 +54,6 @@ * DWA). */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/workqueue.h> @@ -86,7 +85,7 @@ static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id) USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, cluster_id, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); + NULL, 0, USB_CTRL_SET_TIMEOUT); if (result < 0) dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n", cluster_id, result); @@ -106,7 +105,7 @@ static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots) USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, interval << 8 | slots, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); + NULL, 0, USB_CTRL_SET_TIMEOUT); } /* @@ -161,6 +160,13 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd) usb_hcd->uses_new_polling = 1; set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags); usb_hcd->state = HC_STATE_RUNNING; + + /* + * prevent USB core from suspending the root hub since + * bus_suspend and bus_resume are not yet supported. + */ + pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev); + result = 0; out: mutex_unlock(&wusbhc->mutex); @@ -192,10 +198,14 @@ static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd) { struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); + struct wahc *wa = &hwahc->wa; - dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, - usb_hcd, hwahc); - return -ENOSYS; + /* + * We cannot query the HWA for the WUSB time since that requires sending + * a synchronous URB and this function can be called in_interrupt. + * Instead, query the USB frame number for our parent and use that. + */ + return usb_get_current_frame_number(wa->usb_dev); } static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, @@ -213,7 +223,7 @@ static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - return wa_urb_dequeue(&hwahc->wa, urb); + return wa_urb_dequeue(&hwahc->wa, urb, status); } /* @@ -251,8 +261,44 @@ static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) dev_err(dev, "cannot listen to notifications: %d\n", result); goto error_stop; } + /* + * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set, + * disable transfer notifications. + */ + if (hwahc->wa.quirks & + WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) { + struct usb_host_interface *cur_altsetting = + hwahc->wa.usb_iface->cur_altsetting; + + result = usb_control_msg(hwahc->wa.usb_dev, + usb_sndctrlpipe(hwahc->wa.usb_dev, 0), + WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_INTERFACE, + WA_REQ_ALEREON_FEATURE_SET, + cur_altsetting->desc.bInterfaceNumber, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + /* + * If we successfully sent the control message, start DTI here + * because no transfer notifications will be received which is + * where DTI is normally started. + */ + if (result == 0) + result = wa_dti_start(&hwahc->wa); + else + result = 0; /* OK. Continue normally. */ + + if (result < 0) { + dev_err(dev, "cannot start DTI: %d\n", result); + goto error_dti_start; + } + } + return result; +error_dti_start: + wa_nep_disarm(&hwahc->wa); error_stop: __wa_clear_feature(&hwahc->wa, WA_ENABLE); return result; @@ -270,7 +316,7 @@ static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay) USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, delay * 1000, iface_no, - NULL, 0, 1000 /* FIXME: arbitrary */); + NULL, 0, USB_CTRL_SET_TIMEOUT); if (ret == 0) msleep(delay); @@ -299,7 +345,7 @@ static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, stream_index, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); + NULL, 0, USB_CTRL_SET_TIMEOUT); if (result < 0) { dev_err(dev, "Cannot set WUSB stream index: %d\n", result); goto out; @@ -310,7 +356,7 @@ static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index, WUSB_REQ_SET_WUSB_MAS, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - mas_le, 32, 1000 /* FIXME: arbitrary */); + mas_le, 32, USB_CTRL_SET_TIMEOUT); if (result < 0) dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result); out: @@ -344,7 +390,7 @@ static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, interval << 8 | repeat_cnt, handle << 8 | iface_no, - wuie, wuie->bLength, 1000 /* FIXME: arbitrary */); + wuie, wuie->bLength, USB_CTRL_SET_TIMEOUT); } /* @@ -361,7 +407,7 @@ static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle) WUSB_REQ_REMOVE_MMC_IE, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, handle << 8 | iface_no, - NULL, 0, 1000 /* FIXME: arbitrary */); + NULL, 0, USB_CTRL_SET_TIMEOUT); } /* @@ -404,7 +450,7 @@ static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, wusb_dev->port_idx << 8 | iface_no, dev_info, sizeof(struct hwa_dev_info), - 1000 /* FIXME: arbitrary */); + USB_CTRL_SET_TIMEOUT); kfree(dev_info); return ret; } @@ -444,7 +490,7 @@ static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_DT_KEY << 8 | key_idx, port_idx << 8 | iface_no, - keyd, keyd_len, 1000 /* FIXME: arbitrary */); + keyd, keyd_len, USB_CTRL_SET_TIMEOUT); kzfree(keyd); /* clear keys etc. */ return result; @@ -486,7 +532,7 @@ static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, USB_REQ_SET_ENCRYPTION, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, encryption_value, port_idx << 8 | iface_no, - NULL, 0, 1000 /* FIXME: arbitrary */); + NULL, 0, USB_CTRL_SET_TIMEOUT); if (result < 0) dev_err(wusbhc->dev, "Can't set host's WUSB encryption for " "port index %u to %s (value %d): %d\n", port_idx, @@ -559,14 +605,10 @@ found: goto error; } wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr; - /* Make LE fields CPU order */ - wa_descr->bcdWAVersion = le16_to_cpu(wa_descr->bcdWAVersion); - wa_descr->wNumRPipes = le16_to_cpu(wa_descr->wNumRPipes); - wa_descr->wRPipeMaxBlock = le16_to_cpu(wa_descr->wRPipeMaxBlock); - if (wa_descr->bcdWAVersion > 0x0100) + if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100) dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n", - wa_descr->bcdWAVersion & 0xff00 >> 8, - wa_descr->bcdWAVersion & 0x00ff); + le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00 >> 8, + le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff); result = 0; error: return result; @@ -577,7 +619,7 @@ static struct hc_driver hwahc_hc_driver = { .product_desc = "Wireless USB HWA host controller", .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd), .irq = NULL, /* FIXME */ - .flags = HCD_USB2, /* FIXME */ + .flags = HCD_USB25, .reset = hwahc_op_reset, .start = hwahc_op_start, .stop = hwahc_op_stop, @@ -588,8 +630,6 @@ static struct hc_driver hwahc_hc_driver = { .hub_status_data = wusbhc_rh_status_data, .hub_control = wusbhc_rh_control, - .bus_suspend = wusbhc_rh_suspend, - .bus_resume = wusbhc_rh_resume, .start_port_reset = wusbhc_rh_start_port_reset, }; @@ -674,7 +714,8 @@ static void hwahc_security_release(struct hwahc *hwahc) /* nothing to do here so far... */ } -static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) +static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface, + kernel_ulong_t quirks) { int result; struct device *dev = &iface->dev; @@ -685,12 +726,9 @@ static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ wa->usb_iface = usb_get_intf(iface); wusbhc->dev = dev; - wusbhc->uwb_rc = uwb_rc_get_by_grandpa(iface->dev.parent); - if (wusbhc->uwb_rc == NULL) { - result = -ENODEV; - dev_err(dev, "Cannot get associated UWB Host Controller\n"); - goto error_rc_get; - } + /* defer getting the uwb_rc handle until it is needed since it + * may not have been registered by the hwa_rc driver yet. */ + wusbhc->uwb_rc = NULL; result = wa_fill_descr(wa); /* Get the device descriptor */ if (result < 0) goto error_fill_descriptor; @@ -722,7 +760,7 @@ static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) dev_err(dev, "Can't create WUSB HC structures: %d\n", result); goto error_wusbhc_create; } - result = wa_create(&hwahc->wa, iface); + result = wa_create(&hwahc->wa, iface, quirks); if (result < 0) goto error_wa_create; return 0; @@ -733,8 +771,6 @@ error_wusbhc_create: /* WA Descr fill allocs no resources */ error_security_create: error_fill_descriptor: - uwb_rc_put(wusbhc->uwb_rc); -error_rc_get: usb_put_intf(iface); usb_put_dev(usb_dev); return result; @@ -776,10 +812,11 @@ static int hwahc_probe(struct usb_interface *usb_iface, goto error_alloc; } usb_hcd->wireless = 1; + usb_hcd->self.sg_tablesize = ~0; wusbhc = usb_hcd_to_wusbhc(usb_hcd); hwahc = container_of(wusbhc, struct hwahc, wusbhc); hwahc_init(hwahc); - result = hwahc_create(hwahc, usb_iface); + result = hwahc_create(hwahc, usb_iface, id->driver_info); if (result < 0) { dev_err(dev, "Cannot initialize internals: %d\n", result); goto error_hwahc_create; @@ -789,6 +826,7 @@ static int hwahc_probe(struct usb_interface *usb_iface, dev_err(dev, "Cannot add HCD: %d\n", result); goto error_add_hcd; } + device_wakeup_enable(usb_hcd->self.controller); result = wusbhc_b_create(&hwahc->wusbhc); if (result < 0) { dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result); @@ -823,6 +861,14 @@ static void hwahc_disconnect(struct usb_interface *usb_iface) } static struct usb_device_id hwahc_id_table[] = { + /* Alereon 5310 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01), + .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC | + WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS }, + /* Alereon 5611 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01), + .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC | + WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS }, /* FIXME: use class labels for this */ { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), }, {}, diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c index ec98ecee351..4f320d050da 100644 --- a/drivers/usb/host/imx21-dbg.c +++ b/drivers/usb/host/imx21-dbg.c @@ -18,6 +18,10 @@ /* this file is part of imx21-hcd.c */ +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif + #ifndef DEBUG static inline void create_debug_files(struct imx21 *imx21) { } diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index f0ebe8e7c58..207bad99301 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -62,6 +62,10 @@ #include "imx21-hcd.h" +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif + #ifdef DEBUG #define DEBUG_LOG_FRAME(imx21, etd, event) \ (etd)->event##_frame = readl((imx21)->regs + USBH_FRMNUB) @@ -809,26 +813,36 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd, /* calculate frame */ cur_frame = imx21_hc_get_frame(hcd); - if (urb->transfer_flags & URB_ISO_ASAP) { - if (list_empty(&ep_priv->td_list)) - urb->start_frame = cur_frame + 5; - else - urb->start_frame = list_entry( - ep_priv->td_list.prev, - struct td, list)->frame + urb->interval; - } - urb->start_frame = wrap_frame(urb->start_frame); - if (frame_after(cur_frame, urb->start_frame)) { - dev_dbg(imx21->dev, - "enqueue: adjusting iso start %d (cur=%d) asap=%d\n", - urb->start_frame, cur_frame, - (urb->transfer_flags & URB_ISO_ASAP) != 0); - urb->start_frame = wrap_frame(cur_frame + 1); + i = 0; + if (list_empty(&ep_priv->td_list)) { + urb->start_frame = wrap_frame(cur_frame + 5); + } else { + urb->start_frame = wrap_frame(list_entry(ep_priv->td_list.prev, + struct td, list)->frame + urb->interval); + + if (frame_after(cur_frame, urb->start_frame)) { + dev_dbg(imx21->dev, + "enqueue: adjusting iso start %d (cur=%d) asap=%d\n", + urb->start_frame, cur_frame, + (urb->transfer_flags & URB_ISO_ASAP) != 0); + i = DIV_ROUND_UP(wrap_frame( + cur_frame - urb->start_frame), + urb->interval); + + /* Treat underruns as if URB_ISO_ASAP was set */ + if ((urb->transfer_flags & URB_ISO_ASAP) || + i >= urb->number_of_packets) { + urb->start_frame = wrap_frame(urb->start_frame + + i * urb->interval); + i = 0; + } + } } /* set up transfers */ + urb_priv->isoc_remaining = urb->number_of_packets - i; td = urb_priv->isoc_td; - for (i = 0; i < urb->number_of_packets; i++, td++) { + for (; i < urb->number_of_packets; i++, td++) { unsigned int offset = urb->iso_frame_desc[i].offset; td->ep = ep; td->urb = urb; @@ -840,7 +854,6 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd, list_add_tail(&td->list, &ep_priv->td_list); } - urb_priv->isoc_remaining = urb->number_of_packets; dev_vdbg(imx21->dev, "setup %d packets for iso frame %d->%d\n", urb->number_of_packets, urb->start_frame, td->frame); @@ -1851,7 +1864,7 @@ static int imx21_probe(struct platform_device *pdev) imx21 = hcd_to_imx21(hcd); imx21->hcd = hcd; imx21->dev = &pdev->dev; - imx21->pdata = pdev->dev.platform_data; + imx21->pdata = dev_get_platdata(&pdev->dev); if (!imx21->pdata) imx21->pdata = &default_pdata; @@ -1897,6 +1910,7 @@ static int imx21_probe(struct platform_device *pdev) dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret); goto failed_add_hcd; } + device_wakeup_enable(hcd->self.controller); return 0; @@ -1917,7 +1931,7 @@ failed_request_mem: static struct platform_driver imx21_hcd_driver = { .driver = { - .name = (char *)hcd_name, + .name = hcd_name, }, .probe = imx21_probe, .remove = imx21_remove, diff --git a/drivers/usb/host/imx21-hcd.h b/drivers/usb/host/imx21-hcd.h index c005770a73e..05122f8a698 100644 --- a/drivers/usb/host/imx21-hcd.h +++ b/drivers/usb/host/imx21-hcd.h @@ -24,6 +24,10 @@ #ifndef __LINUX_IMX21_HCD_H__ #define __LINUX_IMX21_HCD_H__ +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif + #include <linux/platform_data/usb-mx2.h> #define NUM_ISO_ETDS 2 diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index b64e661618b..240e792c81a 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -60,7 +60,6 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/list.h> #include <linux/slab.h> #include <linux/usb.h> @@ -1626,7 +1625,7 @@ static int isp116x_probe(struct platform_device *pdev) isp116x->addr_reg = addr_reg; spin_lock_init(&isp116x->lock); INIT_LIST_HEAD(&isp116x->async); - isp116x->board = pdev->dev.platform_data; + isp116x->board = dev_get_platdata(&pdev->dev); if (!isp116x->board) { ERR("Platform data structure not initialized\n"); @@ -1645,6 +1644,8 @@ static int isp116x_probe(struct platform_device *pdev) if (ret) goto err6; + device_wakeup_enable(hcd->self.controller); + ret = create_debug_file(isp116x); if (ret) { ERR("Couldn't create debugfs entry\n"); @@ -1705,7 +1706,7 @@ static struct platform_driver isp116x_driver = { .suspend = isp116x_suspend, .resume = isp116x_resume, .driver = { - .name = (char *)hcd_name, + .name = hcd_name, .owner = THIS_MODULE, }, }; diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index 9a2c400e609..dd34b7a3396 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -325,11 +325,7 @@ struct isp116x_ep { /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "116x: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif +#define DBG(stuff...) pr_debug("116x: " stuff) #ifdef VERBOSE # define VDBG DBG @@ -358,15 +354,8 @@ struct isp116x_ep { #define isp116x_check_platform_delay(h) 0 #endif -#if defined(DEBUG) -#define IRQ_TEST() BUG_ON(!irqs_disabled()) -#else -#define IRQ_TEST() do{}while(0) -#endif - static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg) { - IRQ_TEST(); writew(reg & 0xff, isp116x->addr_reg); isp116x_delay(isp116x, 300); } diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index b04e8ece4d3..875bcfd3ec1 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -37,11 +37,7 @@ * recovery time (MSCx = 0x7f8c) with a memory clock of 99.53 MHz. */ -#ifdef CONFIG_USB_DEBUG -# define ISP1362_DEBUG -#else -# undef ISP1362_DEBUG -#endif +#undef ISP1362_DEBUG /* * The PXA255 UDC apparently doesn't handle GET_STATUS, GET_CONFIG and @@ -71,7 +67,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/list.h> #include <linux/interrupt.h> #include <linux/usb.h> @@ -82,6 +77,8 @@ #include <linux/io.h> #include <linux/bitmap.h> #include <linux/prefetch.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> #include <asm/irq.h> #include <asm/byteorder.h> @@ -92,7 +89,6 @@ static int dbg_level; module_param(dbg_level, int, 0644); #else module_param(dbg_level, int, 0); -#define STUB_DEBUG_FILE #endif #include "../core/usb.h" @@ -350,8 +346,6 @@ static void isp1362_write_ptd(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep struct ptd *ptd = &ep->ptd; int len = PTD_GET_DIR(ptd) == PTD_DIR_IN ? 0 : ep->length; - _BUG_ON(ep->ptd_offset < 0); - prefetch(ptd); isp1362_write_buffer(isp1362_hcd, ptd, ep->ptd_offset, PTD_HEADER_SIZE); if (len) @@ -1575,12 +1569,12 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, DBG(0, "ClearHubFeature: "); switch (wValue) { case C_HUB_OVER_CURRENT: - _DBG(0, "C_HUB_OVER_CURRENT\n"); + DBG(0, "C_HUB_OVER_CURRENT\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_OCIC); spin_unlock_irqrestore(&isp1362_hcd->lock, flags); case C_HUB_LOCAL_POWER: - _DBG(0, "C_HUB_LOCAL_POWER\n"); + DBG(0, "C_HUB_LOCAL_POWER\n"); break; default: goto error; @@ -1591,7 +1585,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: - _DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); + DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); break; default: goto error; @@ -1622,36 +1616,36 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case USB_PORT_FEAT_ENABLE: - _DBG(0, "USB_PORT_FEAT_ENABLE\n"); + DBG(0, "USB_PORT_FEAT_ENABLE\n"); tmp = RH_PS_CCS; break; case USB_PORT_FEAT_C_ENABLE: - _DBG(0, "USB_PORT_FEAT_C_ENABLE\n"); + DBG(0, "USB_PORT_FEAT_C_ENABLE\n"); tmp = RH_PS_PESC; break; case USB_PORT_FEAT_SUSPEND: - _DBG(0, "USB_PORT_FEAT_SUSPEND\n"); + DBG(0, "USB_PORT_FEAT_SUSPEND\n"); tmp = RH_PS_POCI; break; case USB_PORT_FEAT_C_SUSPEND: - _DBG(0, "USB_PORT_FEAT_C_SUSPEND\n"); + DBG(0, "USB_PORT_FEAT_C_SUSPEND\n"); tmp = RH_PS_PSSC; break; case USB_PORT_FEAT_POWER: - _DBG(0, "USB_PORT_FEAT_POWER\n"); + DBG(0, "USB_PORT_FEAT_POWER\n"); tmp = RH_PS_LSDA; break; case USB_PORT_FEAT_C_CONNECTION: - _DBG(0, "USB_PORT_FEAT_C_CONNECTION\n"); + DBG(0, "USB_PORT_FEAT_C_CONNECTION\n"); tmp = RH_PS_CSC; break; case USB_PORT_FEAT_C_OVER_CURRENT: - _DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n"); + DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n"); tmp = RH_PS_OCIC; break; case USB_PORT_FEAT_C_RESET: - _DBG(0, "USB_PORT_FEAT_C_RESET\n"); + DBG(0, "USB_PORT_FEAT_C_RESET\n"); tmp = RH_PS_PRSC; break; default: @@ -1671,7 +1665,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wIndex--; switch (wValue) { case USB_PORT_FEAT_SUSPEND: - _DBG(0, "USB_PORT_FEAT_SUSPEND\n"); + DBG(0, "USB_PORT_FEAT_SUSPEND\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PSS); isp1362_hcd->rhport[wIndex] = @@ -1679,7 +1673,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, spin_unlock_irqrestore(&isp1362_hcd->lock, flags); break; case USB_PORT_FEAT_POWER: - _DBG(0, "USB_PORT_FEAT_POWER\n"); + DBG(0, "USB_PORT_FEAT_POWER\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PPS); isp1362_hcd->rhport[wIndex] = @@ -1687,7 +1681,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, spin_unlock_irqrestore(&isp1362_hcd->lock, flags); break; case USB_PORT_FEAT_RESET: - _DBG(0, "USB_PORT_FEAT_RESET\n"); + DBG(0, "USB_PORT_FEAT_RESET\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); t1 = jiffies + msecs_to_jiffies(USB_RESET_WIDTH); @@ -1721,7 +1715,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: error: /* "protocol stall" on error */ - _DBG(0, "PROTOCOL STALL\n"); + DBG(0, "PROTOCOL STALL\n"); retval = -EPIPE; } @@ -1913,20 +1907,6 @@ static int isp1362_bus_resume(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILE - -static inline void create_debug_file(struct isp1362_hcd *isp1362_hcd) -{ -} -static inline void remove_debug_file(struct isp1362_hcd *isp1362_hcd) -{ -} - -#else - -#include <linux/proc_fs.h> -#include <linux/seq_file.h> - static void dump_irq(struct seq_file *s, char *label, u16 mask) { seq_printf(s, "%-15s %04x%s%s%s%s%s%s\n", label, mask, @@ -2069,7 +2049,7 @@ static void dump_regs(struct seq_file *s, struct isp1362_hcd *isp1362_hcd) isp1362_read_reg16(isp1362_hcd, HCATLDTCTO)); } -static int proc_isp1362_show(struct seq_file *s, void *unused) +static int isp1362_show(struct seq_file *s, void *unused) { struct isp1362_hcd *isp1362_hcd = s->private; struct isp1362_ep *ep; @@ -2127,7 +2107,7 @@ static int proc_isp1362_show(struct seq_file *s, void *unused) default: s = "?"; break; - }; + } s;}), ep->maxpacket) ; list_for_each_entry(urb, &ep->hep->urb_list, urb_list) { seq_printf(s, " urb%p, %d/%d\n", urb, @@ -2173,41 +2153,31 @@ static int proc_isp1362_show(struct seq_file *s, void *unused) return 0; } -static int proc_isp1362_open(struct inode *inode, struct file *file) +static int isp1362_open(struct inode *inode, struct file *file) { - return single_open(file, proc_isp1362_show, PDE_DATA(inode)); + return single_open(file, isp1362_show, inode); } -static const struct file_operations proc_ops = { - .open = proc_isp1362_open, +static const struct file_operations debug_ops = { + .open = isp1362_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; /* expect just one isp1362_hcd per system */ -static const char proc_filename[] = "driver/isp1362"; - static void create_debug_file(struct isp1362_hcd *isp1362_hcd) { - struct proc_dir_entry *pde; - - pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, isp1362_hcd); - if (pde == NULL) { - pr_warning("%s: Failed to create debug file '%s'\n", __func__, proc_filename); - return; - } - isp1362_hcd->pde = pde; + isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO, + usb_debug_root, + isp1362_hcd, &debug_ops); } static void remove_debug_file(struct isp1362_hcd *isp1362_hcd) { - if (isp1362_hcd->pde) - remove_proc_entry(proc_filename, NULL); + debugfs_remove(isp1362_hcd->debug_file); } -#endif - /*-------------------------------------------------------------------------*/ static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) @@ -2754,7 +2724,7 @@ static int isp1362_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isp1362_hcd->periodic); INIT_LIST_HEAD(&isp1362_hcd->isoc); INIT_LIST_HEAD(&isp1362_hcd->remove_list); - isp1362_hcd->board = pdev->dev.platform_data; + isp1362_hcd->board = dev_get_platdata(&pdev->dev); #if USE_PLATFORM_DELAY if (!isp1362_hcd->board->delay) { dev_err(hcd->self.controller, "No platform delay function given\n"); @@ -2775,6 +2745,8 @@ static int isp1362_probe(struct platform_device *pdev) retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_SHARED); if (retval != 0) goto err6; + device_wakeup_enable(hcd->self.controller); + pr_info("%s, irq %d\n", hcd->product_desc, irq); create_debug_file(isp1362_hcd); @@ -2858,7 +2830,7 @@ static struct platform_driver isp1362_driver = { .suspend = isp1362_suspend, .resume = isp1362_resume, .driver = { - .name = (char *)hcd_name, + .name = hcd_name, .owner = THIS_MODULE, }, }; diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index 0f97820e65b..3b0b4847c3a 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -76,14 +76,14 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len) #define ISP1362_REG_WRITE_OFFSET 0x80 -#ifdef ISP1362_DEBUG -typedef const unsigned int isp1362_reg_t; - #define REG_WIDTH_16 0x000 #define REG_WIDTH_32 0x100 #define REG_WIDTH_MASK 0x100 #define REG_NO_MASK 0x0ff +#ifdef ISP1362_DEBUG +typedef const unsigned int isp1362_reg_t; + #define REG_ACCESS_R 0x200 #define REG_ACCESS_W 0x400 #define REG_ACCESS_RW 0x600 @@ -91,9 +91,6 @@ typedef const unsigned int isp1362_reg_t; #define ISP1362_REG_NO(r) ((r) & REG_NO_MASK) -#define _BUG_ON(x) BUG_ON(x) -#define _WARN_ON(x) WARN_ON(x) - #define ISP1362_REG(name, addr, width, rw) \ static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw)) @@ -102,8 +99,6 @@ static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw)) #else typedef const unsigned char isp1362_reg_t; #define ISP1362_REG_NO(r) (r) -#define _BUG_ON(x) do {} while (0) -#define _WARN_ON(x) do {} while (0) #define ISP1362_REG(name, addr, width, rw) \ static isp1362_reg_t ISP1362_REG_##name = addr @@ -485,7 +480,7 @@ struct isp1362_hcd { struct isp1362_platform_data *board; - struct proc_dir_entry *pde; + struct dentry *debug_file; unsigned long stat1, stat2, stat4, stat8, stat16; /* HC registers */ @@ -587,21 +582,11 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd * ISP1362 HW Interface */ -#ifdef ISP1362_DEBUG #define DBG(level, fmt...) \ do { \ if (dbg_level > level) \ pr_debug(fmt); \ } while (0) -#define _DBG(level, fmt...) \ - do { \ - if (dbg_level > level) \ - printk(fmt); \ - } while (0) -#else -#define DBG(fmt...) do {} while (0) -#define _DBG DBG -#endif #ifdef VERBOSE # define VDBG(fmt...) DBG(3, fmt) @@ -645,9 +630,7 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd */ static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t reg) { - /*_BUG_ON((reg & ISP1362_REG_WRITE_OFFSET) && !(reg & REG_ACCESS_W));*/ REG_ACCESS_TEST(reg); - _BUG_ON(!irqs_disabled()); DUMMY_DELAY_ACCESS; writew(ISP1362_REG_NO(reg), isp1362_hcd->addr_reg); DUMMY_DELAY_ACCESS; @@ -656,7 +639,6 @@ static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t re static void isp1362_write_data16(struct isp1362_hcd *isp1362_hcd, u16 val) { - _BUG_ON(!irqs_disabled()); DUMMY_DELAY_ACCESS; writew(val, isp1362_hcd->data_reg); } @@ -665,7 +647,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd) { u16 val; - _BUG_ON(!irqs_disabled()); DUMMY_DELAY_ACCESS; val = readw(isp1362_hcd->data_reg); @@ -674,7 +655,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd) static void isp1362_write_data32(struct isp1362_hcd *isp1362_hcd, u32 val) { - _BUG_ON(!irqs_disabled()); #if USE_32BIT DUMMY_DELAY_ACCESS; writel(val, isp1362_hcd->data_reg); @@ -690,7 +670,6 @@ static u32 isp1362_read_data32(struct isp1362_hcd *isp1362_hcd) { u32 val; - _BUG_ON(!irqs_disabled()); #if USE_32BIT DUMMY_DELAY_ACCESS; val = readl(isp1362_hcd->data_reg); @@ -713,8 +692,6 @@ static void isp1362_read_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 le if (!len) return; - _BUG_ON(!irqs_disabled()); - RDBG("%s: Reading %d byte from fifo to mem @ %p\n", __func__, len, buf); #if USE_32BIT if (len >= 4) { @@ -760,8 +737,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l return; } - _BUG_ON(!irqs_disabled()); - RDBG("%s: Writing %d byte to fifo from memory @%p\n", __func__, len, buf); #if USE_32BIT if (len >= 4) { @@ -854,7 +829,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l isp1362_write_reg32(d, r, __v & ~m); \ } -#ifdef ISP1362_DEBUG #define isp1362_show_reg(d, r) { \ if ((ISP1362_REG_##r & REG_WIDTH_MASK) == REG_WIDTH_32) \ DBG(0, "%-12s[%02x]: %08x\n", #r, \ @@ -863,9 +837,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l DBG(0, "%-12s[%02x]: %04x\n", #r, \ ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r)); \ } -#else -#define isp1362_show_reg(d, r) do {} while (0) -#endif static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd) { @@ -923,10 +894,6 @@ static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *is static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len) { - _BUG_ON(offset & 1); - _BUG_ON(offset >= ISP1362_BUF_SIZE); - _BUG_ON(len > ISP1362_BUF_SIZE); - _BUG_ON(offset + len > ISP1362_BUF_SIZE); len = (len + 1) & ~1; isp1362_clr_mask16(isp1362_hcd, HCDMACFG, HCDMACFG_CTR_ENABLE); @@ -936,42 +903,32 @@ static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len) { - _BUG_ON(offset & 1); - isp1362_write_diraddr(isp1362_hcd, offset, len); DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n", __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA); isp1362_read_fifo(isp1362_hcd, buf, len); - _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); } static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len) { - _BUG_ON(offset & 1); - isp1362_write_diraddr(isp1362_hcd, offset, len); DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n", __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA | ISP1362_REG_WRITE_OFFSET); isp1362_write_fifo(isp1362_hcd, buf, len); - _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); } static void __attribute__((unused)) dump_data(char *buf, int len) @@ -1002,7 +959,7 @@ static void __attribute__((unused)) dump_data(char *buf, int len) } } -#if defined(ISP1362_DEBUG) && defined(PTD_TRACE) +#if defined(PTD_TRACE) static void dump_ptd(struct ptd *ptd) { diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 2facee53eab..51a0ae9cdd1 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -2250,6 +2250,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, ret = usb_add_hcd(hcd, irq, irqflags); if (ret) goto err_unmap; + device_wakeup_enable(hcd->self.controller); return hcd; diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index a13709ee4e5..df931e9ba5b 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -118,7 +118,7 @@ static int of_isp1760_probe(struct platform_device *dev) goto free_gpio; } - dev_set_drvdata(&dev->dev, drvdata); + platform_set_drvdata(dev, drvdata); return ret; free_gpio: @@ -133,9 +133,7 @@ free_data: static int of_isp1760_remove(struct platform_device *dev) { - struct isp1760 *drvdata = dev_get_drvdata(&dev->dev); - - dev_set_drvdata(&dev->dev, NULL); + struct isp1760 *drvdata = platform_get_drvdata(dev); usb_remove_hcd(drvdata->hcd); iounmap(drvdata->hcd->regs); @@ -353,7 +351,7 @@ static int isp1760_plat_probe(struct platform_device *pdev) struct resource *mem_res; struct resource *irq_res; resource_size_t mem_size; - struct isp1760_platform_data *priv = pdev->dev.platform_data; + struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev); unsigned int devflags = 0; unsigned long irqflags = IRQF_SHARED; @@ -398,7 +396,7 @@ static int isp1760_plat_probe(struct platform_device *pdev) irqflags, -ENOENT, &pdev->dev, dev_name(&pdev->dev), devflags); - dev_set_drvdata(&pdev->dev, hcd); + platform_set_drvdata(pdev, hcd); if (IS_ERR(hcd)) { pr_warning("isp1760: Failed to register the HCD device\n"); @@ -419,7 +417,7 @@ static int isp1760_plat_remove(struct platform_device *pdev) { struct resource *mem_res; resource_size_t mem_size; - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c new file mode 100644 index 00000000000..858efcfda50 --- /dev/null +++ b/drivers/usb/host/max3421-hcd.c @@ -0,0 +1,1957 @@ +/* + * MAX3421 Host Controller driver for USB. + * + * Author: David Mosberger-Tang <davidm@egauge.net> + * + * (C) Copyright 2014 David Mosberger-Tang <davidm@egauge.net> + * + * MAX3421 is a chip implementing a USB 2.0 Full-/Low-Speed host + * controller on a SPI bus. + * + * Based on: + * o MAX3421E datasheet + * http://datasheets.maximintegrated.com/en/ds/MAX3421E.pdf + * o MAX3421E Programming Guide + * http://www.hdl.co.jp/ftpdata/utl-001/AN3785.pdf + * o gadget/dummy_hcd.c + * For USB HCD implementation. + * o Arduino MAX3421 driver + * https://github.com/felis/USB_Host_Shield_2.0/blob/master/Usb.cpp + * + * This file is licenced under the GPL v2. + * + * Important note on worst-case (full-speed) packet size constraints + * (See USB 2.0 Section 5.6.3 and following): + * + * - control: 64 bytes + * - isochronous: 1023 bytes + * - interrupt: 64 bytes + * - bulk: 64 bytes + * + * Since the MAX3421 FIFO size is 64 bytes, we do not have to work about + * multi-FIFO writes/reads for a single USB packet *except* for isochronous + * transfers. We don't support isochronous transfers at this time, so we + * just assume that a USB packet always fits into a single FIFO buffer. + * + * NOTE: The June 2006 version of "MAX3421E Programming Guide" + * (AN3785) has conflicting info for the RCVDAVIRQ bit: + * + * The description of RCVDAVIRQ says "The CPU *must* clear + * this IRQ bit (by writing a 1 to it) before reading the + * RCVFIFO data. + * + * However, the earlier section on "Programming BULK-IN + * Transfers" says * that: + * + * After the CPU retrieves the data, it clears the + * RCVDAVIRQ bit. + * + * The December 2006 version has been corrected and it consistently + * states the second behavior is the correct one. + * + * Synchronous SPI transactions sleep so we can't perform any such + * transactions while holding a spin-lock (and/or while interrupts are + * masked). To achieve this, all SPI transactions are issued from a + * single thread (max3421_spi_thread). + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include <linux/platform_data/max3421-hcd.h> + +#define DRIVER_DESC "MAX3421 USB Host-Controller Driver" +#define DRIVER_VERSION "1.0" + +/* 11-bit counter that wraps around (USB 2.0 Section 8.3.3): */ +#define USB_MAX_FRAME_NUMBER 0x7ff +#define USB_MAX_RETRIES 3 /* # of retries before error is reported */ + +/* + * Max. # of times we're willing to retransmit a request immediately in + * resposne to a NAK. Afterwards, we fall back on trying once a frame. + */ +#define NAK_MAX_FAST_RETRANSMITS 2 + +#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ + +/* Port-change mask: */ +#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | \ + USB_PORT_STAT_C_ENABLE | \ + USB_PORT_STAT_C_SUSPEND | \ + USB_PORT_STAT_C_OVERCURRENT | \ + USB_PORT_STAT_C_RESET) << 16) + +enum max3421_rh_state { + MAX3421_RH_RESET, + MAX3421_RH_SUSPENDED, + MAX3421_RH_RUNNING +}; + +enum pkt_state { + PKT_STATE_SETUP, /* waiting to send setup packet to ctrl pipe */ + PKT_STATE_TRANSFER, /* waiting to xfer transfer_buffer */ + PKT_STATE_TERMINATE /* waiting to terminate control transfer */ +}; + +enum scheduling_pass { + SCHED_PASS_PERIODIC, + SCHED_PASS_NON_PERIODIC, + SCHED_PASS_DONE +}; + +struct max3421_dma_buf { + u8 data[2]; +}; + +struct max3421_hcd { + spinlock_t lock; + + struct task_struct *spi_thread; + + struct max3421_hcd *next; + + enum max3421_rh_state rh_state; + /* lower 16 bits contain port status, upper 16 bits the change mask: */ + u32 port_status; + + unsigned active:1; + + struct list_head ep_list; /* list of EP's with work */ + + /* + * The following are owned by spi_thread (may be accessed by + * SPI-thread without acquiring the HCD lock: + */ + u8 rev; /* chip revision */ + u16 frame_number; + /* + * kmalloc'd buffers guaranteed to be in separate (DMA) + * cache-lines: + */ + struct max3421_dma_buf *tx; + struct max3421_dma_buf *rx; + /* + * URB we're currently processing. Must not be reset to NULL + * unless MAX3421E chip is idle: + */ + struct urb *curr_urb; + enum scheduling_pass sched_pass; + struct usb_device *loaded_dev; /* dev that's loaded into the chip */ + int loaded_epnum; /* epnum whose toggles are loaded */ + int urb_done; /* > 0 -> no errors, < 0: errno */ + size_t curr_len; + u8 hien; + u8 mode; + u8 iopins[2]; + unsigned int do_enable_irq:1; + unsigned int do_reset_hcd:1; + unsigned int do_reset_port:1; + unsigned int do_check_unlink:1; + unsigned int do_iopin_update:1; +#ifdef DEBUG + unsigned long err_stat[16]; +#endif +}; + +struct max3421_ep { + struct usb_host_endpoint *ep; + struct list_head ep_list; + u32 naks; + u16 last_active; /* frame # this ep was last active */ + enum pkt_state pkt_state; + u8 retries; + u8 retransmit; /* packet needs retransmission */ +}; + +static struct max3421_hcd *max3421_hcd_list; + +#define MAX3421_FIFO_SIZE 64 + +#define MAX3421_SPI_DIR_RD 0 /* read register from MAX3421 */ +#define MAX3421_SPI_DIR_WR 1 /* write register to MAX3421 */ + +/* SPI commands: */ +#define MAX3421_SPI_DIR_SHIFT 1 +#define MAX3421_SPI_REG_SHIFT 3 + +#define MAX3421_REG_RCVFIFO 1 +#define MAX3421_REG_SNDFIFO 2 +#define MAX3421_REG_SUDFIFO 4 +#define MAX3421_REG_RCVBC 6 +#define MAX3421_REG_SNDBC 7 +#define MAX3421_REG_USBIRQ 13 +#define MAX3421_REG_USBIEN 14 +#define MAX3421_REG_USBCTL 15 +#define MAX3421_REG_CPUCTL 16 +#define MAX3421_REG_PINCTL 17 +#define MAX3421_REG_REVISION 18 +#define MAX3421_REG_IOPINS1 20 +#define MAX3421_REG_IOPINS2 21 +#define MAX3421_REG_GPINIRQ 22 +#define MAX3421_REG_GPINIEN 23 +#define MAX3421_REG_GPINPOL 24 +#define MAX3421_REG_HIRQ 25 +#define MAX3421_REG_HIEN 26 +#define MAX3421_REG_MODE 27 +#define MAX3421_REG_PERADDR 28 +#define MAX3421_REG_HCTL 29 +#define MAX3421_REG_HXFR 30 +#define MAX3421_REG_HRSL 31 + +enum { + MAX3421_USBIRQ_OSCOKIRQ_BIT = 0, + MAX3421_USBIRQ_NOVBUSIRQ_BIT = 5, + MAX3421_USBIRQ_VBUSIRQ_BIT +}; + +enum { + MAX3421_CPUCTL_IE_BIT = 0, + MAX3421_CPUCTL_PULSEWID0_BIT = 6, + MAX3421_CPUCTL_PULSEWID1_BIT +}; + +enum { + MAX3421_USBCTL_PWRDOWN_BIT = 4, + MAX3421_USBCTL_CHIPRES_BIT +}; + +enum { + MAX3421_PINCTL_GPXA_BIT = 0, + MAX3421_PINCTL_GPXB_BIT, + MAX3421_PINCTL_POSINT_BIT, + MAX3421_PINCTL_INTLEVEL_BIT, + MAX3421_PINCTL_FDUPSPI_BIT, + MAX3421_PINCTL_EP0INAK_BIT, + MAX3421_PINCTL_EP2INAK_BIT, + MAX3421_PINCTL_EP3INAK_BIT, +}; + +enum { + MAX3421_HI_BUSEVENT_BIT = 0, /* bus-reset/-resume */ + MAX3421_HI_RWU_BIT, /* remote wakeup */ + MAX3421_HI_RCVDAV_BIT, /* receive FIFO data available */ + MAX3421_HI_SNDBAV_BIT, /* send buffer available */ + MAX3421_HI_SUSDN_BIT, /* suspend operation done */ + MAX3421_HI_CONDET_BIT, /* peripheral connect/disconnect */ + MAX3421_HI_FRAME_BIT, /* frame generator */ + MAX3421_HI_HXFRDN_BIT, /* host transfer done */ +}; + +enum { + MAX3421_HCTL_BUSRST_BIT = 0, + MAX3421_HCTL_FRMRST_BIT, + MAX3421_HCTL_SAMPLEBUS_BIT, + MAX3421_HCTL_SIGRSM_BIT, + MAX3421_HCTL_RCVTOG0_BIT, + MAX3421_HCTL_RCVTOG1_BIT, + MAX3421_HCTL_SNDTOG0_BIT, + MAX3421_HCTL_SNDTOG1_BIT +}; + +enum { + MAX3421_MODE_HOST_BIT = 0, + MAX3421_MODE_LOWSPEED_BIT, + MAX3421_MODE_HUBPRE_BIT, + MAX3421_MODE_SOFKAENAB_BIT, + MAX3421_MODE_SEPIRQ_BIT, + MAX3421_MODE_DELAYISO_BIT, + MAX3421_MODE_DMPULLDN_BIT, + MAX3421_MODE_DPPULLDN_BIT +}; + +enum { + MAX3421_HRSL_OK = 0, + MAX3421_HRSL_BUSY, + MAX3421_HRSL_BADREQ, + MAX3421_HRSL_UNDEF, + MAX3421_HRSL_NAK, + MAX3421_HRSL_STALL, + MAX3421_HRSL_TOGERR, + MAX3421_HRSL_WRONGPID, + MAX3421_HRSL_BADBC, + MAX3421_HRSL_PIDERR, + MAX3421_HRSL_PKTERR, + MAX3421_HRSL_CRCERR, + MAX3421_HRSL_KERR, + MAX3421_HRSL_JERR, + MAX3421_HRSL_TIMEOUT, + MAX3421_HRSL_BABBLE, + MAX3421_HRSL_RESULT_MASK = 0xf, + MAX3421_HRSL_RCVTOGRD_BIT = 4, + MAX3421_HRSL_SNDTOGRD_BIT, + MAX3421_HRSL_KSTATUS_BIT, + MAX3421_HRSL_JSTATUS_BIT +}; + +/* Return same error-codes as ohci.h:cc_to_error: */ +static const int hrsl_to_error[] = { + [MAX3421_HRSL_OK] = 0, + [MAX3421_HRSL_BUSY] = -EINVAL, + [MAX3421_HRSL_BADREQ] = -EINVAL, + [MAX3421_HRSL_UNDEF] = -EINVAL, + [MAX3421_HRSL_NAK] = -EAGAIN, + [MAX3421_HRSL_STALL] = -EPIPE, + [MAX3421_HRSL_TOGERR] = -EILSEQ, + [MAX3421_HRSL_WRONGPID] = -EPROTO, + [MAX3421_HRSL_BADBC] = -EREMOTEIO, + [MAX3421_HRSL_PIDERR] = -EPROTO, + [MAX3421_HRSL_PKTERR] = -EPROTO, + [MAX3421_HRSL_CRCERR] = -EILSEQ, + [MAX3421_HRSL_KERR] = -EIO, + [MAX3421_HRSL_JERR] = -EIO, + [MAX3421_HRSL_TIMEOUT] = -ETIME, + [MAX3421_HRSL_BABBLE] = -EOVERFLOW +}; + +/* + * See http://www.beyondlogic.org/usbnutshell/usb4.shtml#Control for a + * reasonable overview of how control transfers use the the IN/OUT + * tokens. + */ +#define MAX3421_HXFR_BULK_IN(ep) (0x00 | (ep)) /* bulk or interrupt */ +#define MAX3421_HXFR_SETUP 0x10 +#define MAX3421_HXFR_BULK_OUT(ep) (0x20 | (ep)) /* bulk or interrupt */ +#define MAX3421_HXFR_ISO_IN(ep) (0x40 | (ep)) +#define MAX3421_HXFR_ISO_OUT(ep) (0x60 | (ep)) +#define MAX3421_HXFR_HS_IN 0x80 /* handshake in */ +#define MAX3421_HXFR_HS_OUT 0xa0 /* handshake out */ + +#define field(val, bit) ((val) << (bit)) + +static inline s16 +frame_diff(u16 left, u16 right) +{ + return ((unsigned) (left - right)) % (USB_MAX_FRAME_NUMBER + 1); +} + +static inline struct max3421_hcd * +hcd_to_max3421(struct usb_hcd *hcd) +{ + return (struct max3421_hcd *) hcd->hcd_priv; +} + +static inline struct usb_hcd * +max3421_to_hcd(struct max3421_hcd *max3421_hcd) +{ + return container_of((void *) max3421_hcd, struct usb_hcd, hcd_priv); +} + +static u8 +spi_rd8(struct usb_hcd *hcd, unsigned int reg) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct spi_transfer transfer; + struct spi_message msg; + + memset(&transfer, 0, sizeof(transfer)); + + spi_message_init(&msg); + + max3421_hcd->tx->data[0] = + (field(reg, MAX3421_SPI_REG_SHIFT) | + field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT)); + + transfer.tx_buf = max3421_hcd->tx->data; + transfer.rx_buf = max3421_hcd->rx->data; + transfer.len = 2; + + spi_message_add_tail(&transfer, &msg); + spi_sync(spi, &msg); + + return max3421_hcd->rx->data[1]; +} + +static void +spi_wr8(struct usb_hcd *hcd, unsigned int reg, u8 val) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct spi_transfer transfer; + struct spi_message msg; + + memset(&transfer, 0, sizeof(transfer)); + + spi_message_init(&msg); + + max3421_hcd->tx->data[0] = + (field(reg, MAX3421_SPI_REG_SHIFT) | + field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT)); + max3421_hcd->tx->data[1] = val; + + transfer.tx_buf = max3421_hcd->tx->data; + transfer.len = 2; + + spi_message_add_tail(&transfer, &msg); + spi_sync(spi, &msg); +} + +static void +spi_rd_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct spi_transfer transfer[2]; + struct spi_message msg; + + memset(transfer, 0, sizeof(transfer)); + + spi_message_init(&msg); + + max3421_hcd->tx->data[0] = + (field(reg, MAX3421_SPI_REG_SHIFT) | + field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT)); + transfer[0].tx_buf = max3421_hcd->tx->data; + transfer[0].len = 1; + + transfer[1].rx_buf = buf; + transfer[1].len = len; + + spi_message_add_tail(&transfer[0], &msg); + spi_message_add_tail(&transfer[1], &msg); + spi_sync(spi, &msg); +} + +static void +spi_wr_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct spi_transfer transfer[2]; + struct spi_message msg; + + memset(transfer, 0, sizeof(transfer)); + + spi_message_init(&msg); + + max3421_hcd->tx->data[0] = + (field(reg, MAX3421_SPI_REG_SHIFT) | + field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT)); + + transfer[0].tx_buf = max3421_hcd->tx->data; + transfer[0].len = 1; + + transfer[1].tx_buf = buf; + transfer[1].len = len; + + spi_message_add_tail(&transfer[0], &msg); + spi_message_add_tail(&transfer[1], &msg); + spi_sync(spi, &msg); +} + +/* + * Figure out the correct setting for the LOWSPEED and HUBPRE mode + * bits. The HUBPRE bit needs to be set when MAX3421E operates at + * full speed, but it's talking to a low-speed device (i.e., through a + * hub). Setting that bit ensures that every low-speed packet is + * preceded by a full-speed PRE PID. Possible configurations: + * + * Hub speed: Device speed: => LOWSPEED bit: HUBPRE bit: + * FULL FULL => 0 0 + * FULL LOW => 1 1 + * LOW LOW => 1 0 + * LOW FULL => 1 0 + */ +static void +max3421_set_speed(struct usb_hcd *hcd, struct usb_device *dev) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + u8 mode_lowspeed, mode_hubpre, mode = max3421_hcd->mode; + + mode_lowspeed = BIT(MAX3421_MODE_LOWSPEED_BIT); + mode_hubpre = BIT(MAX3421_MODE_HUBPRE_BIT); + if (max3421_hcd->port_status & USB_PORT_STAT_LOW_SPEED) { + mode |= mode_lowspeed; + mode &= ~mode_hubpre; + } else if (dev->speed == USB_SPEED_LOW) { + mode |= mode_lowspeed | mode_hubpre; + } else { + mode &= ~(mode_lowspeed | mode_hubpre); + } + if (mode != max3421_hcd->mode) { + max3421_hcd->mode = mode; + spi_wr8(hcd, MAX3421_REG_MODE, max3421_hcd->mode); + } + +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_set_address(struct usb_hcd *hcd, struct usb_device *dev, int epnum, + int force_toggles) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + int old_epnum, same_ep, rcvtog, sndtog; + struct usb_device *old_dev; + u8 hctl; + + old_dev = max3421_hcd->loaded_dev; + old_epnum = max3421_hcd->loaded_epnum; + + same_ep = (dev == old_dev && epnum == old_epnum); + if (same_ep && !force_toggles) + return; + + if (old_dev && !same_ep) { + /* save the old end-points toggles: */ + u8 hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); + + rcvtog = (hrsl >> MAX3421_HRSL_RCVTOGRD_BIT) & 1; + sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1; + + /* no locking: HCD (i.e., we) own toggles, don't we? */ + usb_settoggle(old_dev, old_epnum, 0, rcvtog); + usb_settoggle(old_dev, old_epnum, 1, sndtog); + } + /* setup new endpoint's toggle bits: */ + rcvtog = usb_gettoggle(dev, epnum, 0); + sndtog = usb_gettoggle(dev, epnum, 1); + hctl = (BIT(rcvtog + MAX3421_HCTL_RCVTOG0_BIT) | + BIT(sndtog + MAX3421_HCTL_SNDTOG0_BIT)); + + max3421_hcd->loaded_epnum = epnum; + spi_wr8(hcd, MAX3421_REG_HCTL, hctl); + + /* + * Note: devnum for one and the same device can change during + * address-assignment so it's best to just always load the + * address whenever the end-point changed/was forced. + */ + max3421_hcd->loaded_dev = dev; + spi_wr8(hcd, MAX3421_REG_PERADDR, dev->devnum); +} + +static int +max3421_ctrl_setup(struct usb_hcd *hcd, struct urb *urb) +{ + spi_wr_buf(hcd, MAX3421_REG_SUDFIFO, urb->setup_packet, 8); + return MAX3421_HXFR_SETUP; +} + +static int +max3421_transfer_in(struct usb_hcd *hcd, struct urb *urb) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + int epnum = usb_pipeendpoint(urb->pipe); + + max3421_hcd->curr_len = 0; + max3421_hcd->hien |= BIT(MAX3421_HI_RCVDAV_BIT); + return MAX3421_HXFR_BULK_IN(epnum); +} + +static int +max3421_transfer_out(struct usb_hcd *hcd, struct urb *urb, int fast_retransmit) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + int epnum = usb_pipeendpoint(urb->pipe); + u32 max_packet; + void *src; + + src = urb->transfer_buffer + urb->actual_length; + + if (fast_retransmit) { + if (max3421_hcd->rev == 0x12) { + /* work around rev 0x12 bug: */ + spi_wr8(hcd, MAX3421_REG_SNDBC, 0); + spi_wr8(hcd, MAX3421_REG_SNDFIFO, ((u8 *) src)[0]); + spi_wr8(hcd, MAX3421_REG_SNDBC, max3421_hcd->curr_len); + } + return MAX3421_HXFR_BULK_OUT(epnum); + } + + max_packet = usb_maxpacket(urb->dev, urb->pipe, 1); + + if (max_packet > MAX3421_FIFO_SIZE) { + /* + * We do not support isochronous transfers at this + * time. + */ + dev_err(&spi->dev, + "%s: packet-size of %u too big (limit is %u bytes)", + __func__, max_packet, MAX3421_FIFO_SIZE); + max3421_hcd->urb_done = -EMSGSIZE; + return -EMSGSIZE; + } + max3421_hcd->curr_len = min((urb->transfer_buffer_length - + urb->actual_length), max_packet); + + spi_wr_buf(hcd, MAX3421_REG_SNDFIFO, src, max3421_hcd->curr_len); + spi_wr8(hcd, MAX3421_REG_SNDBC, max3421_hcd->curr_len); + return MAX3421_HXFR_BULK_OUT(epnum); +} + +/* + * Issue the next host-transfer command. + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_next_transfer(struct usb_hcd *hcd, int fast_retransmit) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct urb *urb = max3421_hcd->curr_urb; + struct max3421_ep *max3421_ep; + int cmd = -EINVAL; + + if (!urb) + return; /* nothing to do */ + + max3421_ep = urb->ep->hcpriv; + + switch (max3421_ep->pkt_state) { + case PKT_STATE_SETUP: + cmd = max3421_ctrl_setup(hcd, urb); + break; + + case PKT_STATE_TRANSFER: + if (usb_urb_dir_in(urb)) + cmd = max3421_transfer_in(hcd, urb); + else + cmd = max3421_transfer_out(hcd, urb, fast_retransmit); + break; + + case PKT_STATE_TERMINATE: + /* + * IN transfers are terminated with HS_OUT token, + * OUT transfers with HS_IN: + */ + if (usb_urb_dir_in(urb)) + cmd = MAX3421_HXFR_HS_OUT; + else + cmd = MAX3421_HXFR_HS_IN; + break; + } + + if (cmd < 0) + return; + + /* issue the command and wait for host-xfer-done interrupt: */ + + spi_wr8(hcd, MAX3421_REG_HXFR, cmd); + max3421_hcd->hien |= BIT(MAX3421_HI_HXFRDN_BIT); +} + +/* + * Find the next URB to process and start its execution. + * + * At this time, we do not anticipate ever connecting a USB hub to the + * MAX3421 chip, so at most USB device can be connected and we can use + * a simplistic scheduler: at the start of a frame, schedule all + * periodic transfers. Once that is done, use the remainder of the + * frame to process non-periodic (bulk & control) transfers. + * + * Preconditions: + * o Caller must NOT hold HCD spinlock. + * o max3421_hcd->curr_urb MUST BE NULL. + * o MAX3421E chip must be idle. + */ +static int +max3421_select_and_start_urb(struct usb_hcd *hcd) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct urb *urb, *curr_urb = NULL; + struct max3421_ep *max3421_ep; + int epnum, force_toggles = 0; + struct usb_host_endpoint *ep; + struct list_head *pos; + unsigned long flags; + + spin_lock_irqsave(&max3421_hcd->lock, flags); + + for (; + max3421_hcd->sched_pass < SCHED_PASS_DONE; + ++max3421_hcd->sched_pass) + list_for_each(pos, &max3421_hcd->ep_list) { + urb = NULL; + max3421_ep = container_of(pos, struct max3421_ep, + ep_list); + ep = max3421_ep->ep; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: + if (max3421_hcd->sched_pass != + SCHED_PASS_PERIODIC) + continue; + break; + + case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_BULK: + if (max3421_hcd->sched_pass != + SCHED_PASS_NON_PERIODIC) + continue; + break; + } + + if (list_empty(&ep->urb_list)) + continue; /* nothing to do */ + urb = list_first_entry(&ep->urb_list, struct urb, + urb_list); + if (urb->unlinked) { + dev_dbg(&spi->dev, "%s: URB %p unlinked=%d", + __func__, urb, urb->unlinked); + max3421_hcd->curr_urb = urb; + max3421_hcd->urb_done = 1; + spin_unlock_irqrestore(&max3421_hcd->lock, + flags); + return 1; + } + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + /* + * Allow one control transaction per + * frame per endpoint: + */ + if (frame_diff(max3421_ep->last_active, + max3421_hcd->frame_number) == 0) + continue; + break; + + case USB_ENDPOINT_XFER_BULK: + if (max3421_ep->retransmit + && (frame_diff(max3421_ep->last_active, + max3421_hcd->frame_number) + == 0)) + /* + * We already tried this EP + * during this frame and got a + * NAK or error; wait for next frame + */ + continue; + break; + + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: + if (frame_diff(max3421_hcd->frame_number, + max3421_ep->last_active) + < urb->interval) + /* + * We already processed this + * end-point in the current + * frame + */ + continue; + break; + } + + /* move current ep to tail: */ + list_move_tail(pos, &max3421_hcd->ep_list); + curr_urb = urb; + goto done; + } +done: + if (!curr_urb) { + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + return 0; + } + + urb = max3421_hcd->curr_urb = curr_urb; + epnum = usb_endpoint_num(&urb->ep->desc); + if (max3421_ep->retransmit) + /* restart (part of) a USB transaction: */ + max3421_ep->retransmit = 0; + else { + /* start USB transaction: */ + if (usb_endpoint_xfer_control(&ep->desc)) { + /* + * See USB 2.0 spec section 8.6.1 + * Initialization via SETUP Token: + */ + usb_settoggle(urb->dev, epnum, 0, 1); + usb_settoggle(urb->dev, epnum, 1, 1); + max3421_ep->pkt_state = PKT_STATE_SETUP; + force_toggles = 1; + } else + max3421_ep->pkt_state = PKT_STATE_TRANSFER; + } + + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + + max3421_ep->last_active = max3421_hcd->frame_number; + max3421_set_address(hcd, urb->dev, epnum, force_toggles); + max3421_set_speed(hcd, urb->dev); + max3421_next_transfer(hcd, 0); + return 1; +} + +/* + * Check all endpoints for URBs that got unlinked. + * + * Caller must NOT hold HCD spinlock. + */ +static int +max3421_check_unlink(struct usb_hcd *hcd) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct list_head *pos, *upos, *next_upos; + struct max3421_ep *max3421_ep; + struct usb_host_endpoint *ep; + struct urb *urb; + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&max3421_hcd->lock, flags); + list_for_each(pos, &max3421_hcd->ep_list) { + max3421_ep = container_of(pos, struct max3421_ep, ep_list); + ep = max3421_ep->ep; + list_for_each_safe(upos, next_upos, &ep->urb_list) { + urb = container_of(upos, struct urb, urb_list); + if (urb->unlinked) { + retval = 1; + dev_dbg(&spi->dev, "%s: URB %p unlinked=%d", + __func__, urb, urb->unlinked); + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock_irqrestore(&max3421_hcd->lock, + flags); + usb_hcd_giveback_urb(hcd, urb, 0); + spin_lock_irqsave(&max3421_hcd->lock, flags); + } + } + } + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + return retval; +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_slow_retransmit(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct urb *urb = max3421_hcd->curr_urb; + struct max3421_ep *max3421_ep; + + max3421_ep = urb->ep->hcpriv; + max3421_ep->retransmit = 1; + max3421_hcd->curr_urb = NULL; +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_recv_data_available(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct urb *urb = max3421_hcd->curr_urb; + size_t remaining, transfer_size; + u8 rcvbc; + + rcvbc = spi_rd8(hcd, MAX3421_REG_RCVBC); + + if (rcvbc > MAX3421_FIFO_SIZE) + rcvbc = MAX3421_FIFO_SIZE; + if (urb->actual_length >= urb->transfer_buffer_length) + remaining = 0; + else + remaining = urb->transfer_buffer_length - urb->actual_length; + transfer_size = rcvbc; + if (transfer_size > remaining) + transfer_size = remaining; + if (transfer_size > 0) { + void *dst = urb->transfer_buffer + urb->actual_length; + + spi_rd_buf(hcd, MAX3421_REG_RCVFIFO, dst, transfer_size); + urb->actual_length += transfer_size; + max3421_hcd->curr_len = transfer_size; + } + + /* ack the RCVDAV irq now that the FIFO has been read: */ + spi_wr8(hcd, MAX3421_REG_HIRQ, BIT(MAX3421_HI_RCVDAV_BIT)); +} + +static void +max3421_handle_error(struct usb_hcd *hcd, u8 hrsl) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + u8 result_code = hrsl & MAX3421_HRSL_RESULT_MASK; + struct urb *urb = max3421_hcd->curr_urb; + struct max3421_ep *max3421_ep = urb->ep->hcpriv; + int switch_sndfifo; + + /* + * If an OUT command results in any response other than OK + * (i.e., error or NAK), we have to perform a dummy-write to + * SNDBC so the FIFO gets switched back to us. Otherwise, we + * get out of sync with the SNDFIFO double buffer. + */ + switch_sndfifo = (max3421_ep->pkt_state == PKT_STATE_TRANSFER && + usb_urb_dir_out(urb)); + + switch (result_code) { + case MAX3421_HRSL_OK: + return; /* this shouldn't happen */ + + case MAX3421_HRSL_WRONGPID: /* received wrong PID */ + case MAX3421_HRSL_BUSY: /* SIE busy */ + case MAX3421_HRSL_BADREQ: /* bad val in HXFR */ + case MAX3421_HRSL_UNDEF: /* reserved */ + case MAX3421_HRSL_KERR: /* K-state instead of response */ + case MAX3421_HRSL_JERR: /* J-state instead of response */ + /* + * packet experienced an error that we cannot recover + * from; report error + */ + max3421_hcd->urb_done = hrsl_to_error[result_code]; + dev_dbg(&spi->dev, "%s: unexpected error HRSL=0x%02x", + __func__, hrsl); + break; + + case MAX3421_HRSL_TOGERR: + if (usb_urb_dir_in(urb)) + ; /* don't do anything (device will switch toggle) */ + else { + /* flip the send toggle bit: */ + int sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1; + + sndtog ^= 1; + spi_wr8(hcd, MAX3421_REG_HCTL, + BIT(sndtog + MAX3421_HCTL_SNDTOG0_BIT)); + } + /* FALL THROUGH */ + case MAX3421_HRSL_BADBC: /* bad byte count */ + case MAX3421_HRSL_PIDERR: /* received PID is corrupted */ + case MAX3421_HRSL_PKTERR: /* packet error (stuff, EOP) */ + case MAX3421_HRSL_CRCERR: /* CRC error */ + case MAX3421_HRSL_BABBLE: /* device talked too long */ + case MAX3421_HRSL_TIMEOUT: + if (max3421_ep->retries++ < USB_MAX_RETRIES) + /* retry the packet again in the next frame */ + max3421_slow_retransmit(hcd); + else { + /* Based on ohci.h cc_to_err[]: */ + max3421_hcd->urb_done = hrsl_to_error[result_code]; + dev_dbg(&spi->dev, "%s: unexpected error HRSL=0x%02x", + __func__, hrsl); + } + break; + + case MAX3421_HRSL_STALL: + dev_dbg(&spi->dev, "%s: unexpected error HRSL=0x%02x", + __func__, hrsl); + max3421_hcd->urb_done = hrsl_to_error[result_code]; + break; + + case MAX3421_HRSL_NAK: + /* + * Device wasn't ready for data or has no data + * available: retry the packet again. + */ + if (max3421_ep->naks++ < NAK_MAX_FAST_RETRANSMITS) { + max3421_next_transfer(hcd, 1); + switch_sndfifo = 0; + } else + max3421_slow_retransmit(hcd); + break; + } + if (switch_sndfifo) + spi_wr8(hcd, MAX3421_REG_SNDBC, 0); +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static int +max3421_transfer_in_done(struct usb_hcd *hcd, struct urb *urb) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + u32 max_packet; + + if (urb->actual_length >= urb->transfer_buffer_length) + return 1; /* read is complete, so we're done */ + + /* + * USB 2.0 Section 5.3.2 Pipes: packets must be full size + * except for last one. + */ + max_packet = usb_maxpacket(urb->dev, urb->pipe, 0); + if (max_packet > MAX3421_FIFO_SIZE) { + /* + * We do not support isochronous transfers at this + * time... + */ + dev_err(&spi->dev, + "%s: packet-size of %u too big (limit is %u bytes)", + __func__, max_packet, MAX3421_FIFO_SIZE); + return -EINVAL; + } + + if (max3421_hcd->curr_len < max_packet) { + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + /* + * remaining > 0 and received an + * unexpected partial packet -> + * error + */ + return -EREMOTEIO; + } else + /* short read, but it's OK */ + return 1; + } + return 0; /* not done */ +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static int +max3421_transfer_out_done(struct usb_hcd *hcd, struct urb *urb) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + + urb->actual_length += max3421_hcd->curr_len; + if (urb->actual_length < urb->transfer_buffer_length) + return 0; + if (urb->transfer_flags & URB_ZERO_PACKET) { + /* + * Some hardware needs a zero-size packet at the end + * of a bulk-out transfer if the last transfer was a + * full-sized packet (i.e., such hardware use < + * max_packet as an indicator that the end of the + * packet has been reached). + */ + u32 max_packet = usb_maxpacket(urb->dev, urb->pipe, 1); + + if (max3421_hcd->curr_len == max_packet) + return 0; + } + return 1; +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_host_transfer_done(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct urb *urb = max3421_hcd->curr_urb; + struct max3421_ep *max3421_ep; + u8 result_code, hrsl; + int urb_done = 0; + + max3421_hcd->hien &= ~(BIT(MAX3421_HI_HXFRDN_BIT) | + BIT(MAX3421_HI_RCVDAV_BIT)); + + hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); + result_code = hrsl & MAX3421_HRSL_RESULT_MASK; + +#ifdef DEBUG + ++max3421_hcd->err_stat[result_code]; +#endif + + max3421_ep = urb->ep->hcpriv; + + if (unlikely(result_code != MAX3421_HRSL_OK)) { + max3421_handle_error(hcd, hrsl); + return; + } + + max3421_ep->naks = 0; + max3421_ep->retries = 0; + switch (max3421_ep->pkt_state) { + + case PKT_STATE_SETUP: + if (urb->transfer_buffer_length > 0) + max3421_ep->pkt_state = PKT_STATE_TRANSFER; + else + max3421_ep->pkt_state = PKT_STATE_TERMINATE; + break; + + case PKT_STATE_TRANSFER: + if (usb_urb_dir_in(urb)) + urb_done = max3421_transfer_in_done(hcd, urb); + else + urb_done = max3421_transfer_out_done(hcd, urb); + if (urb_done > 0 && usb_pipetype(urb->pipe) == PIPE_CONTROL) { + /* + * We aren't really done - we still need to + * terminate the control transfer: + */ + max3421_hcd->urb_done = urb_done = 0; + max3421_ep->pkt_state = PKT_STATE_TERMINATE; + } + break; + + case PKT_STATE_TERMINATE: + urb_done = 1; + break; + } + + if (urb_done) + max3421_hcd->urb_done = urb_done; + else + max3421_next_transfer(hcd, 0); +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_detect_conn(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + unsigned int jk, have_conn = 0; + u32 old_port_status, chg; + unsigned long flags; + u8 hrsl, mode; + + hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); + + jk = ((((hrsl >> MAX3421_HRSL_JSTATUS_BIT) & 1) << 0) | + (((hrsl >> MAX3421_HRSL_KSTATUS_BIT) & 1) << 1)); + + mode = max3421_hcd->mode; + + switch (jk) { + case 0x0: /* SE0: disconnect */ + /* + * Turn off SOFKAENAB bit to avoid getting interrupt + * every milli-second: + */ + mode &= ~BIT(MAX3421_MODE_SOFKAENAB_BIT); + break; + + case 0x1: /* J=0,K=1: low-speed (in full-speed or vice versa) */ + case 0x2: /* J=1,K=0: full-speed (in full-speed or vice versa) */ + if (jk == 0x2) + /* need to switch to the other speed: */ + mode ^= BIT(MAX3421_MODE_LOWSPEED_BIT); + /* turn on SOFKAENAB bit: */ + mode |= BIT(MAX3421_MODE_SOFKAENAB_BIT); + have_conn = 1; + break; + + case 0x3: /* illegal */ + break; + } + + max3421_hcd->mode = mode; + spi_wr8(hcd, MAX3421_REG_MODE, max3421_hcd->mode); + + spin_lock_irqsave(&max3421_hcd->lock, flags); + old_port_status = max3421_hcd->port_status; + if (have_conn) + max3421_hcd->port_status |= USB_PORT_STAT_CONNECTION; + else + max3421_hcd->port_status &= ~USB_PORT_STAT_CONNECTION; + if (mode & BIT(MAX3421_MODE_LOWSPEED_BIT)) + max3421_hcd->port_status |= USB_PORT_STAT_LOW_SPEED; + else + max3421_hcd->port_status &= ~USB_PORT_STAT_LOW_SPEED; + chg = (old_port_status ^ max3421_hcd->port_status); + max3421_hcd->port_status |= chg << 16; + spin_unlock_irqrestore(&max3421_hcd->lock, flags); +} + +static irqreturn_t +max3421_irq_handler(int irq, void *dev_id) +{ + struct usb_hcd *hcd = dev_id; + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + + if (max3421_hcd->spi_thread && + max3421_hcd->spi_thread->state != TASK_RUNNING) + wake_up_process(max3421_hcd->spi_thread); + if (!max3421_hcd->do_enable_irq) { + max3421_hcd->do_enable_irq = 1; + disable_irq_nosync(spi->irq); + } + return IRQ_HANDLED; +} + +#ifdef DEBUG + +static void +dump_eps(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct max3421_ep *max3421_ep; + struct usb_host_endpoint *ep; + struct list_head *pos, *upos; + char ubuf[512], *dp, *end; + unsigned long flags; + struct urb *urb; + int epnum, ret; + + spin_lock_irqsave(&max3421_hcd->lock, flags); + list_for_each(pos, &max3421_hcd->ep_list) { + max3421_ep = container_of(pos, struct max3421_ep, ep_list); + ep = max3421_ep->ep; + + dp = ubuf; + end = dp + sizeof(ubuf); + *dp = '\0'; + list_for_each(upos, &ep->urb_list) { + urb = container_of(upos, struct urb, urb_list); + ret = snprintf(dp, end - dp, " %p(%d.%s %d/%d)", urb, + usb_pipetype(urb->pipe), + usb_urb_dir_in(urb) ? "IN" : "OUT", + urb->actual_length, + urb->transfer_buffer_length); + if (ret < 0 || ret >= end - dp) + break; /* error or buffer full */ + dp += ret; + } + + epnum = usb_endpoint_num(&ep->desc); + pr_info("EP%0u %u lst %04u rtr %u nak %6u rxmt %u: %s\n", + epnum, max3421_ep->pkt_state, max3421_ep->last_active, + max3421_ep->retries, max3421_ep->naks, + max3421_ep->retransmit, ubuf); + } + spin_unlock_irqrestore(&max3421_hcd->lock, flags); +} + +#endif /* DEBUG */ + +/* Return zero if no work was performed, 1 otherwise. */ +static int +max3421_handle_irqs(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + u32 chg, old_port_status; + unsigned long flags; + u8 hirq; + + /* + * Read and ack pending interrupts (CPU must never + * clear SNDBAV directly and RCVDAV must be cleared by + * max3421_recv_data_available()!): + */ + hirq = spi_rd8(hcd, MAX3421_REG_HIRQ); + hirq &= max3421_hcd->hien; + if (!hirq) + return 0; + + spi_wr8(hcd, MAX3421_REG_HIRQ, + hirq & ~(BIT(MAX3421_HI_SNDBAV_BIT) | + BIT(MAX3421_HI_RCVDAV_BIT))); + + if (hirq & BIT(MAX3421_HI_FRAME_BIT)) { + max3421_hcd->frame_number = ((max3421_hcd->frame_number + 1) + & USB_MAX_FRAME_NUMBER); + max3421_hcd->sched_pass = SCHED_PASS_PERIODIC; + } + + if (hirq & BIT(MAX3421_HI_RCVDAV_BIT)) + max3421_recv_data_available(hcd); + + if (hirq & BIT(MAX3421_HI_HXFRDN_BIT)) + max3421_host_transfer_done(hcd); + + if (hirq & BIT(MAX3421_HI_CONDET_BIT)) + max3421_detect_conn(hcd); + + /* + * Now process interrupts that may affect HCD state + * other than the end-points: + */ + spin_lock_irqsave(&max3421_hcd->lock, flags); + + old_port_status = max3421_hcd->port_status; + if (hirq & BIT(MAX3421_HI_BUSEVENT_BIT)) { + if (max3421_hcd->port_status & USB_PORT_STAT_RESET) { + /* BUSEVENT due to completion of Bus Reset */ + max3421_hcd->port_status &= ~USB_PORT_STAT_RESET; + max3421_hcd->port_status |= USB_PORT_STAT_ENABLE; + } else { + /* BUSEVENT due to completion of Bus Resume */ + pr_info("%s: BUSEVENT Bus Resume Done\n", __func__); + } + } + if (hirq & BIT(MAX3421_HI_RWU_BIT)) + pr_info("%s: RWU\n", __func__); + if (hirq & BIT(MAX3421_HI_SUSDN_BIT)) + pr_info("%s: SUSDN\n", __func__); + + chg = (old_port_status ^ max3421_hcd->port_status); + max3421_hcd->port_status |= chg << 16; + + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + +#ifdef DEBUG + { + static unsigned long last_time; + char sbuf[16 * 16], *dp, *end; + int i; + + if (jiffies - last_time > 5*HZ) { + dp = sbuf; + end = sbuf + sizeof(sbuf); + *dp = '\0'; + for (i = 0; i < 16; ++i) { + int ret = snprintf(dp, end - dp, " %lu", + max3421_hcd->err_stat[i]); + if (ret < 0 || ret >= end - dp) + break; /* error or buffer full */ + dp += ret; + } + pr_info("%s: hrsl_stats %s\n", __func__, sbuf); + memset(max3421_hcd->err_stat, 0, + sizeof(max3421_hcd->err_stat)); + last_time = jiffies; + + dump_eps(hcd); + } + } +#endif + return 1; +} + +static int +max3421_reset_hcd(struct usb_hcd *hcd) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + int timeout; + + /* perform a chip reset and wait for OSCIRQ signal to appear: */ + spi_wr8(hcd, MAX3421_REG_USBCTL, BIT(MAX3421_USBCTL_CHIPRES_BIT)); + /* clear reset: */ + spi_wr8(hcd, MAX3421_REG_USBCTL, 0); + timeout = 1000; + while (1) { + if (spi_rd8(hcd, MAX3421_REG_USBIRQ) + & BIT(MAX3421_USBIRQ_OSCOKIRQ_BIT)) + break; + if (--timeout < 0) { + dev_err(&spi->dev, + "timed out waiting for oscillator OK signal"); + return 1; + } + cond_resched(); + } + + /* + * Turn on host mode, automatic generation of SOF packets, and + * enable pull-down registers on DM/DP: + */ + max3421_hcd->mode = (BIT(MAX3421_MODE_HOST_BIT) | + BIT(MAX3421_MODE_SOFKAENAB_BIT) | + BIT(MAX3421_MODE_DMPULLDN_BIT) | + BIT(MAX3421_MODE_DPPULLDN_BIT)); + spi_wr8(hcd, MAX3421_REG_MODE, max3421_hcd->mode); + + /* reset frame-number: */ + max3421_hcd->frame_number = USB_MAX_FRAME_NUMBER; + spi_wr8(hcd, MAX3421_REG_HCTL, BIT(MAX3421_HCTL_FRMRST_BIT)); + + /* sample the state of the D+ and D- lines */ + spi_wr8(hcd, MAX3421_REG_HCTL, BIT(MAX3421_HCTL_SAMPLEBUS_BIT)); + max3421_detect_conn(hcd); + + /* enable frame, connection-detected, and bus-event interrupts: */ + max3421_hcd->hien = (BIT(MAX3421_HI_FRAME_BIT) | + BIT(MAX3421_HI_CONDET_BIT) | + BIT(MAX3421_HI_BUSEVENT_BIT)); + spi_wr8(hcd, MAX3421_REG_HIEN, max3421_hcd->hien); + + /* enable interrupts: */ + spi_wr8(hcd, MAX3421_REG_CPUCTL, BIT(MAX3421_CPUCTL_IE_BIT)); + return 1; +} + +static int +max3421_urb_done(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + unsigned long flags; + struct urb *urb; + int status; + + status = max3421_hcd->urb_done; + max3421_hcd->urb_done = 0; + if (status > 0) + status = 0; + urb = max3421_hcd->curr_urb; + if (urb) { + max3421_hcd->curr_urb = NULL; + spin_lock_irqsave(&max3421_hcd->lock, flags); + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + + /* must be called without the HCD spinlock: */ + usb_hcd_giveback_urb(hcd, urb, status); + } + return 1; +} + +static int +max3421_spi_thread(void *dev_id) +{ + struct usb_hcd *hcd = dev_id; + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + int i, i_worked = 1; + + /* set full-duplex SPI mode, low-active interrupt pin: */ + spi_wr8(hcd, MAX3421_REG_PINCTL, + (BIT(MAX3421_PINCTL_FDUPSPI_BIT) | /* full-duplex */ + BIT(MAX3421_PINCTL_INTLEVEL_BIT))); /* low-active irq */ + + while (!kthread_should_stop()) { + max3421_hcd->rev = spi_rd8(hcd, MAX3421_REG_REVISION); + if (max3421_hcd->rev == 0x12 || max3421_hcd->rev == 0x13) + break; + dev_err(&spi->dev, "bad rev 0x%02x", max3421_hcd->rev); + msleep(10000); + } + dev_info(&spi->dev, "rev 0x%x, SPI clk %dHz, bpw %u, irq %d\n", + max3421_hcd->rev, spi->max_speed_hz, spi->bits_per_word, + spi->irq); + + while (!kthread_should_stop()) { + if (!i_worked) { + /* + * We'll be waiting for wakeups from the hard + * interrupt handler, so now is a good time to + * sync our hien with the chip: + */ + spi_wr8(hcd, MAX3421_REG_HIEN, max3421_hcd->hien); + + set_current_state(TASK_INTERRUPTIBLE); + if (max3421_hcd->do_enable_irq) { + max3421_hcd->do_enable_irq = 0; + enable_irq(spi->irq); + } + schedule(); + __set_current_state(TASK_RUNNING); + } + + i_worked = 0; + + if (max3421_hcd->urb_done) + i_worked |= max3421_urb_done(hcd); + else if (max3421_handle_irqs(hcd)) + i_worked = 1; + else if (!max3421_hcd->curr_urb) + i_worked |= max3421_select_and_start_urb(hcd); + + if (max3421_hcd->do_reset_hcd) { + /* reset the HCD: */ + max3421_hcd->do_reset_hcd = 0; + i_worked |= max3421_reset_hcd(hcd); + } + if (max3421_hcd->do_reset_port) { + /* perform a USB bus reset: */ + max3421_hcd->do_reset_port = 0; + spi_wr8(hcd, MAX3421_REG_HCTL, + BIT(MAX3421_HCTL_BUSRST_BIT)); + i_worked = 1; + } + if (max3421_hcd->do_check_unlink) { + max3421_hcd->do_check_unlink = 0; + i_worked |= max3421_check_unlink(hcd); + } + if (max3421_hcd->do_iopin_update) { + /* + * IOPINS1/IOPINS2 do not auto-increment, so we can't + * use spi_wr_buf(). + */ + for (i = 0; i < ARRAY_SIZE(max3421_hcd->iopins); ++i) { + u8 val = spi_rd8(hcd, MAX3421_REG_IOPINS1); + + val = ((val & 0xf0) | + (max3421_hcd->iopins[i] & 0x0f)); + spi_wr8(hcd, MAX3421_REG_IOPINS1 + i, val); + max3421_hcd->iopins[i] = val; + } + max3421_hcd->do_iopin_update = 0; + i_worked = 1; + } + } + set_current_state(TASK_RUNNING); + dev_info(&spi->dev, "SPI thread exiting"); + return 0; +} + +static int +max3421_reset_port(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + + max3421_hcd->port_status &= ~(USB_PORT_STAT_ENABLE | + USB_PORT_STAT_LOW_SPEED); + max3421_hcd->do_reset_port = 1; + wake_up_process(max3421_hcd->spi_thread); + return 0; +} + +static int +max3421_reset(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + + hcd->self.sg_tablesize = 0; + hcd->speed = HCD_USB2; + hcd->self.root_hub->speed = USB_SPEED_FULL; + max3421_hcd->do_reset_hcd = 1; + wake_up_process(max3421_hcd->spi_thread); + return 0; +} + +static int +max3421_start(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + + spin_lock_init(&max3421_hcd->lock); + max3421_hcd->rh_state = MAX3421_RH_RUNNING; + + INIT_LIST_HEAD(&max3421_hcd->ep_list); + + hcd->power_budget = POWER_BUDGET; + hcd->state = HC_STATE_RUNNING; + hcd->uses_new_polling = 1; + return 0; +} + +static void +max3421_stop(struct usb_hcd *hcd) +{ +} + +static int +max3421_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct max3421_ep *max3421_ep; + unsigned long flags; + int retval; + + switch (usb_pipetype(urb->pipe)) { + case PIPE_INTERRUPT: + case PIPE_ISOCHRONOUS: + if (urb->interval < 0) { + dev_err(&spi->dev, + "%s: interval=%d for intr-/iso-pipe; expected > 0\n", + __func__, urb->interval); + return -EINVAL; + } + default: + break; + } + + spin_lock_irqsave(&max3421_hcd->lock, flags); + + max3421_ep = urb->ep->hcpriv; + if (!max3421_ep) { + /* gets freed in max3421_endpoint_disable: */ + max3421_ep = kzalloc(sizeof(struct max3421_ep), mem_flags); + if (!max3421_ep) { + retval = -ENOMEM; + goto out; + } + max3421_ep->ep = urb->ep; + max3421_ep->last_active = max3421_hcd->frame_number; + urb->ep->hcpriv = max3421_ep; + + list_add_tail(&max3421_ep->ep_list, &max3421_hcd->ep_list); + } + + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + /* Since we added to the queue, restart scheduling: */ + max3421_hcd->sched_pass = SCHED_PASS_PERIODIC; + wake_up_process(max3421_hcd->spi_thread); + } + +out: + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + return retval; +} + +static int +max3421_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + unsigned long flags; + int retval; + + spin_lock_irqsave(&max3421_hcd->lock, flags); + + /* + * This will set urb->unlinked which in turn causes the entry + * to be dropped at the next opportunity. + */ + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval == 0) { + max3421_hcd->do_check_unlink = 1; + wake_up_process(max3421_hcd->spi_thread); + } + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + return retval; +} + +static void +max3421_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + unsigned long flags; + + spin_lock_irqsave(&max3421_hcd->lock, flags); + + if (ep->hcpriv) { + struct max3421_ep *max3421_ep = ep->hcpriv; + + /* remove myself from the ep_list: */ + if (!list_empty(&max3421_ep->ep_list)) + list_del(&max3421_ep->ep_list); + kfree(max3421_ep); + ep->hcpriv = NULL; + } + + spin_unlock_irqrestore(&max3421_hcd->lock, flags); +} + +static int +max3421_get_frame_number(struct usb_hcd *hcd) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + return max3421_hcd->frame_number; +} + +/* + * Should return a non-zero value when any port is undergoing a resume + * transition while the root hub is suspended. + */ +static int +max3421_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&max3421_hcd->lock, flags); + if (!HCD_HW_ACCESSIBLE(hcd)) + goto done; + + *buf = 0; + if ((max3421_hcd->port_status & PORT_C_MASK) != 0) { + *buf = (1 << 1); /* a hub over-current condition exists */ + dev_dbg(hcd->self.controller, + "port status 0x%08x has changes\n", + max3421_hcd->port_status); + retval = 1; + if (max3421_hcd->rh_state == MAX3421_RH_SUSPENDED) + usb_hcd_resume_root_hub(hcd); + } +done: + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + return retval; +} + +static inline void +hub_descriptor(struct usb_hub_descriptor *desc) +{ + memset(desc, 0, sizeof(*desc)); + /* + * See Table 11-13: Hub Descriptor in USB 2.0 spec. + */ + desc->bDescriptorType = 0x29; /* hub descriptor */ + desc->bDescLength = 9; + desc->wHubCharacteristics = cpu_to_le16(0x0001); + desc->bNbrPorts = 1; +} + +/* + * Set the MAX3421E general-purpose output with number PIN_NUMBER to + * VALUE (0 or 1). PIN_NUMBER may be in the range from 1-8. For + * any other value, this function acts as a no-op. + */ +static void +max3421_gpout_set_value(struct usb_hcd *hcd, u8 pin_number, u8 value) +{ + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + u8 mask, idx; + + --pin_number; + if (pin_number > 7) + return; + + mask = 1u << pin_number; + idx = pin_number / 4; + + if (value) + max3421_hcd->iopins[idx] |= mask; + else + max3421_hcd->iopins[idx] &= ~mask; + max3421_hcd->do_iopin_update = 1; + wake_up_process(max3421_hcd->spi_thread); +} + +static int +max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index, + char *buf, u16 length) +{ + struct spi_device *spi = to_spi_device(hcd->self.controller); + struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + struct max3421_hcd_platform_data *pdata; + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&max3421_hcd->lock, flags); + + pdata = spi->dev.platform_data; + + switch (type_req) { + case ClearHubFeature: + break; + case ClearPortFeature: + switch (value) { + case USB_PORT_FEAT_SUSPEND: + break; + case USB_PORT_FEAT_POWER: + dev_dbg(hcd->self.controller, "power-off\n"); + max3421_gpout_set_value(hcd, pdata->vbus_gpout, + !pdata->vbus_active_level); + /* FALLS THROUGH */ + default: + max3421_hcd->port_status &= ~(1 << value); + } + break; + case GetHubDescriptor: + hub_descriptor((struct usb_hub_descriptor *) buf); + break; + + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + case GetPortErrorCount: + case SetHubDepth: + /* USB3 only */ + goto error; + + case GetHubStatus: + *(__le32 *) buf = cpu_to_le32(0); + break; + + case GetPortStatus: + if (index != 1) { + retval = -EPIPE; + goto error; + } + ((__le16 *) buf)[0] = cpu_to_le16(max3421_hcd->port_status); + ((__le16 *) buf)[1] = + cpu_to_le16(max3421_hcd->port_status >> 16); + break; + + case SetHubFeature: + retval = -EPIPE; + break; + + case SetPortFeature: + switch (value) { + case USB_PORT_FEAT_LINK_STATE: + case USB_PORT_FEAT_U1_TIMEOUT: + case USB_PORT_FEAT_U2_TIMEOUT: + case USB_PORT_FEAT_BH_PORT_RESET: + goto error; + case USB_PORT_FEAT_SUSPEND: + if (max3421_hcd->active) + max3421_hcd->port_status |= + USB_PORT_STAT_SUSPEND; + break; + case USB_PORT_FEAT_POWER: + dev_dbg(hcd->self.controller, "power-on\n"); + max3421_hcd->port_status |= USB_PORT_STAT_POWER; + max3421_gpout_set_value(hcd, pdata->vbus_gpout, + pdata->vbus_active_level); + break; + case USB_PORT_FEAT_RESET: + max3421_reset_port(hcd); + /* FALLS THROUGH */ + default: + if ((max3421_hcd->port_status & USB_PORT_STAT_POWER) + != 0) + max3421_hcd->port_status |= (1 << value); + } + break; + + default: + dev_dbg(hcd->self.controller, + "hub control req%04x v%04x i%04x l%d\n", + type_req, value, index, length); +error: /* "protocol stall" on error */ + retval = -EPIPE; + } + + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + return retval; +} + +static int +max3421_bus_suspend(struct usb_hcd *hcd) +{ + return -1; +} + +static int +max3421_bus_resume(struct usb_hcd *hcd) +{ + return -1; +} + +/* + * The SPI driver already takes care of DMA-mapping/unmapping, so no + * reason to do it twice. + */ +static int +max3421_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) +{ + return 0; +} + +static void +max3421_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ +} + +static struct hc_driver max3421_hcd_desc = { + .description = "max3421", + .product_desc = DRIVER_DESC, + .hcd_priv_size = sizeof(struct max3421_hcd), + .flags = HCD_USB11, + .reset = max3421_reset, + .start = max3421_start, + .stop = max3421_stop, + .get_frame_number = max3421_get_frame_number, + .urb_enqueue = max3421_urb_enqueue, + .urb_dequeue = max3421_urb_dequeue, + .map_urb_for_dma = max3421_map_urb_for_dma, + .unmap_urb_for_dma = max3421_unmap_urb_for_dma, + .endpoint_disable = max3421_endpoint_disable, + .hub_status_data = max3421_hub_status_data, + .hub_control = max3421_hub_control, + .bus_suspend = max3421_bus_suspend, + .bus_resume = max3421_bus_resume, +}; + +static int +max3421_probe(struct spi_device *spi) +{ + struct max3421_hcd *max3421_hcd; + struct usb_hcd *hcd = NULL; + int retval = -ENOMEM; + + if (spi_setup(spi) < 0) { + dev_err(&spi->dev, "Unable to setup SPI bus"); + return -EFAULT; + } + + hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev, + dev_name(&spi->dev)); + if (!hcd) { + dev_err(&spi->dev, "failed to create HCD structure\n"); + goto error; + } + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); + max3421_hcd = hcd_to_max3421(hcd); + max3421_hcd->next = max3421_hcd_list; + max3421_hcd_list = max3421_hcd; + INIT_LIST_HEAD(&max3421_hcd->ep_list); + + max3421_hcd->tx = kmalloc(sizeof(*max3421_hcd->tx), GFP_KERNEL); + if (!max3421_hcd->tx) { + dev_err(&spi->dev, "failed to kmalloc tx buffer\n"); + goto error; + } + max3421_hcd->rx = kmalloc(sizeof(*max3421_hcd->rx), GFP_KERNEL); + if (!max3421_hcd->rx) { + dev_err(&spi->dev, "failed to kmalloc rx buffer\n"); + goto error; + } + + max3421_hcd->spi_thread = kthread_run(max3421_spi_thread, hcd, + "max3421_spi_thread"); + if (max3421_hcd->spi_thread == ERR_PTR(-ENOMEM)) { + dev_err(&spi->dev, + "failed to create SPI thread (out of memory)\n"); + goto error; + } + + retval = usb_add_hcd(hcd, 0, 0); + if (retval) { + dev_err(&spi->dev, "failed to add HCD\n"); + goto error; + } + + retval = request_irq(spi->irq, max3421_irq_handler, + IRQF_TRIGGER_LOW, "max3421", hcd); + if (retval < 0) { + dev_err(&spi->dev, "failed to request irq %d\n", spi->irq); + goto error; + } + return 0; + +error: + if (hcd) { + kfree(max3421_hcd->tx); + kfree(max3421_hcd->rx); + if (max3421_hcd->spi_thread) + kthread_stop(max3421_hcd->spi_thread); + usb_put_hcd(hcd); + } + return retval; +} + +static int +max3421_remove(struct spi_device *spi) +{ + struct max3421_hcd *max3421_hcd = NULL, **prev; + struct usb_hcd *hcd = NULL; + unsigned long flags; + + for (prev = &max3421_hcd_list; *prev; prev = &(*prev)->next) { + max3421_hcd = *prev; + hcd = max3421_to_hcd(max3421_hcd); + if (hcd->self.controller == &spi->dev) + break; + } + if (!max3421_hcd) { + dev_err(&spi->dev, "no MAX3421 HCD found for SPI device %p\n", + spi); + return -ENODEV; + } + + usb_remove_hcd(hcd); + + spin_lock_irqsave(&max3421_hcd->lock, flags); + + kthread_stop(max3421_hcd->spi_thread); + *prev = max3421_hcd->next; + + spin_unlock_irqrestore(&max3421_hcd->lock, flags); + + free_irq(spi->irq, hcd); + + usb_put_hcd(hcd); + return 0; +} + +static struct spi_driver max3421_driver = { + .probe = max3421_probe, + .remove = max3421_remove, + .driver = { + .name = "max3421-hcd", + .owner = THIS_MODULE, + }, +}; + +module_spi_driver(max3421_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("David Mosberger <davidm@egauge.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 2ee1496dbc1..e49eb4f90f5 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -13,26 +13,38 @@ */ #include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> +#include <linux/platform_device.h> #include <linux/platform_data/atmel.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> #include <mach/hardware.h> #include <asm/gpio.h> #include <mach/cpu.h> -#ifndef CONFIG_ARCH_AT91 -#error "CONFIG_ARCH_AT91 must be defined." -#endif + +#include "ohci.h" #define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) #define at91_for_each_port(index) \ for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++) +/* interface, function and usb clocks; sometimes also an AHB clock */ +static struct clk *iclk, *fclk, *uclk, *hclk; /* interface and function clocks; sometimes also an AHB clock */ -static struct clk *iclk, *fclk, *hclk; + +#define DRIVER_DESC "OHCI Atmel driver" + +static const char hcd_name[] = "ohci-atmel"; + +static struct hc_driver __read_mostly ohci_at91_hc_driver; static int clocked; extern int usb_disabled(void); @@ -41,17 +53,23 @@ extern int usb_disabled(void); static void at91_start_clock(void) { - clk_enable(hclk); - clk_enable(iclk); - clk_enable(fclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + clk_set_rate(uclk, 48000000); + clk_prepare_enable(uclk); + } + clk_prepare_enable(hclk); + clk_prepare_enable(iclk); + clk_prepare_enable(fclk); clocked = 1; } static void at91_stop_clock(void) { - clk_disable(fclk); - clk_disable(iclk); - clk_disable(hclk); + clk_disable_unprepare(fclk); + clk_disable_unprepare(iclk); + clk_disable_unprepare(hclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_disable_unprepare(uclk); clocked = 0; } @@ -111,81 +129,80 @@ static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); static int usb_hcd_at91_probe(const struct hc_driver *driver, struct platform_device *pdev) { + struct at91_usbh_data *board; + struct ohci_hcd *ohci; int retval; struct usb_hcd *hcd = NULL; - - if (pdev->num_resources != 2) { - pr_debug("hcd probe: invalid num_resources"); - return -ENODEV; + struct device *dev = &pdev->dev; + struct resource *res; + int irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_dbg(dev, "hcd probe: missing memory resource\n"); + return -ENXIO; } - if ((pdev->resource[0].flags != IORESOURCE_MEM) - || (pdev->resource[1].flags != IORESOURCE_IRQ)) { - pr_debug("hcd probe: invalid resource type\n"); - return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_dbg(dev, "hcd probe: missing irq resource\n"); + return irq; } - hcd = usb_create_hcd(driver, &pdev->dev, "at91"); + hcd = usb_create_hcd(driver, dev, "at91"); if (!hcd) return -ENOMEM; - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = resource_size(&pdev->resource[0]); + 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("request_mem_region failed\n"); - retval = -EBUSY; - goto err1; + hcd->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); + goto err; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed\n"); - retval = -EIO; - goto err2; - } - - iclk = clk_get(&pdev->dev, "ohci_clk"); + iclk = devm_clk_get(dev, "ohci_clk"); if (IS_ERR(iclk)) { - dev_err(&pdev->dev, "failed to get ohci_clk\n"); + dev_err(dev, "failed to get ohci_clk\n"); retval = PTR_ERR(iclk); - goto err3; + goto err; } - fclk = clk_get(&pdev->dev, "uhpck"); + fclk = devm_clk_get(dev, "uhpck"); if (IS_ERR(fclk)) { - dev_err(&pdev->dev, "failed to get uhpck\n"); + dev_err(dev, "failed to get uhpck\n"); retval = PTR_ERR(fclk); - goto err4; + goto err; } - hclk = clk_get(&pdev->dev, "hclk"); + hclk = devm_clk_get(dev, "hclk"); if (IS_ERR(hclk)) { - dev_err(&pdev->dev, "failed to get hclk\n"); + dev_err(dev, "failed to get hclk\n"); retval = PTR_ERR(hclk); - goto err5; + goto err; + } + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + uclk = devm_clk_get(dev, "usb_clk"); + if (IS_ERR(uclk)) { + dev_err(dev, "failed to get uclk\n"); + retval = PTR_ERR(uclk); + goto err; + } } + board = hcd->self.controller->platform_data; + ohci = hcd_to_ohci(hcd); + ohci->num_ports = board->ports; at91_start_hc(pdev); - ohci_hcd_init(hcd_to_ohci(hcd)); - retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); - if (retval == 0) + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval == 0) { + device_wakeup_enable(hcd->self.controller); return retval; + } /* Error handling */ at91_stop_hc(pdev); - clk_put(hclk); - err5: - clk_put(fclk); - err4: - clk_put(iclk); - - err3: - iounmap(hcd->regs); - - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - err1: + err: usb_put_hcd(hcd); return retval; } @@ -208,49 +225,10 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd, { usb_remove_hcd(hcd); at91_stop_hc(pdev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - - clk_put(hclk); - clk_put(fclk); - clk_put(iclk); - fclk = iclk = hclk = NULL; - - dev_set_drvdata(&pdev->dev, NULL); } /*-------------------------------------------------------------------------*/ - -static int -ohci_at91_reset (struct usb_hcd *hcd) -{ - struct at91_usbh_data *board = hcd->self.controller->platform_data; - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - ohci->num_ports = board->ports; - return 0; -} - -static int -ohci_at91_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int 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 void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) { if (!valid_port(port)) @@ -301,7 +279,7 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { - struct at91_usbh_data *pdata = hcd->self.controller->platform_data; + struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); struct usb_hub_descriptor *desc; int ret = -EINVAL; u32 *data = (u32 *)buf; @@ -413,55 +391,10 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /*-------------------------------------------------------------------------*/ -static const struct hc_driver ohci_at91_hc_driver = { - .description = hcd_name, - .product_desc = "AT91 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_at91_reset, - .start = ohci_at91_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_at91_hub_status_data, - .hub_control = ohci_at91_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) { struct platform_device *pdev = data; - struct at91_usbh_data *pdata = pdev->dev.platform_data; + struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev); int val, gpio, port; /* From the GPIO notifying the over-current situation, find @@ -507,7 +440,7 @@ MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids); static int ohci_at91_of_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int i, gpio; + int i, gpio, ret; enum of_gpio_flags flags; struct at91_usbh_data *pdata; u32 ports; @@ -519,10 +452,9 @@ static int ohci_at91_of_init(struct platform_device *pdev) * 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -567,7 +499,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) if (ret) return ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (pdata) { at91_for_each_port(i) { @@ -643,7 +575,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) { - struct at91_usbh_data *pdata = pdev->dev.platform_data; + struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev); int i; if (pdata) { @@ -674,10 +606,17 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); + bool do_wakeup = device_may_wakeup(&pdev->dev); + int ret; - if (device_may_wakeup(&pdev->dev)) + if (do_wakeup) enable_irq_wake(hcd->irq); + ret = ohci_suspend(hcd, do_wakeup); + if (ret) { + disable_irq_wake(hcd->irq); + return ret; + } /* * The integrated transceivers seem unable to notice disconnect, * reconnect, or wakeup without the 48 MHz clock active. so for @@ -686,13 +625,17 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) * REVISIT: some boards will be able to turn VBUS off... */ if (at91_suspend_entering_slow_clock()) { - ohci_usb_reset (ohci); + ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + ohci->hc_control &= OHCI_CTRL_RWC; + ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); + ohci->rh_state = OHCI_RH_HALTED; + /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); at91_stop_clock(); } - return 0; + return ret; } static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) @@ -713,8 +656,6 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) #define ohci_hcd_at91_drv_resume NULL #endif -MODULE_ALIAS("platform:at91_ohci"); - static struct platform_driver ohci_hcd_at91_driver = { .probe = ohci_hcd_at91_drv_probe, .remove = ohci_hcd_at91_drv_remove, @@ -727,3 +668,37 @@ static struct platform_driver ohci_hcd_at91_driver = { .of_match_table = of_match_ptr(at91_ohci_dt_ids), }, }; + +static int __init ohci_at91_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ohci_init_driver(&ohci_at91_hc_driver, NULL); + + /* + * The Atmel HW has some unusual quirks, which require Atmel-specific + * workarounds. We override certain hc_driver functions here to + * achieve that. We explicitly do not enhance ohci_driver_overrides to + * allow this more easily, since this is an unusual case, and we don't + * want to encourage others to override these functions by making it + * too easy. + */ + + ohci_at91_hc_driver.hub_status_data = ohci_at91_hub_status_data; + ohci_at91_hc_driver.hub_control = ohci_at91_hub_control; + + return platform_driver_register(&ohci_hcd_at91_driver); +} +module_init(ohci_at91_init); + +static void __exit ohci_at91_cleanup(void) +{ + platform_driver_unregister(&ohci_hcd_at91_driver); +} +module_exit(ohci_at91_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:at91_ohci"); diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 0b815a85681..df06be6b47f 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -85,7 +85,7 @@ static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub, static int ohci_da8xx_init(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev->platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); int result; u32 rh_a; @@ -171,7 +171,7 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev->platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); int temp; switch (typeReq) { @@ -292,7 +292,7 @@ static const struct hc_driver ohci_da8xx_hc_driver = { static int usb_hcd_da8xx_probe(const struct hc_driver *driver, struct platform_device *pdev) { - struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd; struct resource *mem; int error, irq; @@ -300,41 +300,28 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver, if (hub == NULL) return -ENODEV; - usb11_clk = clk_get(&pdev->dev, "usb11"); + usb11_clk = devm_clk_get(&pdev->dev, "usb11"); if (IS_ERR(usb11_clk)) return PTR_ERR(usb11_clk); - usb20_clk = clk_get(&pdev->dev, "usb20"); - if (IS_ERR(usb20_clk)) { - error = PTR_ERR(usb20_clk); - goto err0; - } + usb20_clk = devm_clk_get(&pdev->dev, "usb20"); + if (IS_ERR(usb20_clk)) + return PTR_ERR(usb20_clk); hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - error = -ENOMEM; - goto err1; - } + if (!hcd) + return -ENOMEM; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - error = -ENODEV; - goto err2; - } + if (!mem) + return -ENODEV; hcd->rsrc_start = mem->start; hcd->rsrc_len = resource_size(mem); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); - error = -EBUSY; - goto err2; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - error = -ENOMEM; - goto err3; + hcd->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(hcd->regs)) { + error = PTR_ERR(hcd->regs); + goto err; } ohci_hcd_init(hcd_to_ohci(hcd)); @@ -342,11 +329,13 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver, irq = platform_get_irq(pdev, 0); if (irq < 0) { error = -ENODEV; - goto err4; + goto err; } error = usb_add_hcd(hcd, irq, 0); if (error) - goto err4; + goto err; + + device_wakeup_enable(hcd->self.controller); if (hub->ocic_notify) { error = hub->ocic_notify(ohci_da8xx_ocic_handler); @@ -355,16 +344,8 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver, } usb_remove_hcd(hcd); -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: +err: usb_put_hcd(hcd); -err1: - clk_put(usb20_clk); -err0: - clk_put(usb11_clk); return error; } @@ -380,15 +361,11 @@ err0: static inline void usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev) { - struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev); hub->ocic_notify(NULL); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - clk_put(usb20_clk); - clk_put(usb11_clk); } static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev) @@ -401,25 +378,32 @@ static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); usb_hcd_da8xx_remove(hcd, dev); - platform_set_drvdata(dev, NULL); return 0; } #ifdef CONFIG_PM -static int ohci_da8xx_suspend(struct platform_device *dev, pm_message_t message) +static int ohci_da8xx_suspend(struct platform_device *pdev, + pm_message_t message) { - struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); + bool do_wakeup = device_may_wakeup(&pdev->dev); + int ret; + if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; + ret = ohci_suspend(hcd, do_wakeup); + if (ret) + return ret; + ohci_da8xx_clock(0); hcd->state = HC_STATE_SUSPENDED; - dev->dev.power.power_state = PMSG_SUSPEND; - return 0; + + return ret; } static int ohci_da8xx_resume(struct platform_device *dev) diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 31b81f9eacd..45032e933e1 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -9,68 +9,15 @@ /*-------------------------------------------------------------------------*/ -#ifdef DEBUG - #define edstring(ed_type) ({ char *temp; \ switch (ed_type) { \ case PIPE_CONTROL: temp = "ctrl"; break; \ case PIPE_BULK: temp = "bulk"; break; \ case PIPE_INTERRUPT: temp = "intr"; break; \ default: temp = "isoc"; break; \ - }; temp;}) + } temp;}) #define pipestring(pipe) edstring(usb_pipetype(pipe)) -/* debug| print the main components of an URB - * small: 0) header + data packets 1) just header - */ -static void __maybe_unused -urb_print(struct urb * urb, char * str, int small, int status) -{ - unsigned int pipe= urb->pipe; - - if (!urb->dev || !urb->dev->bus) { - printk(KERN_DEBUG "%s URB: no dev\n", str); - return; - } - -#ifndef OHCI_VERBOSE_DEBUG - if (status != 0) -#endif - printk(KERN_DEBUG "%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d\n", - str, - urb, - usb_pipedevice (pipe), - usb_pipeendpoint (pipe), - usb_pipeout (pipe)? "out" : "in", - pipestring (pipe), - urb->transfer_flags, - urb->actual_length, - urb->transfer_buffer_length, - status); - -#ifdef OHCI_VERBOSE_DEBUG - if (!small) { - int i, len; - - if (usb_pipecontrol (pipe)) { - printk (KERN_DEBUG "%s: setup(8):", __FILE__); - for (i = 0; i < 8 ; i++) - printk (" %02x", ((__u8 *) urb->setup_packet) [i]); - printk ("\n"); - } - if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) { - printk (KERN_DEBUG "%s: data(%d/%d):", __FILE__, - urb->actual_length, - urb->transfer_buffer_length); - len = usb_pipeout (pipe)? - urb->transfer_buffer_length: urb->actual_length; - for (i = 0; i < 16 && i < len; i++) - printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", status); - } - } -#endif -} #define ohci_dbg_sw(ohci, next, size, format, arg...) \ do { \ @@ -407,22 +354,8 @@ ohci_dump_ed (const struct ohci_hcd *ohci, const char *label, } } -#else -static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {} - -#undef OHCI_VERBOSE_DEBUG - -#endif /* DEBUG */ - /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILES - -static inline void create_debug_files (struct ohci_hcd *bus) { } -static inline void remove_debug_files (struct ohci_hcd *bus) { } - -#else - 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 *); @@ -871,7 +804,5 @@ static inline void remove_debug_files (struct ohci_hcd *ohci) debugfs_remove(ohci->debug_dir); } -#endif - /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c deleted file mode 100644 index 8704e9fa5a8..00000000000 --- a/drivers/usb/host/ohci-ep93xx.c +++ /dev/null @@ -1,217 +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 ep93xx. - * - * 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 pxa27x from ohci-lh7a404.c - * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004 - * - * Modified for ep93xx from ohci-pxa27x.c - * by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006 - * Based on an earlier driver by Ray Lehtiniemi - * - * This file is licenced under the GPL. - */ - -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/signal.h> -#include <linux/platform_device.h> - -static struct clk *usb_host_clock; - -static void ep93xx_start_hc(struct device *dev) -{ - clk_enable(usb_host_clock); -} - -static void ep93xx_stop_hc(struct device *dev) -{ - clk_disable(usb_host_clock); -} - -static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval; - struct usb_hcd *hcd; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx"); - if (hcd == NULL) - 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)) { - usb_put_hcd(hcd); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "ioremap failed\n"); - retval = -ENOMEM; - goto err2; - } - - usb_host_clock = clk_get(&pdev->dev, NULL); - if (IS_ERR(usb_host_clock)) { - dev_dbg(&pdev->dev, "clk_get failed\n"); - retval = PTR_ERR(usb_host_clock); - goto err3; - } - - ep93xx_start_hc(&pdev->dev); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, pdev->resource[1].start, 0); - if (retval == 0) - return retval; - - ep93xx_stop_hc(&pdev->dev); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - - return retval; -} - -static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - ep93xx_stop_hc(&pdev->dev); - clk_put(usb_host_clock); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -static int ohci_ep93xx_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 struct hc_driver ohci_ep93xx_hc_driver = { - .description = hcd_name, - .product_desc = "EP93xx OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - .start = ohci_ep93xx_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, -}; - -extern int usb_disabled(void); - -static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) -{ - int ret; - - ret = -ENODEV; - if (!usb_disabled()) - ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev); - - return ret; -} - -static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_ep93xx_remove(hcd, pdev); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - ep93xx_stop_hc(&pdev->dev); - return 0; -} - -static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - ep93xx_start_hc(&pdev->dev); - - ohci_resume(hcd, false); - return 0; -} -#endif - - -static struct platform_driver ohci_hcd_ep93xx_driver = { - .probe = ohci_hcd_ep93xx_drv_probe, - .remove = ohci_hcd_ep93xx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM - .suspend = ohci_hcd_ep93xx_drv_suspend, - .resume = ohci_hcd_ep93xx_drv_resume, -#endif - .driver = { - .name = "ep93xx-ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:ep93xx-ohci"); diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index b0b542c14e3..060a6a41475 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -12,100 +12,139 @@ */ #include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> -#include <linux/platform_data/usb-ohci-exynos.h> +#include <linux/phy/phy.h> #include <linux/usb/phy.h> #include <linux/usb/samsung_usb_phy.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include "ohci.h" + +#define DRIVER_DESC "OHCI EXYNOS driver" + +static const char hcd_name[] = "ohci-exynos"; +static struct hc_driver __read_mostly exynos_ohci_hc_driver; + +#define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv) + +#define PHY_NUMBER 3 struct exynos_ohci_hcd { - struct device *dev; - struct usb_hcd *hcd; struct clk *clk; struct usb_phy *phy; struct usb_otg *otg; - struct exynos4_ohci_platdata *pdata; + struct phy *phy_g[PHY_NUMBER]; }; -static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) +static int exynos_ohci_get_phy(struct device *dev, + struct exynos_ohci_hcd *exynos_ohci) { - struct platform_device *pdev = to_platform_device(exynos_ohci->dev); + struct device_node *child; + struct phy *phy; + int phy_number; + int ret = 0; + + exynos_ohci->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR(exynos_ohci->phy)) { + ret = PTR_ERR(exynos_ohci->phy); + if (ret != -ENXIO && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } else { + exynos_ohci->otg = exynos_ohci->phy->otg; + } - if (exynos_ohci->phy) - usb_phy_init(exynos_ohci->phy); - else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_init) - exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); -} + /* + * Getting generic phy: + * We are keeping both types of phys as a part of transiting OHCI + * to generic phy framework, so as to maintain backward compatibilty + * with old DTB. + * If there are existing devices using DTB files built from them, + * to remove the support for old bindings in this driver, + * we need to make sure that such devices have their DTBs + * updated to ones built from new DTS. + */ + for_each_available_child_of_node(dev->of_node, child) { + ret = of_property_read_u32(child, "reg", &phy_number); + if (ret) { + dev_err(dev, "Failed to parse device tree\n"); + of_node_put(child); + return ret; + } -static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci) -{ - struct platform_device *pdev = to_platform_device(exynos_ohci->dev); + if (phy_number >= PHY_NUMBER) { + dev_err(dev, "Invalid number of PHYs\n"); + of_node_put(child); + return -EINVAL; + } - if (exynos_ohci->phy) - usb_phy_shutdown(exynos_ohci->phy); - else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_exit) - exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); + phy = devm_of_phy_get(dev, child, 0); + of_node_put(child); + if (IS_ERR(phy)) { + ret = PTR_ERR(phy); + if (ret != -ENOSYS && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } + exynos_ohci->phy_g[phy_number] = phy; + } + + return ret; } -static int ohci_exynos_reset(struct usb_hcd *hcd) +static int exynos_ohci_phy_enable(struct device *dev) { - return ohci_init(hcd_to_ohci(hcd)); + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + int i; + int ret = 0; + + if (!IS_ERR(exynos_ohci->phy)) + return usb_phy_init(exynos_ohci->phy); + + for (i = 0; ret == 0 && i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ohci->phy_g[i])) + ret = phy_power_on(exynos_ohci->phy_g[i]); + if (ret) + for (i--; i >= 0; i--) + if (!IS_ERR(exynos_ohci->phy_g[i])) + phy_power_off(exynos_ohci->phy_g[i]); + + return ret; } -static int ohci_exynos_start(struct usb_hcd *hcd) +static void exynos_ohci_phy_disable(struct device *dev) { - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + int i; - 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; + if (!IS_ERR(exynos_ohci->phy)) { + usb_phy_shutdown(exynos_ohci->phy); + return; } - return 0; + for (i = 0; i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ohci->phy_g[i])) + phy_power_off(exynos_ohci->phy_g[i]); } -static const struct hc_driver exynos_ohci_hc_driver = { - .description = hcd_name, - .product_desc = "EXYNOS OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - - .irq = ohci_irq, - .flags = HCD_MEMORY|HCD_USB11, - - .reset = ohci_exynos_reset, - .start = ohci_exynos_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - .get_frame_number = ohci_get_frame, - - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - .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 exynos_ohci_probe(struct platform_device *pdev) { - struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; struct exynos_ohci_hcd *exynos_ohci; struct usb_hcd *hcd; - struct ohci_hcd *ohci; struct resource *res; - struct usb_phy *phy; int irq; int err; @@ -114,46 +153,28 @@ static int exynos_ohci_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we move to full device tree support this will vanish off. */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - - exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd), - GFP_KERNEL); - if (!exynos_ohci) + err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + return err; + + hcd = usb_create_hcd(&exynos_ohci_hc_driver, + &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; + } + + exynos_ohci = to_exynos_ohci(hcd); if (of_device_is_compatible(pdev->dev.of_node, "samsung,exynos5440-ohci")) goto skip_phy; - phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR(phy)) { - /* Fallback to pdata */ - if (!pdata) { - dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; - } else { - exynos_ohci->pdata = pdata; - } - } else { - exynos_ohci->phy = phy; - exynos_ohci->otg = phy->otg; - } + err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci); + if (err) + goto fail_clk; skip_phy: - - exynos_ohci->dev = &pdev->dev; - - hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - return -ENOMEM; - } - - exynos_ohci->hcd = hcd; exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ohci->clk)) { @@ -175,10 +196,9 @@ skip_phy: hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to remap I/O memory\n"); - err = -ENOMEM; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + err = PTR_ERR(hcd->regs); goto fail_io; } @@ -190,26 +210,26 @@ skip_phy: } if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, - &exynos_ohci->hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - exynos_ohci_phy_enable(exynos_ohci); + platform_set_drvdata(pdev, hcd); - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); + err = exynos_ohci_phy_enable(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "Failed to enable USB phy\n"); + goto fail_io; + } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { dev_err(&pdev->dev, "Failed to add USB HCD\n"); goto fail_add_hcd; } - - platform_set_drvdata(pdev, exynos_ohci); - + device_wakeup_enable(hcd->self.controller); return 0; fail_add_hcd: - exynos_ohci_phy_disable(exynos_ohci); + exynos_ohci_phy_disable(&pdev->dev); fail_io: clk_disable_unprepare(exynos_ohci->clk); fail_clk: @@ -219,16 +239,15 @@ fail_clk: static int exynos_ohci_remove(struct platform_device *pdev) { - struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = exynos_ohci->hcd; + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); usb_remove_hcd(hcd); if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, - &exynos_ohci->hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - exynos_ohci_phy_disable(exynos_ohci); + exynos_ohci_phy_disable(&pdev->dev); clk_disable_unprepare(exynos_ohci->clk); @@ -239,8 +258,7 @@ static int exynos_ohci_remove(struct platform_device *pdev) static void exynos_ohci_shutdown(struct platform_device *pdev) { - struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = exynos_ohci->hcd; + struct usb_hcd *hcd = platform_get_drvdata(pdev); if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); @@ -249,53 +267,41 @@ static void exynos_ohci_shutdown(struct platform_device *pdev) #ifdef CONFIG_PM static int exynos_ohci_suspend(struct device *dev) { - struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); - struct usb_hcd *hcd = exynos_ohci->hcd; - 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 && - ohci->rh_state != OHCI_RH_HALTED) { - rc = -EINVAL; - goto fail; - } + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + bool do_wakeup = device_may_wakeup(dev); + int rc = ohci_suspend(hcd, do_wakeup); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + if (rc) + return rc; if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, - &exynos_ohci->hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - exynos_ohci_phy_disable(exynos_ohci); + exynos_ohci_phy_disable(dev); clk_disable_unprepare(exynos_ohci->clk); -fail: - spin_unlock_irqrestore(&ohci->lock, flags); - - return rc; + return 0; } static int exynos_ohci_resume(struct device *dev) { - struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); - struct usb_hcd *hcd = exynos_ohci->hcd; + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + int ret; clk_prepare_enable(exynos_ohci->clk); if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, - &exynos_ohci->hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - exynos_ohci_phy_enable(exynos_ohci); + ret = exynos_ohci_phy_enable(dev); + if (ret) { + dev_err(dev, "Failed to enable USB phy\n"); + clk_disable_unprepare(exynos_ohci->clk); + return ret; + } ohci_resume(hcd, false); @@ -306,6 +312,10 @@ static int exynos_ohci_resume(struct device *dev) #define exynos_ohci_resume NULL #endif +static const struct ohci_driver_overrides exynos_overrides __initconst = { + .extra_priv_size = sizeof(struct exynos_ohci_hcd), +}; + static const struct dev_pm_ops exynos_ohci_pm_ops = { .suspend = exynos_ohci_suspend, .resume = exynos_ohci_resume, @@ -331,6 +341,23 @@ static struct platform_driver exynos_ohci_driver = { .of_match_table = of_match_ptr(exynos_ohci_match), } }; +static int __init ohci_exynos_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ohci_init_driver(&exynos_ohci_hc_driver, &exynos_overrides); + return platform_driver_register(&exynos_ohci_driver); +} +module_init(ohci_exynos_init); + +static void __exit ohci_exynos_cleanup(void) +{ + platform_driver_unregister(&exynos_ohci_driver); +} +module_exit(ohci_exynos_cleanup); MODULE_ALIAS("platform:exynos-ohci"); MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index fc627fd5411..f98d03f3144 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -51,8 +51,6 @@ /*-------------------------------------------------------------------------*/ -#undef OHCI_VERBOSE_DEBUG /* not always helpful */ - /* For initializing controller (mask in an HCFS mode too) */ #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR #define OHCI_INTR_INIT \ @@ -79,23 +77,8 @@ static const char hcd_name [] = "ohci_hcd"; #include "pci-quirks.h" static void ohci_dump (struct ohci_hcd *ohci, int verbose); -static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); -#if defined(CONFIG_PM) || defined(CONFIG_PCI) -static int ohci_restart (struct ohci_hcd *ohci); -#endif - -#ifdef CONFIG_PCI -static void sb800_prefetch(struct ohci_hcd *ohci, int on); -#else -static inline void sb800_prefetch(struct ohci_hcd *ohci, int on) -{ - return; -} -#endif - - #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -142,10 +125,6 @@ static int ohci_urb_enqueue ( unsigned long flags; int retval = 0; -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); -#endif - /* every endpoint has a ed, locate and maybe (re)initialize it */ if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) return -ENOMEM; @@ -231,31 +210,26 @@ static int ohci_urb_enqueue ( frame &= ~(ed->interval - 1); frame |= ed->branch; urb->start_frame = frame; + ed->last_iso = frame + ed->interval * (size - 1); } } else if (ed->type == PIPE_ISOCHRONOUS) { u16 next = ohci_frame_no(ohci) + 1; u16 frame = ed->last_iso + ed->interval; + u16 length = ed->interval * (size - 1); /* Behind the scheduling threshold? */ if (unlikely(tick_before(frame, next))) { - /* USB_ISO_ASAP: Round up to the first available slot */ + /* URB_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. + * Not ASAP: Use the next slot in the stream, + * no matter what. */ } 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 @@ -266,9 +240,16 @@ static int ohci_urb_enqueue ( urb_priv->td_cnt = DIV_ROUND_UP( (u16) (next - frame), ed->interval); + if (urb_priv->td_cnt >= urb_priv->length) { + ++urb_priv->td_cnt; /* Mark it */ + ohci_dbg(ohci, "iso underrun %p (%u+%u < %u)\n", + urb, frame, length, + next); + } } } urb->start_frame = frame; + ed->last_iso = frame + length; } /* fill the TDs and link them to the ed; and @@ -297,10 +278,6 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) unsigned long flags; int rc; -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "UNLINK", 1, status); -#endif - spin_lock_irqsave (&ohci->lock, flags); rc = usb_hcd_check_unlink_urb(hcd, urb, status); if (rc) { @@ -772,6 +749,32 @@ retry: return 0; } +/* ohci_setup routine for generic controller initialization */ + +int ohci_setup(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci_hcd_init(ohci); + + return ohci_init(ohci); +} +EXPORT_SYMBOL_GPL(ohci_setup); + +/* ohci_start routine for generic controller start of all OHCI bus glue */ +static int ohci_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ret = ohci_run(ohci); + if (ret < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); + } + return ret; +} + /*-------------------------------------------------------------------------*/ /* an interrupt happens */ @@ -827,7 +830,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) } if (ints & OHCI_INTR_RHSC) { - ohci_vdbg(ohci, "rhsc\n"); + ohci_dbg(ohci, "rhsc\n"); ohci->next_statechange = jiffies + STATECHANGE_DELAY; ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC, ®s->intrstatus); @@ -849,7 +852,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) * this might not happen. */ else if (ints & OHCI_INTR_RD) { - ohci_vdbg(ohci, "resume detect\n"); + ohci_dbg(ohci, "resume detect\n"); ohci_writel(ohci, OHCI_INTR_RD, ®s->intrstatus); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); if (ohci->autostop) { @@ -927,8 +930,8 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_nec(ohci)) flush_work(&ohci->nec_work); - ohci_usb_reset (ohci); ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_usb_reset(ohci); free_irq(hcd->irq, hcd); hcd->irq = 0; @@ -953,12 +956,13 @@ static void ohci_stop (struct usb_hcd *hcd) #if defined(CONFIG_PM) || defined(CONFIG_PCI) /* must not be called from interrupt context */ -static int ohci_restart (struct ohci_hcd *ohci) +int ohci_restart(struct ohci_hcd *ohci) { int temp; int i; struct urb_priv *priv; + ohci_init(ohci); spin_lock_irq(&ohci->lock); ohci->rh_state = OHCI_RH_HALTED; @@ -1012,15 +1016,17 @@ static int ohci_restart (struct ohci_hcd *ohci) ohci_dbg(ohci, "restart complete\n"); return 0; } +EXPORT_SYMBOL_GPL(ohci_restart); #endif #ifdef CONFIG_PM -static int __maybe_unused ohci_suspend(struct usb_hcd *hcd, bool do_wakeup) +int ohci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; + int rc = 0; /* Disable irq emission and mark HW unaccessible. Use * the spinlock to properly synchronize with possible pending @@ -1033,11 +1039,18 @@ static int __maybe_unused ohci_suspend(struct usb_hcd *hcd, bool do_wakeup) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore (&ohci->lock, flags); - return 0; + synchronize_irq(hcd->irq); + + if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { + ohci_resume(hcd, false); + rc = -EBUSY; + } + return rc; } +EXPORT_SYMBOL_GPL(ohci_suspend); -static int __maybe_unused ohci_resume(struct usb_hcd *hcd, bool hibernated) +int ohci_resume(struct usb_hcd *hcd, bool hibernated) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); int port; @@ -1085,66 +1098,87 @@ static int __maybe_unused ohci_resume(struct usb_hcd *hcd, bool hibernated) return 0; } +EXPORT_SYMBOL_GPL(ohci_resume); #endif /*-------------------------------------------------------------------------*/ +/* + * Generic structure: This gets copied for platform drivers so that + * individual entries can be overridden as needed. + */ + +static const struct hc_driver ohci_hc_driver = { + .description = hcd_name, + .product_desc = "OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + /* + * basic lifecycle operations + */ + .reset = ohci_setup, + .start = ohci_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, +}; + +void ohci_init_driver(struct hc_driver *drv, + const struct ohci_driver_overrides *over) +{ + /* Copy the generic table to drv and then apply the overrides */ + *drv = ohci_hc_driver; + + if (over) { + drv->product_desc = over->product_desc; + drv->hcd_priv_size += over->extra_priv_size; + if (over->reset) + drv->reset = over->reset; + } +} +EXPORT_SYMBOL_GPL(ohci_init_driver); + +/*-------------------------------------------------------------------------*/ + MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE ("GPL"); -#ifdef CONFIG_PCI -#include "ohci-pci.c" -#define PCI_DRIVER ohci_pci_driver -#endif - #if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111) #include "ohci-sa1111.c" #define SA1111_DRIVER ohci_hcd_sa1111_driver #endif -#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) -#include "ohci-s3c2410.c" -#define S3C2410_PLATFORM_DRIVER ohci_hcd_s3c2410_driver -#endif - -#ifdef CONFIG_USB_OHCI_EXYNOS -#include "ohci-exynos.c" -#define EXYNOS_PLATFORM_DRIVER exynos_ohci_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_OMAP1 -#include "ohci-omap.c" -#define OMAP1_PLATFORM_DRIVER ohci_hcd_omap_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_OMAP3 -#include "ohci-omap3.c" -#define OMAP3_PLATFORM_DRIVER ohci_hcd_omap3_driver -#endif - -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) -#include "ohci-pxa27x.c" -#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver -#endif - -#ifdef CONFIG_ARCH_EP93XX -#include "ohci-ep93xx.c" -#define EP93XX_PLATFORM_DRIVER ohci_hcd_ep93xx_driver -#endif - -#ifdef CONFIG_ARCH_AT91 -#include "ohci-at91.c" -#define AT91_PLATFORM_DRIVER ohci_hcd_at91_driver -#endif - -#ifdef CONFIG_ARCH_LPC32XX -#include "ohci-nxp.c" -#define NXP_PLATFORM_DRIVER usb_hcd_nxp_driver -#endif - -#ifdef CONFIG_ARCH_DAVINCI_DA8XX +#ifdef CONFIG_USB_OHCI_HCD_DAVINCI #include "ohci-da8xx.c" #define DAVINCI_PLATFORM_DRIVER ohci_hcd_da8xx_driver #endif @@ -1154,11 +1188,6 @@ MODULE_LICENSE ("GPL"); #define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver #endif -#ifdef CONFIG_PLAT_SPEAR -#include "ohci-spear.c" -#define SPEAR_PLATFORM_DRIVER spear_ohci_hcd_driver -#endif - #ifdef CONFIG_PPC_PS3 #include "ohci-ps3.c" #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver @@ -1189,30 +1218,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_tilegx_driver #endif -#ifdef CONFIG_USB_OHCI_HCD_PLATFORM -#include "ohci-platform.c" -#define PLATFORM_DRIVER ohci_platform_driver -#endif - -#if !defined(PCI_DRIVER) && \ - !defined(PLATFORM_DRIVER) && \ - !defined(OMAP1_PLATFORM_DRIVER) && \ - !defined(OMAP3_PLATFORM_DRIVER) && \ - !defined(OF_PLATFORM_DRIVER) && \ - !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && \ - !defined(SM501_OHCI_DRIVER) && \ - !defined(TMIO_OHCI_DRIVER) && \ - !defined(S3C2410_PLATFORM_DRIVER) && \ - !defined(EXYNOS_PLATFORM_DRIVER) && \ - !defined(EP93XX_PLATFORM_DRIVER) && \ - !defined(AT91_PLATFORM_DRIVER) && \ - !defined(NXP_PLATFORM_DRIVER) && \ - !defined(DAVINCI_PLATFORM_DRIVER) && \ - !defined(SPEAR_PLATFORM_DRIVER) -#error "missing bus glue for ohci-hcd" -#endif - static int __init ohci_hcd_mod_init(void) { int retval = 0; @@ -1225,13 +1230,11 @@ static int __init ohci_hcd_mod_init(void) sizeof (struct ed), sizeof (struct td)); set_bit(USB_OHCI_LOADED, &usb_hcds_loaded); -#ifdef DEBUG ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root); if (!ohci_debug_root) { retval = -ENOENT; goto error_debug; } -#endif #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER); @@ -1245,18 +1248,6 @@ static int __init ohci_hcd_mod_init(void) goto error_platform; #endif -#ifdef OMAP1_PLATFORM_DRIVER - retval = platform_driver_register(&OMAP1_PLATFORM_DRIVER); - if (retval < 0) - goto error_omap1_platform; -#endif - -#ifdef OMAP3_PLATFORM_DRIVER - retval = platform_driver_register(&OMAP3_PLATFORM_DRIVER); - if (retval < 0) - goto error_omap3_platform; -#endif - #ifdef OF_PLATFORM_DRIVER retval = platform_driver_register(&OF_PLATFORM_DRIVER); if (retval < 0) @@ -1269,12 +1260,6 @@ static int __init ohci_hcd_mod_init(void) goto error_sa1111; #endif -#ifdef PCI_DRIVER - retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) - goto error_pci; -#endif - #ifdef SM501_OHCI_DRIVER retval = platform_driver_register(&SM501_OHCI_DRIVER); if (retval < 0) @@ -1287,79 +1272,19 @@ static int __init ohci_hcd_mod_init(void) goto error_tmio; #endif -#ifdef S3C2410_PLATFORM_DRIVER - retval = platform_driver_register(&S3C2410_PLATFORM_DRIVER); - if (retval < 0) - goto error_s3c2410; -#endif - -#ifdef EXYNOS_PLATFORM_DRIVER - retval = platform_driver_register(&EXYNOS_PLATFORM_DRIVER); - if (retval < 0) - goto error_exynos; -#endif - -#ifdef EP93XX_PLATFORM_DRIVER - retval = platform_driver_register(&EP93XX_PLATFORM_DRIVER); - if (retval < 0) - goto error_ep93xx; -#endif - -#ifdef AT91_PLATFORM_DRIVER - retval = platform_driver_register(&AT91_PLATFORM_DRIVER); - if (retval < 0) - goto error_at91; -#endif - -#ifdef NXP_PLATFORM_DRIVER - retval = platform_driver_register(&NXP_PLATFORM_DRIVER); - if (retval < 0) - goto error_nxp; -#endif - #ifdef DAVINCI_PLATFORM_DRIVER retval = platform_driver_register(&DAVINCI_PLATFORM_DRIVER); if (retval < 0) goto error_davinci; #endif -#ifdef SPEAR_PLATFORM_DRIVER - retval = platform_driver_register(&SPEAR_PLATFORM_DRIVER); - if (retval < 0) - goto error_spear; -#endif - return retval; /* Error path */ -#ifdef SPEAR_PLATFORM_DRIVER - platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); - error_spear: -#endif #ifdef DAVINCI_PLATFORM_DRIVER platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); error_davinci: #endif -#ifdef NXP_PLATFORM_DRIVER - platform_driver_unregister(&NXP_PLATFORM_DRIVER); - error_nxp: -#endif -#ifdef AT91_PLATFORM_DRIVER - platform_driver_unregister(&AT91_PLATFORM_DRIVER); - error_at91: -#endif -#ifdef EP93XX_PLATFORM_DRIVER - platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); - error_ep93xx: -#endif -#ifdef EXYNOS_PLATFORM_DRIVER - platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); - error_exynos: -#endif -#ifdef S3C2410_PLATFORM_DRIVER - platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); - error_s3c2410: -#endif #ifdef TMIO_OHCI_DRIVER platform_driver_unregister(&TMIO_OHCI_DRIVER); error_tmio: @@ -1368,10 +1293,6 @@ static int __init ohci_hcd_mod_init(void) platform_driver_unregister(&SM501_OHCI_DRIVER); error_sm501: #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); - error_pci: -#endif #ifdef SA1111_DRIVER sa1111_driver_unregister(&SA1111_DRIVER); error_sa1111: @@ -1380,14 +1301,6 @@ static int __init ohci_hcd_mod_init(void) platform_driver_unregister(&OF_PLATFORM_DRIVER); error_of_platform: #endif -#ifdef OMAP3_PLATFORM_DRIVER - platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); - error_omap3_platform: -#endif -#ifdef OMAP1_PLATFORM_DRIVER - platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); - error_omap1_platform: -#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); error_platform: @@ -1396,11 +1309,9 @@ static int __init ohci_hcd_mod_init(void) ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); error_ps3: #endif -#ifdef DEBUG debugfs_remove(ohci_debug_root); ohci_debug_root = NULL; error_debug: -#endif clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); return retval; @@ -1409,57 +1320,28 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { -#ifdef SPEAR_PLATFORM_DRIVER - platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); -#endif #ifdef DAVINCI_PLATFORM_DRIVER platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); #endif -#ifdef NXP_PLATFORM_DRIVER - platform_driver_unregister(&NXP_PLATFORM_DRIVER); -#endif -#ifdef AT91_PLATFORM_DRIVER - platform_driver_unregister(&AT91_PLATFORM_DRIVER); -#endif -#ifdef EP93XX_PLATFORM_DRIVER - platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); -#endif -#ifdef EXYNOS_PLATFORM_DRIVER - platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); -#endif -#ifdef S3C2410_PLATFORM_DRIVER - platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); -#endif #ifdef TMIO_OHCI_DRIVER platform_driver_unregister(&TMIO_OHCI_DRIVER); #endif #ifdef SM501_OHCI_DRIVER platform_driver_unregister(&SM501_OHCI_DRIVER); #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -#endif #ifdef SA1111_DRIVER sa1111_driver_unregister(&SA1111_DRIVER); #endif #ifdef OF_PLATFORM_DRIVER platform_driver_unregister(&OF_PLATFORM_DRIVER); #endif -#ifdef OMAP3_PLATFORM_DRIVER - platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); -#endif -#ifdef OMAP1_PLATFORM_DRIVER - platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); -#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif -#ifdef DEBUG debugfs_remove(ohci_debug_root); -#endif clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); } module_exit(ohci_hcd_mod_exit); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 60ff4220e8b..b4940de1eba 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -90,6 +90,24 @@ __acquires(ohci->lock) dl_done_list (ohci); finish_unlinks (ohci, ohci_frame_no(ohci)); + /* + * Some controllers don't handle "global" suspend properly if + * there are unsuspended ports. For these controllers, put all + * the enabled ports into suspend before suspending the root hub. + */ + if (ohci->flags & OHCI_QUIRK_GLOBAL_SUSPEND) { + __hc32 __iomem *portstat = ohci->regs->roothub.portstatus; + int i; + unsigned temp; + + for (i = 0; i < ohci->num_ports; (++i, ++portstat)) { + temp = ohci_readl(ohci, portstat); + if ((temp & (RH_PS_PES | RH_PS_PSS)) == + RH_PS_PES) + ohci_writel(ohci, RH_PS_PSS, portstat); + } + } + /* maybe resume can wake root hub */ if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) { ohci->hc_control |= OHCI_CTRL_RWE; @@ -176,7 +194,6 @@ __acquires(ohci->lock) if (status == -EBUSY) { if (!autostopped) { spin_unlock_irq (&ohci->lock); - (void) ohci_init (ohci); status = ohci_restart (ohci); usb_root_hub_lost_power(hcd->self.root_hub); @@ -213,10 +230,11 @@ __acquires(ohci->lock) /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); - /* the following code is executed with ohci->lock held and - * irqs disabled if and only if autostopped is true + /* + * The following code is executed with ohci->lock held and + * irqs disabled if and only if autostopped is true. This + * will cause sparse to warn about a "context imbalance". */ - skip_resume: /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); @@ -438,8 +456,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, /* build "status change" packet (one or two bytes) from HC registers */ -static int -ohci_hub_status_data (struct usb_hcd *hcd, char *buf) +int ohci_hub_status_data(struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; @@ -504,6 +521,7 @@ done: return changed ? length : 0; } +EXPORT_SYMBOL_GPL(ohci_hub_status_data); /*-------------------------------------------------------------------------*/ @@ -532,7 +550,7 @@ ohci_hub_descriptor ( temp |= 0x0010; else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */ temp |= 0x0008; - desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp); + desc->wHubCharacteristics = cpu_to_le16(temp); /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ rh = roothub_b (ohci); @@ -646,7 +664,7 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) return 0; } -static int ohci_hub_control ( +int ohci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -725,10 +743,8 @@ static int ohci_hub_control ( temp = roothub_portstatus (ohci, wIndex); put_unaligned_le32(temp, buf); -#ifndef OHCI_VERBOSE_DEBUG - if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ -#endif - dbg_port (ohci, "GetStatus", wIndex, temp); + if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ + dbg_port(ohci, "GetStatus", wIndex, temp); break; case SetHubFeature: switch (wValue) { @@ -774,4 +790,4 @@ error: } return retval; } - +EXPORT_SYMBOL_GPL(ohci_hub_control); diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c index 8062bb9dea1..c2c221a332e 100644 --- a/drivers/usb/host/ohci-jz4740.c +++ b/drivers/usb/host/ohci-jz4740.c @@ -82,14 +82,14 @@ static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - int ret; + int ret = 0; switch (typeReq) { - case SetHubFeature: + case SetPortFeature: if (wValue == USB_PORT_FEAT_POWER) ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true); break; - case ClearHubFeature: + case ClearPortFeature: if (wValue == USB_PORT_FEAT_POWER) ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false); break; @@ -174,31 +174,23 @@ static int jz4740_ohci_probe(struct platform_device *pdev) jz4740_ohci = hcd_to_jz4740_hcd(hcd); - res = request_mem_region(res->start, resource_size(res), hcd_name); - if (!res) { - dev_err(&pdev->dev, "Failed to request mem region.\n"); - ret = -EBUSY; - goto err_free; - } - hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(res->start, resource_size(res)); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to ioremap registers.\n"); - ret = -EBUSY; - goto err_release_mem; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); + goto err_free; } - jz4740_ohci->clk = clk_get(&pdev->dev, "uhc"); + jz4740_ohci->clk = devm_clk_get(&pdev->dev, "uhc"); if (IS_ERR(jz4740_ohci->clk)) { ret = PTR_ERR(jz4740_ohci->clk); dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); - goto err_iounmap; + goto err_free; } - jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus"); + jz4740_ohci->vbus = devm_regulator_get(&pdev->dev, "vbus"); if (IS_ERR(jz4740_ohci->vbus)) jz4740_ohci->vbus = NULL; @@ -217,22 +209,15 @@ static int jz4740_ohci_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret); goto err_disable; } + device_wakeup_enable(hcd->self.controller); return 0; err_disable: - platform_set_drvdata(pdev, NULL); - if (jz4740_ohci->vbus) { + if (jz4740_ohci->vbus) regulator_disable(jz4740_ohci->vbus); - regulator_put(jz4740_ohci->vbus); - } clk_disable(jz4740_ohci->clk); - clk_put(jz4740_ohci->clk); -err_iounmap: - iounmap(hcd->regs); -err_release_mem: - release_mem_region(res->start, resource_size(res)); err_free: usb_put_hcd(hcd); @@ -246,18 +231,10 @@ static int jz4740_ohci_remove(struct platform_device *pdev) usb_remove_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - if (jz4740_ohci->vbus) { + if (jz4740_ohci->vbus) regulator_disable(jz4740_ohci->vbus); - regulator_put(jz4740_ohci->vbus); - } clk_disable(jz4740_ohci->clk); - clk_put(jz4740_ohci->clk); - - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 5d7eb72c506..ba180ed0f81 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -19,10 +19,19 @@ * or implied. */ #include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> #include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of.h> +#include <linux/platform_device.h> #include <linux/usb/isp1301.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" + #include <mach/hardware.h> #include <asm/mach-types.h> @@ -57,6 +66,11 @@ #define start_int_umask(irq) #endif +#define DRIVER_DESC "OHCI NXP driver" + +static const char hcd_name[] = "ohci-nxp"; +static struct hc_driver __read_mostly ohci_nxp_hc_driver; + static struct i2c_client *isp1301_i2c_client; extern int usb_disabled(void); @@ -132,14 +146,14 @@ static inline void isp1301_vbus_off(void) OTG1_VBUS_DRV); } -static void nxp_start_hc(void) +static void ohci_nxp_start_hc(void) { unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN; __raw_writel(tmp, USB_OTG_STAT_CONTROL); isp1301_vbus_on(); } -static void nxp_stop_hc(void) +static void ohci_nxp_stop_hc(void) { unsigned long tmp; isp1301_vbus_off(); @@ -147,68 +161,9 @@ static void nxp_stop_hc(void) __raw_writel(tmp, USB_OTG_STAT_CONTROL); } -static int ohci_nxp_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\n"); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static const struct hc_driver ohci_nxp_hc_driver = { - .description = hcd_name, - .product_desc = "nxp OHCI", - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - .hcd_priv_size = sizeof(struct ohci_hcd), - /* - * basic lifecycle operations - */ - .start = ohci_nxp_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 usb_hcd_nxp_probe(struct platform_device *pdev) +static int ohci_hcd_nxp_probe(struct platform_device *pdev) { struct usb_hcd *hcd = 0; - struct ohci_hcd *ohci; const struct hc_driver *driver = &ohci_nxp_hc_driver; struct resource *res; int ret = 0, irq; @@ -226,8 +181,9 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + goto fail_disable; dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); if (usb_disabled()) { @@ -240,17 +196,17 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) __raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL); /* Enable USB PLL */ - usb_pll_clk = clk_get(&pdev->dev, "ck_pll5"); + usb_pll_clk = devm_clk_get(&pdev->dev, "ck_pll5"); if (IS_ERR(usb_pll_clk)) { dev_err(&pdev->dev, "failed to acquire USB PLL\n"); ret = PTR_ERR(usb_pll_clk); - goto fail_pll; + goto fail_disable; } ret = clk_enable(usb_pll_clk); if (ret < 0) { dev_err(&pdev->dev, "failed to start USB PLL\n"); - goto fail_pllen; + goto fail_disable; } ret = clk_set_rate(usb_pll_clk, 48000); @@ -260,21 +216,21 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) } /* Enable USB device clock */ - usb_dev_clk = clk_get(&pdev->dev, "ck_usbd"); + usb_dev_clk = devm_clk_get(&pdev->dev, "ck_usbd"); if (IS_ERR(usb_dev_clk)) { dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n"); ret = PTR_ERR(usb_dev_clk); - goto fail_dev; + goto fail_rate; } ret = clk_enable(usb_dev_clk); if (ret < 0) { dev_err(&pdev->dev, "failed to start USB DEV Clock\n"); - goto fail_deven; + goto fail_rate; } /* Enable USB otg clocks */ - usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg"); + usb_otg_clk = devm_clk_get(&pdev->dev, "ck_usb_otg"); if (IS_ERR(usb_otg_clk)) { dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n"); ret = PTR_ERR(usb_otg_clk); @@ -286,7 +242,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) ret = clk_enable(usb_otg_clk); if (ret < 0) { dev_err(&pdev->dev, "failed to start USB DEV Clock\n"); - goto fail_otgen; + goto fail_otg; } isp1301_configure(); @@ -313,55 +269,42 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) goto fail_resource; } - nxp_start_hc(); + ohci_nxp_start_hc(); platform_set_drvdata(pdev, hcd); - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); ret = usb_add_hcd(hcd, irq, 0); - if (ret == 0) + if (ret == 0) { + device_wakeup_enable(hcd->self.controller); return ret; + } - nxp_stop_hc(); + ohci_nxp_stop_hc(); fail_resource: usb_put_hcd(hcd); fail_hcd: clk_disable(usb_otg_clk); -fail_otgen: - clk_put(usb_otg_clk); fail_otg: clk_disable(usb_dev_clk); -fail_deven: - clk_put(usb_dev_clk); -fail_dev: fail_rate: clk_disable(usb_pll_clk); -fail_pllen: - clk_put(usb_pll_clk); -fail_pll: fail_disable: isp1301_i2c_client = NULL; return ret; } -static int usb_hcd_nxp_remove(struct platform_device *pdev) +static int ohci_hcd_nxp_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - nxp_stop_hc(); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + ohci_nxp_stop_hc(); usb_put_hcd(hcd); clk_disable(usb_pll_clk); - clk_put(usb_pll_clk); clk_disable(usb_dev_clk); - clk_put(usb_dev_clk); i2c_unregister_device(isp1301_i2c_client); isp1301_i2c_client = NULL; - platform_set_drvdata(pdev, NULL); - return 0; } @@ -369,20 +312,40 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev) MODULE_ALIAS("platform:usb-ohci"); #ifdef CONFIG_OF -static const struct of_device_id usb_hcd_nxp_match[] = { +static const struct of_device_id ohci_hcd_nxp_match[] = { { .compatible = "nxp,ohci-nxp" }, {}, }; -MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match); +MODULE_DEVICE_TABLE(of, ohci_hcd_nxp_match); #endif -static struct platform_driver usb_hcd_nxp_driver = { +static struct platform_driver ohci_hcd_nxp_driver = { .driver = { .name = "usb-ohci", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(usb_hcd_nxp_match), + .of_match_table = of_match_ptr(ohci_hcd_nxp_match), }, - .probe = usb_hcd_nxp_probe, - .remove = usb_hcd_nxp_remove, + .probe = ohci_hcd_nxp_probe, + .remove = ohci_hcd_nxp_remove, }; +static int __init ohci_nxp_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ohci_init_driver(&ohci_nxp_hc_driver, NULL); + return platform_driver_register(&ohci_hcd_nxp_driver); +} +module_init(ohci_nxp_init); + +static void __exit ohci_nxp_cleanup(void) +{ + platform_driver_unregister(&ohci_hcd_nxp_driver); +} +module_exit(ohci_nxp_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c index d44430d009f..15af8954085 100644 --- a/drivers/usb/host/ohci-octeon.c +++ b/drivers/usb/host/ohci-octeon.c @@ -127,8 +127,9 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev) } /* Ohci is a 32-bit device. */ - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); if (!hcd) @@ -137,20 +138,12 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - OCTEON_OHCI_HCD_NAME)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; + reg_base = devm_ioremap_resource(&pdev->dev, res_mem); + if (IS_ERR(reg_base)) { + ret = PTR_ERR(reg_base); goto err1; } - reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!reg_base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err2; - } - ohci_octeon_hw_start(); hcd->regs = reg_base; @@ -167,19 +160,18 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev) ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) { dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); - goto err3; + goto err2; } + device_wakeup_enable(hcd->self.controller); + platform_set_drvdata(pdev, hcd); return 0; -err3: +err2: ohci_octeon_hw_stop(); - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); return ret; @@ -192,12 +184,8 @@ static int ohci_octeon_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); ohci_octeon_hw_stop(); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index b1d32fb4a7a..c923cafcaca 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -14,12 +14,21 @@ * This file is licenced under the GPL. */ -#include <linux/signal.h> -#include <linux/jiffies.h> -#include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/gpio.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb/otg.h> +#include <linux/platform_device.h> +#include <linux/signal.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" #include <asm/io.h> #include <asm/mach-types.h> @@ -42,10 +51,7 @@ #define OMAP1510_LB_MMU_RAM_H 0xfffec234 #define OMAP1510_LB_MMU_RAM_L 0xfffec238 - -#ifndef CONFIG_ARCH_OMAP -#error "This file is OMAP bus glue. CONFIG_OMAP must be defined." -#endif +#define DRIVER_DESC "OHCI OMAP driver" #ifdef CONFIG_TPS65010 #include <linux/i2c/tps65010.h> @@ -68,8 +74,9 @@ extern int ocpi_enable(void); static struct clk *usb_host_ck; static struct clk *usb_dc_ck; -static int host_enabled; -static int host_initialized; + +static const char hcd_name[] = "ohci-omap"; +static struct hc_driver __read_mostly ohci_omap_hc_driver; static void omap_ohci_clock_power(int on) { @@ -188,19 +195,19 @@ static void start_hnp(struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -static int ohci_omap_init(struct usb_hcd *hcd) +static int ohci_omap_reset(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct omap_usb_config *config = hcd->self.controller->platform_data; + struct omap_usb_config *config = dev_get_platdata(hcd->self.controller); int need_transceiver = (config->otg != 0); int ret; dev_dbg(hcd->self.controller, "starting USB Controller\n"); if (config->otg) { - ohci_to_hcd(ohci)->self.otg_port = config->otg; + hcd->self.otg_port = config->otg; /* default/minimum OTG power budget: 8 mA */ - ohci_to_hcd(ohci)->power_budget = 8; + hcd->power_budget = 8; } /* boards can use OTG transceivers in non-OTG modes */ @@ -238,9 +245,15 @@ static int ohci_omap_init(struct usb_hcd *hcd) omap_1510_local_bus_init(); } - if ((ret = ohci_init(ohci)) < 0) + ret = ohci_setup(hcd); + if (ret < 0) return ret; + if (config->otg || config->rwc) { + ohci->hc_control = OHCI_CTRL_RWC; + writel(OHCI_CTRL_RWC, &ohci->regs->control); + } + /* board-specific power switching and overcurrent support */ if (machine_is_omap_osk() || machine_is_omap_innovator()) { u32 rh = roothub_a (ohci); @@ -281,14 +294,6 @@ static int ohci_omap_init(struct usb_hcd *hcd) return 0; } -static void ohci_omap_stop(struct usb_hcd *hcd) -{ - dev_dbg(hcd->self.controller, "stopping USB Controller\n"); - ohci_stop(hcd); - omap_ohci_clock_power(0); -} - - /*-------------------------------------------------------------------------*/ /** @@ -304,17 +309,16 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver, { int retval, irq; struct usb_hcd *hcd = 0; - struct ohci_hcd *ohci; if (pdev->num_resources != 2) { - printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", + dev_err(&pdev->dev, "invalid num_resources: %i\n", pdev->num_resources); return -ENODEV; } if (pdev->resource[0].flags != IORESOURCE_MEM || pdev->resource[1].flags != IORESOURCE_IRQ) { - printk(KERN_ERR "hcd probe: invalid resource type\n"); + dev_err(&pdev->dev, "invalid resource type\n"); return -ENODEV; } @@ -354,12 +358,6 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver, goto err2; } - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); - - host_initialized = 0; - host_enabled = 1; - irq = platform_get_irq(pdev, 0); if (irq < 0) { retval = -ENXIO; @@ -369,11 +367,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver, if (retval) goto err3; - host_initialized = 1; - - if (!host_enabled) - omap_ohci_clock_power(0); - + device_wakeup_enable(hcd->self.controller); return 0; err3: iounmap(hcd->regs); @@ -402,7 +396,9 @@ err0: static inline void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) { + dev_dbg(hcd->self.controller, "stopping USB Controller\n"); usb_remove_hcd(hcd); + omap_ohci_clock_power(0); if (!IS_ERR_OR_NULL(hcd->phy)) { (void) otg_set_host(hcd->phy->otg, 0); usb_put_phy(hcd->phy); @@ -418,76 +414,6 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) /*-------------------------------------------------------------------------*/ -static int -ohci_omap_start (struct usb_hcd *hcd) -{ - struct omap_usb_config *config; - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - if (!host_enabled) - return 0; - config = hcd->self.controller->platform_data; - if (config->otg || config->rwc) { - ohci->hc_control = OHCI_CTRL_RWC; - writel(OHCI_CTRL_RWC, &ohci->regs->control); - } - - if ((ret = ohci_run (ohci)) < 0) { - dev_err(hcd->self.controller, "can't start\n"); - ohci_stop (hcd); - return ret; - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_omap_hc_driver = { - .description = hcd_name, - .product_desc = "OMAP OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_omap_init, - .start = ohci_omap_start, - .stop = ohci_omap_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_omap_drv_probe(struct platform_device *dev) { return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev); @@ -498,7 +424,6 @@ static int ohci_hcd_omap_drv_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); usb_hcd_omap_remove(hcd, dev); - platform_set_drvdata(dev, NULL); return 0; } @@ -507,16 +432,23 @@ static int ohci_hcd_omap_drv_remove(struct platform_device *dev) #ifdef CONFIG_PM -static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message) +static int ohci_omap_suspend(struct platform_device *pdev, pm_message_t message) { - struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev)); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + bool do_wakeup = device_may_wakeup(&pdev->dev); + int ret; if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; + ret = ohci_suspend(hcd, do_wakeup); + if (ret) + return ret; + omap_ohci_clock_power(0); - return 0; + return ret; } static int ohci_omap_resume(struct platform_device *dev) @@ -554,4 +486,29 @@ static struct platform_driver ohci_hcd_omap_driver = { }, }; +static const struct ohci_driver_overrides omap_overrides __initconst = { + .product_desc = "OMAP OHCI", + .reset = ohci_omap_reset +}; + +static int __init ohci_omap_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ohci_init_driver(&ohci_omap_hc_driver, &omap_overrides); + return platform_driver_register(&ohci_hcd_omap_driver); +} +module_init(ohci_omap_init); + +static void __exit ohci_omap_cleanup(void) +{ + platform_driver_unregister(&ohci_hcd_omap_driver); +} +module_exit(ohci_omap_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_ALIAS("platform:ohci"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index 8663851c8d8..ec15aebe878 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -29,90 +29,22 @@ * - add kernel-doc */ +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/usb/otg.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/of.h> -#include <linux/dma-mapping.h> - -/*-------------------------------------------------------------------------*/ - -static int ohci_omap3_init(struct usb_hcd *hcd) -{ - dev_dbg(hcd->self.controller, "starting OHCI controller\n"); - - return ohci_init(hcd_to_ohci(hcd)); -} - -/*-------------------------------------------------------------------------*/ - -static int ohci_omap3_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - /* - * RemoteWakeupConnected has to be set explicitly before - * calling ohci_run. The reset value of RWC is 0. - */ - ohci->hc_control = OHCI_CTRL_RWC; - writel(OHCI_CTRL_RWC, &ohci->regs->control); - - ret = ohci_run(ohci); - - if (ret < 0) { - dev_err(hcd->self.controller, "can't start\n"); - ohci_stop(hcd); - } - - return ret; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_omap3_hc_driver = { - .description = hcd_name, - .product_desc = "OMAP3 OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_omap3_init, - .start = ohci_omap3_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, +#include <linux/usb.h> +#include <linux/usb/hcd.h> - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, +#include "ohci.h" - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, +#define DRIVER_DESC "OHCI OMAP3 driver" - /* - * 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 const char hcd_name[] = "ohci-omap3"; +static struct hc_driver __read_mostly ohci_omap3_hc_driver; /* * configure so an HC device and id are always provided @@ -129,10 +61,11 @@ static const struct hc_driver ohci_omap3_hc_driver = { static int ohci_hcd_omap3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct ohci_hcd *ohci; struct usb_hcd *hcd = NULL; void __iomem *regs = NULL; struct resource *res; - int ret = -ENODEV; + int ret; int irq; if (usb_disabled()) @@ -166,11 +99,11 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - if (!dev->dma_mask) - dev->dma_mask = &dev->coherent_dma_mask; - if (!dev->coherent_dma_mask) - dev->coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + goto err_io; + ret = -ENODEV; hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev, dev_name(dev)); if (!hcd) { @@ -185,13 +118,19 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_get_sync(dev); - ohci_hcd_init(hcd_to_ohci(hcd)); + ohci = hcd_to_ohci(hcd); + /* + * RemoteWakeupConnected has to be set explicitly before + * calling ohci_run. The reset value of RWC is 0. + */ + ohci->hc_control = OHCI_CTRL_RWC; ret = usb_add_hcd(hcd, irq, 0); if (ret) { dev_dbg(dev, "failed to add hcd with err %d\n", ret); goto err_add_hcd; } + device_wakeup_enable(hcd->self.controller); return 0; @@ -231,14 +170,6 @@ static int ohci_hcd_omap3_remove(struct platform_device *pdev) return 0; } -static void ohci_hcd_omap3_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - static const struct of_device_id omap_ohci_dt_ids[] = { { .compatible = "ti,ohci-omap3" }, { } @@ -249,12 +180,32 @@ MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids); static struct platform_driver ohci_hcd_omap3_driver = { .probe = ohci_hcd_omap3_probe, .remove = ohci_hcd_omap3_remove, - .shutdown = ohci_hcd_omap3_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ohci-omap3", - .of_match_table = of_match_ptr(omap_ohci_dt_ids), + .of_match_table = omap_ohci_dt_ids, }, }; +static int __init ohci_omap3_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ohci_init_driver(&ohci_omap3_hc_driver, NULL); + return platform_driver_register(&ohci_hcd_omap3_driver); +} +module_init(ohci_omap3_init); + +static void __exit ohci_omap3_cleanup(void) +{ + platform_driver_unregister(&ohci_hcd_omap3_driver); +} +module_exit(ohci_omap3_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_ALIAS("platform:ohci-omap3"); MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 951514ef446..bb150967572 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -14,12 +14,19 @@ * This file is licenced under the GPL. */ -#ifndef CONFIG_PCI -#error "This file is PCI bus glue. CONFIG_PCI must be defined." -#endif - -#include <linux/pci.h> #include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" +#include "pci-quirks.h" + +#define DRIVER_DESC "OHCI PCI platform driver" + +static const char hcd_name[] = "ohci-pci"; /*-------------------------------------------------------------------------*/ @@ -123,13 +130,6 @@ static void ohci_quirk_nec_worker(struct work_struct *work) struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); int status; - status = ohci_init(ohci); - if (status != 0) { - ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", - "ohci_init", status); - return; - } - status = ohci_restart(ohci); if (status != 0) ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", @@ -150,44 +150,20 @@ static int ohci_quirk_nec(struct usb_hcd *hcd) static int ohci_quirk_amd700(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct pci_dev *amd_smbus_dev; - u8 rev; if (usb_amd_find_chipset_info()) ohci->flags |= OHCI_QUIRK_AMD_PLL; - amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, - PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); - if (!amd_smbus_dev) - return 0; - - rev = amd_smbus_dev->revision; - /* SB800 needs pre-fetch fix */ - if ((rev >= 0x40) && (rev <= 0x4f)) { + if (usb_amd_prefetch_quirk()) { ohci->flags |= OHCI_QUIRK_AMD_PREFETCH; ohci_dbg(ohci, "enabled AMD prefetch quirk\n"); } - pci_dev_put(amd_smbus_dev); - amd_smbus_dev = NULL; - + ohci->flags |= OHCI_QUIRK_GLOBAL_SUSPEND; return 0; } -static void sb800_prefetch(struct ohci_hcd *ohci, int on) -{ - struct pci_dev *pdev; - u16 misc; - - pdev = to_pci_dev(ohci_to_hcd(ohci)->self.controller); - pci_read_config_word(pdev, 0x50, &misc); - if (on == 0) - pci_write_config_word(pdev, 0x50, misc & 0xfcff); - else - pci_write_config_word(pdev, 0x50, misc | 0x0300); -} - /* List of quirks for OHCI */ static const struct pci_device_id ohci_pci_quirks[] = { { @@ -249,10 +225,10 @@ static const struct pci_device_id ohci_pci_quirks[] = { static int ohci_pci_reset (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int ret = 0; if (hcd->self.controller) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); const struct pci_device_id *quirk_id; quirk_id = pci_match_id(ohci_pci_quirks, pdev); @@ -262,94 +238,25 @@ static int ohci_pci_reset (struct usb_hcd *hcd) ret = quirk(hcd); } } - if (ret == 0) { - ohci_hcd_init (ohci); - return ohci_init (ohci); - } - return ret; -} - -static int ohci_pci_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - -#ifdef CONFIG_PM /* avoid warnings about unused pdev */ - if (hcd->self.controller) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* RWC may not be set for add-in PCI cards, since boot - * firmware probably ignored them. This transfers PCI - * PM wakeup capabilities. - */ - if (device_can_wakeup(&pdev->dev)) - ohci->hc_control |= OHCI_CTRL_RWC; - } -#endif /* CONFIG_PM */ - - ret = ohci_run (ohci); - if (ret < 0) { - ohci_err (ohci, "can't start\n"); - ohci_stop (hcd); - } + if (ret == 0) + ret = ohci_setup(hcd); + /* + * After ohci setup RWC may not be set for add-in PCI cards. + * This transfers PCI PM wakeup capabilities. + */ + if (device_can_wakeup(&pdev->dev)) + ohci->hc_control |= OHCI_CTRL_RWC; return ret; } +static struct hc_driver __read_mostly ohci_pci_hc_driver; -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_pci_hc_driver = { - .description = hcd_name, - .product_desc = "OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - /* - * basic lifecycle operations - */ +static const struct ohci_driver_overrides pci_overrides __initconst = { + .product_desc = "OHCI PCI host controller", .reset = ohci_pci_reset, - .start = ohci_pci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - -#ifdef CONFIG_PM - .pci_suspend = ohci_suspend, - .pci_resume = ohci_resume, -#endif - - /* - * 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 const struct pci_device_id pci_ids [] = { { /* handle any USB OHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0), @@ -371,9 +278,38 @@ static struct pci_driver ohci_pci_driver = { .remove = usb_hcd_pci_remove, .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, #endif }; + +static int __init ohci_pci_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ohci_init_driver(&ohci_pci_hc_driver, &pci_overrides); + +#ifdef CONFIG_PM + /* Entries for the PCI suspend/resume callbacks are special */ + ohci_pci_hc_driver.pci_suspend = ohci_suspend; + ohci_pci_hc_driver.pci_resume = ohci_resume; +#endif + + return pci_register_driver(&ohci_pci_driver); +} +module_init(ohci_pci_init); + +static void __exit ohci_pci_cleanup(void) +{ + pci_unregister_driver(&ohci_pci_driver); +} +module_exit(ohci_pci_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: ehci_pci"); diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index c3e7287f792..4369299064c 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -3,6 +3,7 @@ * * Copyright 2007 Michael Buesch <m@bues.ch> * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright 2014 Hans de Goede <hdegoede@redhat.com> * * Derived from the OCHI-SSB driver * Derived from the OHCI-PCI driver @@ -13,93 +14,135 @@ * * Licensed under the GNU/GPL. See COPYING for details. */ + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/hrtimer.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/err.h> +#include <linux/phy/phy.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/usb/ohci_pdriver.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" + +#define DRIVER_DESC "OHCI generic platform driver" +#define OHCI_MAX_CLKS 3 +#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv) + +struct ohci_platform_priv { + struct clk *clks[OHCI_MAX_CLKS]; + struct reset_control *rst; + struct phy *phy; +}; + +static const char hcd_name[] = "ohci-platform"; static int ohci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); - struct usb_ohci_pdata *pdata = pdev->dev.platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int err; - if (pdata->big_endian_desc) - ohci->flags |= OHCI_QUIRK_BE_DESC; - if (pdata->big_endian_mmio) - ohci->flags |= OHCI_QUIRK_BE_MMIO; if (pdata->no_big_frame_no) 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; + return ohci_setup(hcd); } -static int ohci_platform_start(struct usb_hcd *hcd) +static int ohci_platform_power_on(struct platform_device *dev) { - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int err; + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); + int clk, ret; - err = ohci_run(ohci); - if (err < 0) { - ohci_err(ohci, "can't start\n"); - ohci_stop(hcd); + for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) { + ret = clk_prepare_enable(priv->clks[clk]); + if (ret) + goto err_disable_clks; } - return err; -} + if (priv->phy) { + ret = phy_init(priv->phy); + if (ret) + goto err_disable_clks; -static const struct hc_driver ohci_platform_hc_driver = { - .description = hcd_name, - .product_desc = "Generic Platform OHCI Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), + ret = phy_power_on(priv->phy); + if (ret) + goto err_exit_phy; + } - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, + return 0; - .reset = ohci_platform_reset, - .start = ohci_platform_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, +err_exit_phy: + phy_exit(priv->phy); +err_disable_clks: + while (--clk >= 0) + clk_disable_unprepare(priv->clks[clk]); - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, + return ret; +} - .get_frame_number = ohci_get_frame, +static void ohci_platform_power_off(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); + int clk; - .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 + if (priv->phy) { + phy_power_off(priv->phy); + phy_exit(priv->phy); + } + + for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--) + if (priv->clks[clk]) + clk_disable_unprepare(priv->clks[clk]); +} + +static struct hc_driver __read_mostly ohci_platform_hc_driver; + +static const struct ohci_driver_overrides platform_overrides __initconst = { + .product_desc = "Generic Platform OHCI controller", + .reset = ohci_platform_reset, + .extra_priv_size = sizeof(struct ohci_platform_priv), +}; - .start_port_reset = ohci_start_port_reset, +static struct usb_ohci_pdata ohci_platform_defaults = { + .power_on = ohci_platform_power_on, + .power_suspend = ohci_platform_power_off, + .power_off = ohci_platform_power_off, }; static int ohci_platform_probe(struct platform_device *dev) { struct usb_hcd *hcd; struct resource *res_mem; - struct usb_ohci_pdata *pdata = dev->dev.platform_data; - int irq; - int err = -ENOMEM; - - if (!pdata) { - WARN_ON(1); - return -ENODEV; - } + struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); + struct ohci_platform_priv *priv; + struct ohci_hcd *ohci; + int err, irq, clk = 0; if (usb_disabled()) return -ENODEV; + /* + * Use reasonable defaults so platforms don't have to provide these + * with DT probing on ARM. + */ + if (!pdata) + pdata = &ohci_platform_defaults; + + err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); + if (err) + return err; + irq = platform_get_irq(dev, 0); if (irq < 0) { dev_err(&dev->dev, "no irq provided"); @@ -112,17 +155,85 @@ static int ohci_platform_probe(struct platform_device *dev) return -ENXIO; } + hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, + dev_name(&dev->dev)); + if (!hcd) + return -ENOMEM; + + platform_set_drvdata(dev, hcd); + dev->dev.platform_data = pdata; + priv = hcd_to_ohci_priv(hcd); + ohci = hcd_to_ohci(hcd); + + if (pdata == &ohci_platform_defaults && dev->dev.of_node) { + if (of_property_read_bool(dev->dev.of_node, "big-endian-regs")) + ohci->flags |= OHCI_QUIRK_BE_MMIO; + + if (of_property_read_bool(dev->dev.of_node, "big-endian-desc")) + ohci->flags |= OHCI_QUIRK_BE_DESC; + + if (of_property_read_bool(dev->dev.of_node, "big-endian")) + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + + priv->phy = devm_phy_get(&dev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); + if (err == -EPROBE_DEFER) + goto err_put_hcd; + priv->phy = NULL; + } + + for (clk = 0; clk < OHCI_MAX_CLKS; clk++) { + priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); + if (IS_ERR(priv->clks[clk])) { + err = PTR_ERR(priv->clks[clk]); + if (err == -EPROBE_DEFER) + goto err_put_clks; + priv->clks[clk] = NULL; + break; + } + } + + } + + priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); + if (IS_ERR(priv->rst)) { + err = PTR_ERR(priv->rst); + if (err == -EPROBE_DEFER) + goto err_put_clks; + priv->rst = NULL; + } else { + err = reset_control_deassert(priv->rst); + if (err) + goto err_put_clks; + } + + if (pdata->big_endian_desc) + ohci->flags |= OHCI_QUIRK_BE_DESC; + if (pdata->big_endian_mmio) + ohci->flags |= OHCI_QUIRK_BE_MMIO; + +#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + if (ohci->flags & OHCI_QUIRK_BE_MMIO) { + dev_err(&dev->dev, + "Error: CONFIG_USB_OHCI_BIG_ENDIAN_MMIO not set\n"); + err = -EINVAL; + goto err_reset; + } +#endif +#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC + if (ohci->flags & OHCI_QUIRK_BE_DESC) { + dev_err(&dev->dev, + "Error: CONFIG_USB_OHCI_BIG_ENDIAN_DESC not set\n"); + err = -EINVAL; + goto err_reset; + } +#endif + if (pdata->power_on) { err = pdata->power_on(dev); if (err < 0) - return err; - } - - hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, - dev_name(&dev->dev)); - if (!hcd) { - err = -ENOMEM; - goto err_power; + goto err_reset; } hcd->rsrc_start = res_mem->start; @@ -131,21 +242,32 @@ static int ohci_platform_probe(struct platform_device *dev) hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); - goto err_put_hcd; + goto err_power; } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_put_hcd; + goto err_power; + + device_wakeup_enable(hcd->self.controller); platform_set_drvdata(dev, hcd); return err; -err_put_hcd: - usb_put_hcd(hcd); err_power: if (pdata->power_off) pdata->power_off(dev); +err_reset: + if (priv->rst) + reset_control_assert(priv->rst); +err_put_clks: + while (--clk >= 0) + clk_put(priv->clks[clk]); +err_put_hcd: + if (pdata == &ohci_platform_defaults) + dev->dev.platform_data = NULL; + + usb_put_hcd(hcd); return err; } @@ -153,15 +275,26 @@ err_power: static int ohci_platform_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); - struct usb_ohci_pdata *pdata = dev->dev.platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); + struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); + int clk; usb_remove_hcd(hcd); - usb_put_hcd(hcd); - platform_set_drvdata(dev, NULL); if (pdata->power_off) pdata->power_off(dev); + if (priv->rst) + reset_control_assert(priv->rst); + + for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) + clk_put(priv->clks[clk]); + + usb_put_hcd(hcd); + + if (pdata == &ohci_platform_defaults) + dev->dev.platform_data = NULL; + return 0; } @@ -169,20 +302,27 @@ static int ohci_platform_remove(struct platform_device *dev) static int ohci_platform_suspend(struct device *dev) { + struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_ohci_pdata *pdata = dev->platform_data; struct platform_device *pdev = container_of(dev, struct platform_device, dev); + bool do_wakeup = device_may_wakeup(dev); + int ret; + + ret = ohci_suspend(hcd, do_wakeup); + if (ret) + return ret; if (pdata->power_suspend) pdata->power_suspend(pdev); - return 0; + return ret; } static int ohci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ohci_pdata *pdata = dev->platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); @@ -201,6 +341,12 @@ static int ohci_platform_resume(struct device *dev) #define ohci_platform_resume NULL #endif /* CONFIG_PM */ +static const struct of_device_id ohci_platform_ids[] = { + { .compatible = "generic-ohci", }, + { } +}; +MODULE_DEVICE_TABLE(of, ohci_platform_ids); + static const struct platform_device_id ohci_platform_table[] = { { "ohci-platform", 0 }, { } @@ -221,5 +367,29 @@ static struct platform_driver ohci_platform_driver = { .owner = THIS_MODULE, .name = "ohci-platform", .pm = &ohci_platform_pm_ops, + .of_match_table = ohci_platform_ids, } }; + +static int __init ohci_platform_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides); + return platform_driver_register(&ohci_platform_driver); +} +module_init(ohci_platform_init); + +static void __exit ohci_platform_cleanup(void) +{ + platform_driver_unregister(&ohci_platform_driver); +} +module_exit(ohci_platform_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_AUTHOR("Alan Stern"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 64c2ed9ff95..965e3e9e688 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -14,6 +14,8 @@ */ #include <linux/signal.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/prom.h> @@ -113,24 +115,18 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op) hcd->rsrc_start = res.start; hcd->rsrc_len = resource_size(&res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; + hcd->regs = devm_ioremap_resource(&op->dev, &res); + if (IS_ERR(hcd->regs)) { + rv = PTR_ERR(hcd->regs); goto err_rmr; } irq = irq_of_parse_and_map(dn, 0); if (irq == NO_IRQ) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); + dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", + __FILE__); rv = -EBUSY; - goto err_irq; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); - rv = -ENOMEM; - goto err_ioremap; + goto err_rmr; } ohci = hcd_to_ohci(hcd); @@ -145,8 +141,10 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op) ohci_hcd_init(ohci); rv = usb_add_hcd(hcd, irq, 0); - if (rv == 0) + if (rv == 0) { + device_wakeup_enable(hcd->self.controller); return 0; + } /* by now, 440epx is known to show usb_23 erratum */ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx"); @@ -172,11 +170,7 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op) pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__); } - iounmap(hcd->regs); -err_ioremap: irq_dispose_mapping(irq); -err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_rmr: usb_put_hcd(hcd); @@ -185,31 +179,19 @@ err_rmr: static int ohci_hcd_ppc_of_remove(struct platform_device *op) { - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - dev_set_drvdata(&op->dev, NULL); + struct usb_hcd *hcd = platform_get_drvdata(op); dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); usb_remove_hcd(hcd); - iounmap(hcd->regs); irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); return 0; } -static void ohci_hcd_ppc_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ohci_hcd_ppc_of_match[] = { #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE { @@ -244,7 +226,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); static struct platform_driver ohci_hcd_ppc_of_driver = { .probe = ohci_hcd_ppc_of_probe, .remove = ohci_hcd_ppc_of_remove, - .shutdown = ohci_hcd_ppc_of_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ppc-of-ohci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 7d35cd9e286..71d8bc4c27f 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -173,6 +173,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) goto fail_add_hcd; } + device_wakeup_enable(hcd->self.controller); return result; fail_add_hcd: diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 279b2ef1741..e68f3d02cd1 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -19,15 +19,28 @@ * This file is licenced under the GPL. */ -#include <linux/device.h> -#include <linux/signal.h> -#include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> -#include <mach/hardware.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/usb-pxa3xx-ulpi.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/signal.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include <mach/hardware.h> + +#include "ohci.h" + +#define DRIVER_DESC "OHCI PXA27x/PXA3x driver" /* * UHC: USB Host Controller (OHCI-like) register definitions @@ -101,16 +114,18 @@ #define PXA_UHC_MAX_PORTNUM 3 -struct pxa27x_ohci { - /* must be 1st member here for hcd_to_ohci() to work */ - struct ohci_hcd ohci; +static const char hcd_name[] = "ohci-pxa27x"; - struct device *dev; +static struct hc_driver __read_mostly ohci_pxa27x_hc_driver; + +struct pxa27x_ohci { struct clk *clk; void __iomem *mmio_base; + struct regulator *vbus[3]; + bool vbus_enabled[3]; }; -#define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)hcd_to_ohci(hcd) +#define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv) /* PMM_NPS_MODE -- PMM Non-power switching mode @@ -122,10 +137,10 @@ struct pxa27x_ohci { PMM_PERPORT_MODE -- PMM per port switching mode Ports are powered individually. */ -static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode) +static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode) { - uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); - uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB); + uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA); + uint32_t uhcrhdb = __raw_readl(pxa_ohci->mmio_base + UHCRHDB); switch (mode) { case PMM_NPS_MODE: @@ -149,20 +164,64 @@ static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode) uhcrhda |= RH_A_NPS; } - __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); - __raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB); + __raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA); + __raw_writel(uhcrhdb, pxa_ohci->mmio_base + UHCRHDB); return 0; } -extern int usb_disabled(void); +static int pxa27x_ohci_set_vbus_power(struct pxa27x_ohci *pxa_ohci, + unsigned int port, bool enable) +{ + struct regulator *vbus = pxa_ohci->vbus[port]; + int ret = 0; + + if (IS_ERR_OR_NULL(vbus)) + return 0; + + if (enable && !pxa_ohci->vbus_enabled[port]) + ret = regulator_enable(vbus); + else if (!enable && pxa_ohci->vbus_enabled[port]) + ret = regulator_disable(vbus); + + if (ret < 0) + return ret; + + pxa_ohci->vbus_enabled[port] = enable; + + return 0; +} +static int pxa27x_ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) +{ + struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + int ret; + + switch (typeReq) { + case SetPortFeature: + case ClearPortFeature: + if (!wIndex || wIndex > 3) + return -EPIPE; + + if (wValue != USB_PORT_FEAT_POWER) + break; + + ret = pxa27x_ohci_set_vbus_power(pxa_ohci, wIndex - 1, + typeReq == SetPortFeature); + if (ret) + return ret; + break; + } + + return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); +} /*-------------------------------------------------------------------------*/ -static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci, +static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci, struct pxaohci_platform_data *inf) { - uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); - uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); + uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); + uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA); if (inf->flags & ENABLE_PORT1) uhchr &= ~UHCHR_SSEP1; @@ -194,17 +253,17 @@ static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci, uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2); } - __raw_writel(uhchr, ohci->mmio_base + UHCHR); - __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); + __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); + __raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA); } -static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci) +static inline void pxa27x_reset_hc(struct pxa27x_ohci *pxa_ohci) { - uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); + uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); - __raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR); + __raw_writel(uhchr | UHCHR_FHR, pxa_ohci->mmio_base + UHCHR); udelay(11); - __raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR); + __raw_writel(uhchr & ~UHCHR_FHR, pxa_ohci->mmio_base + UHCHR); } #ifdef CONFIG_PXA27x @@ -213,25 +272,26 @@ extern void pxa27x_clear_otgph(void); #define pxa27x_clear_otgph() do {} while (0) #endif -static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) +static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) { int retval = 0; struct pxaohci_platform_data *inf; uint32_t uhchr; + struct usb_hcd *hcd = dev_get_drvdata(dev); - inf = dev->platform_data; + inf = dev_get_platdata(dev); - clk_prepare_enable(ohci->clk); + clk_prepare_enable(pxa_ohci->clk); - pxa27x_reset_hc(ohci); + pxa27x_reset_hc(pxa_ohci); - uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR; - __raw_writel(uhchr, ohci->mmio_base + UHCHR); + uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) | UHCHR_FSBIR; + __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); - while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR) + while (__raw_readl(pxa_ohci->mmio_base + UHCHR) & UHCHR_FSBIR) cpu_relax(); - pxa27x_setup_hc(ohci, inf); + pxa27x_setup_hc(pxa_ohci, inf); if (inf->init) retval = inf->init(dev); @@ -240,38 +300,39 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) return retval; if (cpu_is_pxa3xx()) - pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self); + pxa3xx_u2d_start_hc(&hcd->self); - uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE; - __raw_writel(uhchr, ohci->mmio_base + UHCHR); - __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE); + uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) & ~UHCHR_SSE; + __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); + __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, pxa_ohci->mmio_base + UHCHIE); /* Clear any OTG Pin Hold */ pxa27x_clear_otgph(); return 0; } -static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) +static void pxa27x_stop_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) { struct pxaohci_platform_data *inf; + struct usb_hcd *hcd = dev_get_drvdata(dev); uint32_t uhccoms; - inf = dev->platform_data; + inf = dev_get_platdata(dev); if (cpu_is_pxa3xx()) - pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self); + pxa3xx_u2d_stop_hc(&hcd->self); if (inf->exit) inf->exit(dev); - pxa27x_reset_hc(ohci); + pxa27x_reset_hc(pxa_ohci); /* Host Controller Reset */ - uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01; - __raw_writel(uhccoms, ohci->mmio_base + UHCCOMS); + uhccoms = __raw_readl(pxa_ohci->mmio_base + UHCCOMS) | 0x01; + __raw_writel(uhccoms, pxa_ohci->mmio_base + UHCCOMS); udelay(10); - clk_disable_unprepare(ohci->clk); + clk_disable_unprepare(pxa_ohci->clk); } #ifdef CONFIG_OF @@ -287,6 +348,7 @@ static int ohci_pxa_of_init(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct pxaohci_platform_data *pdata; u32 tmp; + int ret; if (!np) return 0; @@ -295,10 +357,9 @@ static int ohci_pxa_of_init(struct platform_device *pdev) * 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -356,15 +417,17 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device int retval, irq; struct usb_hcd *hcd; struct pxaohci_platform_data *inf; - struct pxa27x_ohci *ohci; + struct pxa27x_ohci *pxa_ohci; + struct ohci_hcd *ohci; struct resource *r; struct clk *usb_clk; + unsigned int i; retval = ohci_pxa_of_init(pdev); if (retval) return retval; - inf = pdev->dev.platform_data; + inf = dev_get_platdata(&pdev->dev); if (!inf) return -ENODEV; @@ -375,71 +438,70 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device return -ENXIO; } - usb_clk = clk_get(&pdev->dev, NULL); + usb_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usb_clk)) return PTR_ERR(usb_clk); hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x"); - if (!hcd) { - retval = -ENOMEM; - goto err0; - } + if (!hcd) + return -ENOMEM; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { pr_err("no resource of IORESOURCE_MEM"); retval = -ENXIO; - goto err1; + goto err; } hcd->rsrc_start = r->start; hcd->rsrc_len = resource_size(r); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed"); - retval = -ENOMEM; - goto err2; + hcd->regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); + goto err; } /* initialize "struct pxa27x_ohci" */ - ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd); - ohci->dev = &pdev->dev; - ohci->clk = usb_clk; - ohci->mmio_base = (void __iomem *)hcd->regs; + pxa_ohci = to_pxa27x_ohci(hcd); + pxa_ohci->clk = usb_clk; + pxa_ohci->mmio_base = (void __iomem *)hcd->regs; - if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) { + for (i = 0; i < 3; ++i) { + char name[6]; + + if (!(inf->flags & (ENABLE_PORT1 << i))) + continue; + + sprintf(name, "vbus%u", i + 1); + pxa_ohci->vbus[i] = devm_regulator_get(&pdev->dev, name); + } + + retval = pxa27x_start_hc(pxa_ohci, &pdev->dev); + if (retval < 0) { pr_debug("pxa27x_start_hc failed"); - goto err3; + goto err; } /* Select Power Management Mode */ - pxa27x_ohci_select_pmm(ohci, inf->port_mode); + pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode); if (inf->power_budget) hcd->power_budget = inf->power_budget; - ohci_hcd_init(hcd_to_ohci(hcd)); + /* The value of NDP in roothub_a is incorrect on this hardware */ + ohci = hcd_to_ohci(hcd); + ohci->num_ports = 3; retval = usb_add_hcd(hcd, irq, 0); - if (retval == 0) + if (retval == 0) { + device_wakeup_enable(hcd->self.controller); return retval; + } - pxa27x_stop_hc(ohci, &pdev->dev); - err3: - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: + pxa27x_stop_hc(pxa_ohci, &pdev->dev); + err: usb_put_hcd(hcd); - err0: - clk_put(usb_clk); return retval; } @@ -459,88 +521,20 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device */ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) { - struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); + struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + unsigned int i; usb_remove_hcd(hcd); - pxa27x_stop_hc(ohci, &pdev->dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - clk_put(ohci->clk); -} - -/*-------------------------------------------------------------------------*/ + pxa27x_stop_hc(pxa_ohci, &pdev->dev); -static int -ohci_pxa27x_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); - - /* The value of NDP in roothub_a is incorrect on this hardware */ - ohci->num_ports = 3; - - 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; - } + for (i = 0; i < 3; ++i) + pxa27x_ohci_set_vbus_power(pxa_ohci, i, false); - return 0; + usb_put_hcd(hcd); } /*-------------------------------------------------------------------------*/ -static const struct hc_driver ohci_pxa27x_hc_driver = { - .description = hcd_name, - .product_desc = "PXA27x OHCI", - .hcd_priv_size = sizeof(struct pxa27x_ohci), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_pxa27x_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_pxa27x_drv_probe(struct platform_device *pdev) { pr_debug ("In ohci_hcd_pxa27x_drv_probe"); @@ -556,7 +550,6 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_hcd_pxa27x_remove(hcd, pdev); - platform_set_drvdata(pdev, NULL); return 0; } @@ -564,32 +557,42 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) static int ohci_hcd_pxa27x_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); + struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + bool do_wakeup = device_may_wakeup(dev); + int ret; - if (time_before(jiffies, ohci->ohci.next_statechange)) + + if (time_before(jiffies, ohci->next_statechange)) msleep(5); - ohci->ohci.next_statechange = jiffies; + ohci->next_statechange = jiffies; - pxa27x_stop_hc(ohci, dev); - return 0; + ret = ohci_suspend(hcd, do_wakeup); + if (ret) + return ret; + + pxa27x_stop_hc(pxa_ohci, dev); + return ret; } static int ohci_hcd_pxa27x_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); - struct pxaohci_platform_data *inf = dev->platform_data; + struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + struct pxaohci_platform_data *inf = dev_get_platdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); int status; - if (time_before(jiffies, ohci->ohci.next_statechange)) + if (time_before(jiffies, ohci->next_statechange)) msleep(5); - ohci->ohci.next_statechange = jiffies; + ohci->next_statechange = jiffies; - if ((status = pxa27x_start_hc(ohci, dev)) < 0) + status = pxa27x_start_hc(pxa_ohci, dev); + if (status < 0) return status; /* Select Power Management Mode */ - pxa27x_ohci_select_pmm(ohci, inf->port_mode); + pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode); ohci_resume(hcd, false); return 0; @@ -601,9 +604,6 @@ static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = { }; #endif -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:pxa27x-ohci"); - static struct platform_driver ohci_hcd_pxa27x_driver = { .probe = ohci_hcd_pxa27x_drv_probe, .remove = ohci_hcd_pxa27x_drv_remove, @@ -618,3 +618,30 @@ static struct platform_driver ohci_hcd_pxa27x_driver = { }, }; +static const struct ohci_driver_overrides pxa27x_overrides __initconst = { + .extra_priv_size = sizeof(struct pxa27x_ohci), +}; + +static int __init ohci_pxa27x_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides); + ohci_pxa27x_hc_driver.hub_control = pxa27x_ohci_hub_control; + + return platform_driver_register(&ohci_hcd_pxa27x_driver); +} +module_init(ohci_pxa27x_init); + +static void __exit ohci_pxa27x_cleanup(void) +{ + platform_driver_unregister(&ohci_hcd_pxa27x_driver); +} +module_exit(ohci_pxa27x_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa27x-ohci"); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 88731b7c5f4..d4253e31942 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -41,8 +41,13 @@ finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { + struct device *dev = ohci_to_hcd(ohci)->self.controller; + struct usb_host_endpoint *ep = urb->ep; + struct urb_priv *urb_priv; + // ASSERT (urb->hcpriv != 0); + restart: urb_free_priv (ohci, urb->hcpriv); urb->hcpriv = NULL; if (likely(status == -EINPROGRESS)) @@ -55,7 +60,7 @@ __acquires(ohci->lock) if (quirk_amdiso(ohci)) usb_amd_quirk_pll_enable(); if (quirk_amdprefetch(ohci)) - sb800_prefetch(ohci, 0); + sb800_prefetch(dev, 0); } break; case PIPE_INTERRUPT: @@ -63,10 +68,6 @@ __acquires(ohci->lock) break; } -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "RET", usb_pipeout (urb->pipe), status); -#endif - /* urb->complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); @@ -79,6 +80,21 @@ __acquires(ohci->lock) ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } + + /* + * An isochronous URB that is sumitted too late won't have any TDs + * (marked by the fact that the td_cnt value is larger than the + * actual number of TDs). If the next URB on this endpoint is like + * that, give it back now. + */ + if (!list_empty(&ep->urb_list)) { + urb = list_first_entry(&ep->urb_list, struct urb, urb_list); + urb_priv = urb->hcpriv; + if (urb_priv->td_cnt > urb_priv->length) { + status = 0; + goto restart; + } + } } @@ -127,7 +143,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) { unsigned i; - ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n", + ohci_dbg(ohci, "link %sed %p branch %d [%dus.], interval %d\n", (ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "", ed, ed->branch, ed->load, ed->interval); @@ -274,7 +290,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) } ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval; - ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", + ohci_dbg(ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", (ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "", ed, ed->branch, ed->load, ed->interval); } @@ -545,7 +561,6 @@ td_fill (struct ohci_hcd *ohci, u32 info, td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000); *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci, (data & 0x0FFF) | 0xE000); - td->ed->last_iso = info & 0xffff; } else { td->hwCBP = cpu_to_hc32 (ohci, data); } @@ -580,6 +595,7 @@ static void td_submit_urb ( struct urb *urb ) { struct urb_priv *urb_priv = urb->hcpriv; + struct device *dev = ohci_to_hcd(ohci)->self.controller; dma_addr_t data; int data_len = urb->transfer_buffer_length; int cnt = 0; @@ -689,7 +705,7 @@ static void td_submit_urb ( if (quirk_amdiso(ohci)) usb_amd_quirk_pll_disable(); if (quirk_amdprefetch(ohci)) - sb800_prefetch(ohci, 1); + sb800_prefetch(dev, 1); } periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0 && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0; @@ -745,7 +761,7 @@ static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb->iso_frame_desc [td->index].status = cc_to_error [cc]; if (cc != TD_CC_NOERROR) - ohci_vdbg (ohci, + ohci_dbg(ohci, "urb %p iso td %p (%d) len %d cc %d\n", urb, td, 1 + td->index, dlen, cc); @@ -777,7 +793,7 @@ static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) } if (cc != TD_CC_NOERROR && cc < 0x0E) - ohci_vdbg (ohci, + ohci_dbg(ohci, "urb %p td %p (%d) cc %d, len=%d/%d\n", urb, td, 1 + td->index, cc, urb->actual_length, @@ -994,7 +1010,7 @@ rescan_this: urb_priv->td_cnt++; /* if URB is done, clean up */ - if (urb_priv->td_cnt == urb_priv->length) { + if (urb_priv->td_cnt >= urb_priv->length) { modified = completed = 1; finish_urb(ohci, urb, 0); } @@ -1084,7 +1100,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) + if (urb_priv->td_cnt >= urb_priv->length) finish_urb(ohci, urb, status); /* clean schedule: unlink EDs that are no longer busy */ diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index e125770b893..3d753a9d314 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -19,14 +19,27 @@ * This file is licenced under the GPL. */ -#include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <linux/platform_data/usb-ohci-s3c2410.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" + #define valid_port(idx) ((idx) == 1 || (idx) == 2) /* clock device associated with the hcd */ + +#define DRIVER_DESC "OHCI S3C2410 driver" + +static const char hcd_name[] = "ohci-s3c2410"; + static struct clk *clk; static struct clk *usb_clk; @@ -38,19 +51,19 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) { - return hcd->self.controller->platform_data; + return dev_get_platdata(hcd->self.controller); } static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) { - struct s3c2410_hcd_info *info = dev->dev.platform_data; + struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev); dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); - clk_enable(usb_clk); + clk_prepare_enable(usb_clk); mdelay(2); /* let the bus clock stabilise */ - clk_enable(clk); + clk_prepare_enable(clk); if (info != NULL) { info->hcd = hcd; @@ -63,7 +76,7 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) static void s3c2410_stop_hc(struct platform_device *dev) { - struct s3c2410_hcd_info *info = dev->dev.platform_data; + struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev); dev_dbg(&dev->dev, "s3c2410_stop_hc:\n"); @@ -75,8 +88,8 @@ static void s3c2410_stop_hc(struct platform_device *dev) (info->enable_oc)(info, 0); } - clk_disable(clk); - clk_disable(usb_clk); + clk_disable_unprepare(clk); + clk_disable_unprepare(usb_clk); } /* ohci_s3c2410_hub_status_data @@ -93,7 +106,7 @@ ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf) int orig; int portno; - orig = ohci_hub_status_data(hcd, buf); + orig = ohci_hub_status_data(hcd, buf); if (info == NULL) return orig; @@ -339,10 +352,11 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, struct platform_device *dev) { struct usb_hcd *hcd = NULL; + struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev); int retval; - s3c2410_usb_set_power(dev->dev.platform_data, 1, 1); - s3c2410_usb_set_power(dev->dev.platform_data, 2, 1); + s3c2410_usb_set_power(info, 1, 1); + s3c2410_usb_set_power(info, 2, 1); hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx"); if (hcd == NULL) @@ -373,12 +387,11 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, s3c2410_start_hc(dev, hcd); - ohci_hcd_init(hcd_to_ohci(hcd)); - retval = usb_add_hcd(hcd, dev->resource[1].start, 0); if (retval != 0) goto err_ioremap; + device_wakeup_enable(hcd->self.controller); return 0; err_ioremap: @@ -391,71 +404,7 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, /*-------------------------------------------------------------------------*/ -static int -ohci_s3c2410_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - 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", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - - -static const struct hc_driver ohci_s3c2410_hc_driver = { - .description = hcd_name, - .product_desc = "S3C24XX OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_s3c2410_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_s3c2410_hub_status_data, - .hub_control = ohci_s3c2410_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/* device driver */ +static struct hc_driver __read_mostly ohci_s3c2410_hc_driver; static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev) { @@ -474,28 +423,15 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev) static int ohci_hcd_s3c2410_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct platform_device *pdev = to_platform_device(dev); - unsigned long flags; + bool do_wakeup = device_may_wakeup(dev); 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; - } - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + rc = ohci_suspend(hcd, do_wakeup); + if (rc) + return rc; s3c2410_stop_hc(pdev); -bail: - spin_unlock_irqrestore(&ohci->lock, flags); return rc; } @@ -532,4 +468,36 @@ static struct platform_driver ohci_hcd_s3c2410_driver = { }, }; +static int __init ohci_s3c2410_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ohci_init_driver(&ohci_s3c2410_hc_driver, NULL); + + /* + * The Samsung HW has some unusual quirks, which require + * Sumsung-specific workarounds. We override certain hc_driver + * functions here to achieve that. We explicitly do not enhance + * ohci_driver_overrides to allow this more easily, since this + * is an unusual case, and we don't want to encourage others to + * override these functions by making it too easy. + */ + + ohci_s3c2410_hc_driver.hub_status_data = ohci_s3c2410_hub_status_data; + ohci_s3c2410_hc_driver.hub_control = ohci_s3c2410_hub_control; + + return platform_driver_register(&ohci_hcd_s3c2410_driver); +} +module_init(ohci_s3c2410_init); + +static void __exit ohci_s3c2410_cleanup(void) +{ + platform_driver_unregister(&ohci_hcd_s3c2410_driver); +} +module_exit(ohci_s3c2410_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:s3c2410-ohci"); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 17b2a7dad77..2ac266d692a 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -185,6 +185,12 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) if (usb_disabled()) return -ENODEV; + /* + * We don't call dma_set_mask_and_coherent() here because the + * DMA mask has already been appropraitely setup by the core + * SA-1111 bus code (which includes bug workarounds.) + */ + hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111"); if (!hcd) return -ENOMEM; @@ -205,8 +211,10 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) goto err2; ret = usb_add_hcd(hcd, dev->irq[1], 0); - if (ret == 0) + if (ret == 0) { + device_wakeup_enable(hcd->self.controller); return ret; + } sa1111_stop_hc(dev); err2: diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 3b5b908fd47..4e81c804c73 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -168,6 +168,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) goto err5; + device_wakeup_enable(hcd->self.controller); /* enable power and unmask interrupts */ @@ -207,7 +208,6 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6); sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0); - platform_set_drvdata(pdev, NULL); return 0; } @@ -217,14 +217,21 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg) { struct device *dev = &pdev->dev; - struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + bool do_wakeup = device_may_wakeup(dev); + int ret; if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; + ret = ohci_suspend(hcd, do_wakeup); + if (ret) + return ret; + sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); - return 0; + return ret; } static int ohci_sm501_resume(struct platform_device *pdev) diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 3e19e0170d1..8b29a0c04c2 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -11,92 +11,37 @@ * warranty of any kind, whether express or implied. */ -#include <linux/signal.h> -#include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/signal.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include "ohci.h" + +#define DRIVER_DESC "OHCI SPEAr driver" + +static const char hcd_name[] = "SPEAr-ohci"; struct spear_ohci { - struct ohci_hcd ohci; struct clk *clk; }; -#define to_spear_ohci(hcd) (struct spear_ohci *)hcd_to_ohci(hcd) - -static void spear_start_ohci(struct spear_ohci *ohci) -{ - clk_prepare_enable(ohci->clk); -} - -static void spear_stop_ohci(struct spear_ohci *ohci) -{ - clk_disable_unprepare(ohci->clk); -} - -static int ohci_spear_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - ohci->regs = hcd->regs; - - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "can't start\n"); - ohci_stop(hcd); - return ret; - } - - create_debug_files(ohci); - -#ifdef DEBUG - ohci_dump(ohci, 1); -#endif - return 0; -} - -static const struct hc_driver ohci_spear_hc_driver = { - .description = hcd_name, - .product_desc = "SPEAr OHCI", - .hcd_priv_size = sizeof(struct spear_ohci), - - /* generic hardware linkage */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* basic lifecycle operations */ - .start = ohci_spear_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, +#define to_spear_ohci(hcd) (struct spear_ohci *)(hcd_to_ohci(hcd)->priv) - /* scheduling support */ - .get_frame_number = ohci_get_frame, - - /* root hub support */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, - - .start_port_reset = ohci_start_port_reset, -}; +static struct hc_driver __read_mostly ohci_spear_hc_driver; static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) { const struct hc_driver *driver = &ohci_spear_hc_driver; + struct ohci_hcd *ohci; struct usb_hcd *hcd = NULL; struct clk *usbh_clk; - struct spear_ohci *ohci_p; + struct spear_ohci *sohci_p; struct resource *res; int retval, irq; @@ -111,10 +56,9 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) * 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (retval) + goto fail; usbh_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usbh_clk)) { @@ -137,30 +81,27 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) hcd->rsrc_start = pdev->resource[0].start; hcd->rsrc_len = resource_size(res); - if (!devm_request_mem_region(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len, - hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); - retval = -EBUSY; - goto err_put_hcd; - } - hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_dbg(&pdev->dev, "ioremap failed\n"); - retval = -ENOMEM; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); goto err_put_hcd; } - ohci_p = (struct spear_ohci *)hcd_to_ohci(hcd); - ohci_p->clk = usbh_clk; - spear_start_ohci(ohci_p); - ohci_hcd_init(hcd_to_ohci(hcd)); + sohci_p = to_spear_ohci(hcd); + sohci_p->clk = usbh_clk; + + clk_prepare_enable(sohci_p->clk); + + ohci = hcd_to_ohci(hcd); retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0); - if (retval == 0) + if (retval == 0) { + device_wakeup_enable(hcd->self.controller); return retval; + } - spear_stop_ohci(ohci_p); + clk_disable_unprepare(sohci_p->clk); err_put_hcd: usb_put_hcd(hcd); fail: @@ -172,45 +113,50 @@ fail: static int spear_ohci_hcd_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct spear_ohci *ohci_p = to_spear_ohci(hcd); + struct spear_ohci *sohci_p = to_spear_ohci(hcd); usb_remove_hcd(hcd); - if (ohci_p->clk) - spear_stop_ohci(ohci_p); + if (sohci_p->clk) + clk_disable_unprepare(sohci_p->clk); usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); return 0; } #if defined(CONFIG_PM) -static int spear_ohci_hcd_drv_suspend(struct platform_device *dev, +static int spear_ohci_hcd_drv_suspend(struct platform_device *pdev, pm_message_t message) { - struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct spear_ohci *ohci_p = to_spear_ohci(hcd); + struct spear_ohci *sohci_p = to_spear_ohci(hcd); + bool do_wakeup = device_may_wakeup(&pdev->dev); + int ret; if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; - spear_stop_ohci(ohci_p); - return 0; + ret = ohci_suspend(hcd, do_wakeup); + if (ret) + return ret; + + clk_disable_unprepare(sohci_p->clk); + + return ret; } static int spear_ohci_hcd_drv_resume(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct spear_ohci *ohci_p = to_spear_ohci(hcd); + struct spear_ohci *sohci_p = to_spear_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; - spear_start_ohci(ohci_p); + clk_prepare_enable(sohci_p->clk); ohci_resume(hcd, false); return 0; } @@ -232,8 +178,32 @@ static struct platform_driver spear_ohci_hcd_driver = { .driver = { .owner = THIS_MODULE, .name = "spear-ohci", - .of_match_table = of_match_ptr(spear_ohci_id_table), + .of_match_table = spear_ohci_id_table, }, }; +static const struct ohci_driver_overrides spear_overrides __initconst = { + .extra_priv_size = sizeof(struct spear_ohci), +}; +static int __init ohci_spear_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ohci_init_driver(&ohci_spear_hc_driver, &spear_overrides); + return platform_driver_register(&spear_ohci_hcd_driver); +} +module_init(ohci_spear_init); + +static void __exit ohci_spear_cleanup(void) +{ + platform_driver_unregister(&spear_ohci_hcd_driver); +} +module_exit(ohci_spear_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Deepak Sikri"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spear-ohci"); diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c index ea73009de62..bef6dfb0405 100644 --- a/drivers/usb/host/ohci-tilegx.c +++ b/drivers/usb/host/ohci-tilegx.c @@ -95,7 +95,7 @@ static const struct hc_driver ohci_tilegx_hc_driver = { static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd; - struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); pte_t pte = { 0 }; int my_cpu = smp_processor_id(); int ret; @@ -129,8 +129,8 @@ static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) tilegx_start_ohc(); /* Create our IRQs and register them. */ - pdata->irq = create_irq(); - if (pdata->irq < 0) { + pdata->irq = irq_alloc_hwirq(-1); + if (!pdata->irq) { ret = -ENXIO; goto err_no_irq; } @@ -159,11 +159,12 @@ static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); if (ret == 0) { platform_set_drvdata(pdev, hcd); + device_wakeup_enable(hcd->self.controller); return ret; } err_have_irq: - destroy_irq(pdata->irq); + irq_free_hwirq(pdata->irq); err_no_irq: tilegx_stop_ohc(); usb_put_hcd(hcd); @@ -175,14 +176,13 @@ err_hcd: static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); usb_remove_hcd(hcd); usb_put_hcd(hcd); tilegx_stop_ohc(); gxio_usb_host_destroy(&pdata->usb_ctx); - destroy_irq(pdata->irq); - platform_set_drvdata(pdev, NULL); + irq_free_hwirq(pdata->irq); return 0; } diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index 5e3a6deb62b..bb409588d39 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -27,7 +27,6 @@ /*#include <linux/fs.h> #include <linux/mount.h> #include <linux/pagemap.h> -#include <linux/init.h> #include <linux/namei.h> #include <linux/sched.h>*/ #include <linux/platform_device.h> @@ -250,6 +249,7 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev) if (ret) goto err_add_hcd; + device_wakeup_enable(hcd->self.controller); if (ret == 0) return ret; @@ -287,8 +287,6 @@ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev) iounmap(tmio->ccr); usb_put_hcd(hcd); - platform_set_drvdata(dev, NULL); - return 0; } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index d3299143d9e..05e02a709d4 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -405,6 +405,8 @@ struct ohci_hcd { #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ +#define OHCI_QUIRK_GLOBAL_SUSPEND 0x800 /* must suspend ports */ + // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ @@ -415,12 +417,14 @@ struct ohci_hcd { struct ed *ed_to_check; unsigned zf_delay; -#ifdef DEBUG struct dentry *debug_dir; struct dentry *debug_async; struct dentry *debug_periodic; struct dentry *debug_registers; -#endif + + /* platform-specific data -- must come last */ + unsigned long priv[0] __aligned(sizeof(s64)); + }; #ifdef CONFIG_PCI @@ -471,10 +475,6 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -#ifndef DEBUG -#define STUB_DEBUG_FILES -#endif /* DEBUG */ - #define ohci_dbg(ohci, fmt, args...) \ dev_dbg (ohci_to_hcd(ohci)->self.controller , fmt , ## args ) #define ohci_err(ohci, fmt, args...) \ @@ -484,12 +484,6 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) #define ohci_warn(ohci, fmt, args...) \ dev_warn (ohci_to_hcd(ohci)->self.controller , fmt , ## args ) -#ifdef OHCI_VERBOSE_DEBUG -# define ohci_vdbg ohci_dbg -#else -# define ohci_vdbg(ohci, fmt, args...) do { } while (0) -#endif - /*-------------------------------------------------------------------------*/ /* @@ -718,3 +712,23 @@ static inline u32 roothub_status (struct ohci_hcd *hc) { return ohci_readl (hc, &hc->regs->roothub.status); } static inline u32 roothub_portstatus (struct ohci_hcd *hc, int i) { return read_roothub (hc, portstatus [i], 0xffe0fce0); } + +/* Declarations of things exported for use by ohci platform drivers */ + +struct ohci_driver_overrides { + const char *product_desc; + size_t extra_priv_size; + int (*reset)(struct usb_hcd *hcd); +}; + +extern void ohci_init_driver(struct hc_driver *drv, + const struct ohci_driver_overrides *over); +extern int ohci_restart(struct ohci_hcd *ohci); +extern int ohci_setup(struct usb_hcd *hcd); +#ifdef CONFIG_PM +extern int ohci_suspend(struct usb_hcd *hcd, bool do_wakeup); +extern int ohci_resume(struct usb_hcd *hcd, bool hibernated); +#endif +extern int ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength); +extern int ohci_hub_status_data(struct usb_hcd *hcd, char *buf); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 0f401dbfaf0..e07248b6ab6 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -29,7 +29,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/timer.h> #include <linux/list.h> #include <linux/interrupt.h> @@ -60,6 +59,10 @@ #define oxu_info(oxu, fmt, args...) \ dev_info(oxu_to_hcd(oxu)->self.controller , fmt , ## args) +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif + static inline struct usb_hcd *oxu_to_hcd(struct oxu_hcd *oxu) { return container_of((void *) oxu, struct usb_hcd, hcd_priv); @@ -3747,6 +3750,7 @@ static struct usb_hcd *oxu_create(struct platform_device *pdev, if (ret < 0) return ERR_PTR(ret); + device_wakeup_enable(hcd->self.controller); return hcd; } @@ -3874,7 +3878,6 @@ static int oxu_drv_probe(struct platform_device *pdev) error_init: kfree(info); - platform_set_drvdata(pdev, NULL); error_alloc: iounmap(base); @@ -3907,7 +3910,6 @@ static int oxu_drv_remove(struct platform_device *pdev) release_mem_region(memstart, memlen); kfree(info); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 4c338ec03a0..2f3acebb577 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -12,7 +12,6 @@ #include <linux/kconfig.h> #include <linux/kernel.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/export.h> #include <linux/acpi.h> @@ -79,11 +78,30 @@ #define USB_INTEL_USB3_PSSEN 0xD8 #define USB_INTEL_USB3PRM 0xDC +/* + * amd_chipset_gen values represent AMD different chipset generations + */ +enum amd_chipset_gen { + NOT_AMD_CHIPSET = 0, + AMD_CHIPSET_SB600, + AMD_CHIPSET_SB700, + AMD_CHIPSET_SB800, + AMD_CHIPSET_HUDSON2, + AMD_CHIPSET_BOLTON, + AMD_CHIPSET_YANGTZE, + AMD_CHIPSET_UNKNOWN, +}; + +struct amd_chipset_type { + enum amd_chipset_gen gen; + u8 rev; +}; + static struct amd_chipset_info { struct pci_dev *nb_dev; struct pci_dev *smbus_dev; int nb_type; - int sb_type; + struct amd_chipset_type sb_type; int isoc_reqs; int probe_count; int probe_result; @@ -91,9 +109,66 @@ static struct amd_chipset_info { static DEFINE_SPINLOCK(amd_lock); -int usb_amd_find_chipset_info(void) +/* + * amd_chipset_sb_type_init - initialize amd chipset southbridge type + * + * AMD FCH/SB generation and revision is identified by SMBus controller + * vendor, device and revision IDs. + * + * Returns: 1 if it is an AMD chipset, 0 otherwise. + */ +static int amd_chipset_sb_type_init(struct amd_chipset_info *pinfo) { u8 rev = 0; + pinfo->sb_type.gen = AMD_CHIPSET_UNKNOWN; + + pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); + if (pinfo->smbus_dev) { + rev = pinfo->smbus_dev->revision; + if (rev >= 0x10 && rev <= 0x1f) + pinfo->sb_type.gen = AMD_CHIPSET_SB600; + else if (rev >= 0x30 && rev <= 0x3f) + pinfo->sb_type.gen = AMD_CHIPSET_SB700; + else if (rev >= 0x40 && rev <= 0x4f) + pinfo->sb_type.gen = AMD_CHIPSET_SB800; + } else { + pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); + + if (!pinfo->smbus_dev) { + pinfo->sb_type.gen = NOT_AMD_CHIPSET; + return 0; + } + + rev = pinfo->smbus_dev->revision; + if (rev >= 0x11 && rev <= 0x14) + pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; + else if (rev >= 0x15 && rev <= 0x18) + pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; + else if (rev >= 0x39 && rev <= 0x3a) + pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE; + } + + pinfo->sb_type.rev = rev; + return 1; +} + +void sb800_prefetch(struct device *dev, int on) +{ + u16 misc; + struct pci_dev *pdev = to_pci_dev(dev); + + pci_read_config_word(pdev, 0x50, &misc); + if (on == 0) + pci_write_config_word(pdev, 0x50, misc & 0xfcff); + else + pci_write_config_word(pdev, 0x50, misc | 0x0300); +} +EXPORT_SYMBOL_GPL(sb800_prefetch); + +int usb_amd_find_chipset_info(void) +{ unsigned long flags; struct amd_chipset_info info; int ret; @@ -109,27 +184,17 @@ int usb_amd_find_chipset_info(void) memset(&info, 0, sizeof(info)); spin_unlock_irqrestore(&amd_lock, flags); - info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); - if (info.smbus_dev) { - rev = info.smbus_dev->revision; - if (rev >= 0x40) - info.sb_type = 1; - else if (rev >= 0x30 && rev <= 0x3b) - info.sb_type = 3; - } else { - info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, - 0x780b, NULL); - if (!info.smbus_dev) { - ret = 0; - goto commit; - } - - rev = info.smbus_dev->revision; - if (rev >= 0x11 && rev <= 0x18) - info.sb_type = 2; + if (!amd_chipset_sb_type_init(&info)) { + ret = 0; + goto commit; } - if (info.sb_type == 0) { + /* Below chipset generations needn't enable AMD PLL quirk */ + if (info.sb_type.gen == AMD_CHIPSET_UNKNOWN || + info.sb_type.gen == AMD_CHIPSET_SB600 || + info.sb_type.gen == AMD_CHIPSET_YANGTZE || + (info.sb_type.gen == AMD_CHIPSET_SB700 && + info.sb_type.rev > 0x3b)) { if (info.smbus_dev) { pci_dev_put(info.smbus_dev); info.smbus_dev = NULL; @@ -184,6 +249,39 @@ commit: } EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info); +int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev) +{ + /* Make sure amd chipset type has already been initialized */ + usb_amd_find_chipset_info(); + if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE) + return 0; + + dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n"); + return 1; +} +EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk); + +bool usb_amd_hang_symptom_quirk(void) +{ + u8 rev; + + usb_amd_find_chipset_info(); + rev = amd_chipset.sb_type.rev; + /* SB600 and old version of SB700 have hang symptom bug */ + return amd_chipset.sb_type.gen == AMD_CHIPSET_SB600 || + (amd_chipset.sb_type.gen == AMD_CHIPSET_SB700 && + rev >= 0x3a && rev <= 0x3b); +} +EXPORT_SYMBOL_GPL(usb_amd_hang_symptom_quirk); + +bool usb_amd_prefetch_quirk(void) +{ + usb_amd_find_chipset_info(); + /* SB800 needs pre-fetch fix */ + return amd_chipset.sb_type.gen == AMD_CHIPSET_SB800; +} +EXPORT_SYMBOL_GPL(usb_amd_prefetch_quirk); + /* * The hardware normally enables the A-link power management feature, which * lets the system lower the power consumption in idle states. @@ -216,7 +314,9 @@ static void usb_amd_quirk_pll(int disable) } } - if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) { + if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB800 || + amd_chipset.sb_type.gen == AMD_CHIPSET_HUDSON2 || + amd_chipset.sb_type.gen == AMD_CHIPSET_BOLTON) { outb_p(AB_REG_BAR_LOW, 0xcd6); addr_low = inb_p(0xcd7); outb_p(AB_REG_BAR_HIGH, 0xcd6); @@ -227,7 +327,8 @@ static void usb_amd_quirk_pll(int disable) outl_p(0x40, AB_DATA(addr)); outl_p(0x34, AB_INDX(addr)); val = inl_p(AB_DATA(addr)); - } else if (amd_chipset.sb_type == 3) { + } else if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB700 && + amd_chipset.sb_type.rev <= 0x3b) { pci_read_config_dword(amd_chipset.smbus_dev, AB_REG_BAR_SB700, &addr); outl(AX_INDXC, AB_INDX(addr)); @@ -340,7 +441,7 @@ void usb_amd_dev_put(void) amd_chipset.nb_dev = NULL; amd_chipset.smbus_dev = NULL; amd_chipset.nb_type = 0; - amd_chipset.sb_type = 0; + memset(&amd_chipset.sb_type, 0, sizeof(amd_chipset.sb_type)); amd_chipset.isoc_reqs = 0; amd_chipset.probe_result = 0; @@ -555,6 +656,14 @@ static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), }, }, + { + /* HASEE E200 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "HASEE"), + DMI_MATCH(DMI_BOARD_NAME, "E210"), + DMI_MATCH(DMI_BIOS_VERSION, "6.00"), + }, + }, { } }; @@ -564,9 +673,14 @@ static void ehci_bios_handoff(struct pci_dev *pdev, { int try_handoff = 1, tried_handoff = 0; - /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying - * the handoff on its unused controller. Skip it. */ - if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { + /* + * The Pegatron Lucid tablet sporadically waits for 98 seconds trying + * the handoff on its unused controller. Skip it. + * + * The HASEE E200 hangs when the semaphore is set (bugzilla #77021). + */ + if (pdev->vendor == 0x8086 && (pdev->device == 0x283a || + pdev->device == 0x27cc)) { if (dmi_check_system(ehci_dmi_nohandoff_table)) try_handoff = 0; } @@ -722,32 +836,6 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, return -ETIMEDOUT; } -#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 -#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31 - -bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; -} - -/* The Intel Lynx Point chipset also has switchable ports. */ -bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - (pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI); -} - -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) -{ - return usb_is_intel_ppt_switchable_xhci(pdev) || - usb_is_intel_lpt_switchable_xhci(pdev); -} -EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); - /* * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that * share some number of ports. These ports can be switched between either @@ -766,9 +854,30 @@ EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); * terminations before switching the USB 2.0 wires over, so that USB 3.0 * devices connect at SuperSpeed, rather than at USB 2.0 speeds. */ -void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) +void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) { u32 ports_available; + bool ehci_found = false; + struct pci_dev *companion = NULL; + + /* Sony VAIO t-series with subsystem device ID 90a8 is not capable of + * switching ports from EHCI to xHCI + */ + if (xhci_pdev->subsystem_vendor == PCI_VENDOR_ID_SONY && + xhci_pdev->subsystem_device == 0x90a8) + return; + + /* make sure an intel EHCI controller exists */ + for_each_pci_dev(companion) { + if (companion->class == PCI_CLASS_SERIAL_USB_EHCI && + companion->vendor == PCI_VENDOR_ID_INTEL) { + ehci_found = true; + break; + } + } + + if (!ehci_found) + return; /* Don't switchover the ports if the user hasn't compiled the xHCI * driver. Otherwise they will see "dead" USB ports that don't power @@ -798,7 +907,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) * switchable ports. */ pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, - cpu_to_le32(ports_available)); + ports_available); pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, &ports_available); @@ -820,14 +929,14 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) * host. */ pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, - cpu_to_le32(ports_available)); + ports_available); pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, &ports_available); dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over " "to xHCI: 0x%x\n", ports_available); } -EXPORT_SYMBOL_GPL(usb_enable_xhci_ports); +EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) { @@ -908,8 +1017,8 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev) writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); hc_init: - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); + if (pdev->vendor == PCI_VENDOR_ID_INTEL) + usb_enable_intel_xhci_ports(pdev); op_reg_base = base + XHCI_HC_LENGTH(readl(base)); diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index 7f69a39163c..c622ddf21c9 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -5,17 +5,22 @@ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); int usb_amd_find_chipset_info(void); +int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); +bool usb_amd_hang_symptom_quirk(void); +bool usb_amd_prefetch_quirk(void); void usb_amd_dev_put(void); void usb_amd_quirk_pll_disable(void); void usb_amd_quirk_pll_enable(void); -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev); -void usb_enable_xhci_ports(struct pci_dev *xhci_pdev); +void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); +void sb800_prefetch(struct device *dev, int on); #else +struct pci_dev; static inline void usb_amd_quirk_pll_disable(void) {} static inline void usb_amd_quirk_pll_enable(void) {} static inline void usb_amd_dev_put(void) {} static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} +static inline void sb800_prefetch(struct device *dev, int on) {} #endif /* CONFIG_PCI */ #endif /* __LINUX_USB_PCI_QUIRKS_H */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index a6fd8f5371d..110b4b9ebea 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -27,7 +27,6 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/timer.h> #include <linux/delay.h> #include <linux/list.h> @@ -95,7 +94,7 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597) int i = 0; if (r8a66597->pdata->on_chip) { - clk_enable(r8a66597->clk); + clk_prepare_enable(r8a66597->clk); do { r8a66597_write(r8a66597, SCKE, SYSCFG0); tmp = r8a66597_read(r8a66597, SYSCFG0); @@ -139,7 +138,7 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597) udelay(1); if (r8a66597->pdata->on_chip) { - clk_disable(r8a66597->clk); + clk_disable_unprepare(r8a66597->clk); } else { r8a66597_bclr(r8a66597, PLLC, SYSCFG0); r8a66597_bclr(r8a66597, XCKE, SYSCFG0); @@ -2393,7 +2392,7 @@ static const struct dev_pm_ops r8a66597_dev_pm_ops = { static int r8a66597_remove(struct platform_device *pdev) { - struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev); + struct r8a66597 *r8a66597 = platform_get_drvdata(pdev); struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); del_timer_sync(&r8a66597->rh_timer); @@ -2466,8 +2465,8 @@ static int r8a66597_probe(struct platform_device *pdev) } r8a66597 = hcd_to_r8a66597(hcd); memset(r8a66597, 0, sizeof(struct r8a66597)); - dev_set_drvdata(&pdev->dev, r8a66597); - r8a66597->pdata = pdev->dev.platform_data; + platform_set_drvdata(pdev, r8a66597); + r8a66597->pdata = dev_get_platdata(&pdev->dev); r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; if (r8a66597->pdata->on_chip) { @@ -2514,6 +2513,7 @@ static int r8a66597_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to add hcd\n"); goto clean_up3; } + device_wakeup_enable(hcd->self.controller); return 0; @@ -2534,7 +2534,7 @@ static struct platform_driver r8a66597_driver = { .probe = r8a66597_probe, .remove = r8a66597_remove, .driver = { - .name = (char *) hcd_name, + .name = hcd_name, .owner = THIS_MODULE, .pm = R8A66597_DEV_PM_OPS, }, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index b2ec7fe758d..a517151867a 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -39,7 +39,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/timer.h> #include <linux/list.h> #include <linux/interrupt.h> @@ -48,6 +47,8 @@ #include <linux/usb/hcd.h> #include <linux/platform_device.h> #include <linux/prefetch.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> #include <asm/io.h> #include <asm/irq.h> @@ -63,11 +64,6 @@ MODULE_ALIAS("platform:sl811-hcd"); #define DRIVER_VERSION "19 May 2005" - -#ifndef DEBUG -# define STUB_DEBUG_FILE -#endif - /* for now, use only one transfer register bank */ #undef USE_B @@ -100,7 +96,8 @@ static void port_power(struct sl811 *sl811, int is_on) if (sl811->board && sl811->board->port_power) { /* switch VBUS, at 500mA unless hub power budget gets set */ - DBG("power %s\n", is_on ? "on" : "off"); + dev_dbg(hcd->self.controller, "power %s\n", + is_on ? "on" : "off"); sl811->board->port_power(hcd->self.controller, is_on); } @@ -282,7 +279,7 @@ static inline void sofirq_on(struct sl811 *sl811) { if (sl811->irq_enable & SL11H_INTMASK_SOFINTR) return; - VDBG("sof irq on\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq on\n"); sl811->irq_enable |= SL11H_INTMASK_SOFINTR; } @@ -290,7 +287,7 @@ static inline void sofirq_off(struct sl811 *sl811) { if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR)) return; - VDBG("sof irq off\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq off\n"); sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR; } @@ -338,7 +335,8 @@ static struct sl811h_ep *start(struct sl811 *sl811, u8 bank) } if (unlikely(list_empty(&ep->hep->urb_list))) { - DBG("empty %p queue?\n", ep); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "empty %p queue?\n", ep); return NULL; } @@ -391,7 +389,8 @@ static struct sl811h_ep *start(struct sl811 *sl811, u8 bank) status_packet(sl811, ep, urb, bank, control); break; default: - DBG("bad ep%p pid %02x\n", ep, ep->nextpid); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "bad ep%p pid %02x\n", ep, ep->nextpid); ep = NULL; } return ep; @@ -447,7 +446,8 @@ static void finish_request( } /* periodic deschedule */ - DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { struct sl811h_ep *temp; struct sl811h_ep **prev = &sl811->periodic[i]; @@ -593,7 +593,8 @@ static inline u8 checkdone(struct sl811 *sl811) ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)); if (ctl & SL11H_HCTLMASK_ARM) sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); - DBG("%s DONE_A: ctrl %02x sts %02x\n", + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "%s DONE_A: ctrl %02x sts %02x\n", (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", ctl, sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG))); @@ -604,7 +605,8 @@ static inline u8 checkdone(struct sl811 *sl811) ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)); if (ctl & SL11H_HCTLMASK_ARM) sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); - DBG("%s DONE_B: ctrl %02x sts %02x\n", + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "%s DONE_B: ctrl %02x sts %02x\n", (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", ctl, sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG))); @@ -665,7 +667,7 @@ retry: * this one has nothing scheduled. */ if (sl811->next_periodic) { - // ERR("overrun to slot %d\n", index); + // dev_err(hcd->self.controller, "overrun to slot %d\n", index); sl811->stat_overrun++; } if (sl811->periodic[index]) @@ -723,7 +725,7 @@ retry: } else if (irqstat & SL11H_INTMASK_RD) { if (sl811->port1 & USB_PORT_STAT_SUSPEND) { - DBG("wakeup\n"); + dev_dbg(hcd->self.controller, "wakeup\n"); sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16; sl811->stat_wake++; } else @@ -852,8 +854,9 @@ static int sl811h_urb_enqueue( if (ep->maxpacket > H_MAXPACKET) { /* iso packets up to 240 bytes could work... */ - DBG("dev %d ep%d maxpacket %d\n", - udev->devnum, epnum, ep->maxpacket); + dev_dbg(hcd->self.controller, + "dev %d ep%d maxpacket %d\n", udev->devnum, + epnum, ep->maxpacket); retval = -EINVAL; kfree(ep); goto fail; @@ -917,7 +920,8 @@ static int sl811h_urb_enqueue( * to share the faster parts of the tree without needing * dummy/placeholder nodes */ - DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + dev_dbg(hcd->self.controller, "schedule qh%d/%p branch %d\n", + ep->period, ep, ep->branch); for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { struct sl811h_ep **prev = &sl811->periodic[i]; struct sl811h_ep *here = *prev; @@ -976,7 +980,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } else if (sl811->active_a == ep) { if (time_before_eq(sl811->jiffies_a, jiffies)) { /* happens a lot with lowspeed?? */ - DBG("giveup on DONE_A: ctrl %02x sts %02x\n", + dev_dbg(hcd->self.controller, + "giveup on DONE_A: ctrl %02x sts %02x\n", sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)), sl811_read(sl811, @@ -990,7 +995,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } else if (sl811->active_b == ep) { if (time_before_eq(sl811->jiffies_a, jiffies)) { /* happens a lot with lowspeed?? */ - DBG("giveup on DONE_B: ctrl %02x sts %02x\n", + dev_dbg(hcd->self.controller, + "giveup on DONE_B: ctrl %02x sts %02x\n", sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)), sl811_read(sl811, @@ -1008,7 +1014,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (urb) finish_request(sl811, ep, urb, 0); else - VDBG("dequeue, urb %p active %s; wait4irq\n", urb, + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else retval = -EINVAL; @@ -1029,7 +1036,7 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) if (!list_empty(&hep->urb_list)) msleep(3); if (!list_empty(&hep->urb_list)) - WARNING("ep %p not empty?\n", ep); + dev_warn(hcd->self.controller, "ep %p not empty?\n", ep); kfree(ep); hep->hcpriv = NULL; @@ -1132,7 +1139,7 @@ sl811h_timer(unsigned long _sl811) switch (signaling) { case SL11H_CTL1MASK_SE0: - DBG("end reset\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "end reset\n"); sl811->port1 = (USB_PORT_STAT_C_RESET << 16) | USB_PORT_STAT_POWER; sl811->ctrl1 = 0; @@ -1141,11 +1148,12 @@ sl811h_timer(unsigned long _sl811) irqstat &= ~SL11H_INTMASK_RD; break; case SL11H_CTL1MASK_K: - DBG("end resume\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "end resume\n"); sl811->port1 &= ~USB_PORT_STAT_SUSPEND; break; default: - DBG("odd timer signaling: %02x\n", signaling); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "odd timer signaling: %02x\n", signaling); break; } sl811_write(sl811, SL11H_IRQ_STATUS, irqstat); @@ -1243,7 +1251,7 @@ sl811h_hub_control( break; /* 20 msec of resume/K signaling, other irqs blocked */ - DBG("start resume...\n"); + dev_dbg(hcd->self.controller, "start resume...\n"); sl811->irq_enable = 0; sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); @@ -1281,7 +1289,8 @@ sl811h_hub_control( #ifndef VERBOSE if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ #endif - DBG("GetPortStatus %08x\n", sl811->port1); + dev_dbg(hcd->self.controller, "GetPortStatus %08x\n", + sl811->port1); break; case SetPortFeature: if (wIndex != 1 || wLength != 0) @@ -1293,7 +1302,7 @@ sl811h_hub_control( if (!(sl811->port1 & USB_PORT_STAT_ENABLE)) goto error; - DBG("suspend...\n"); + dev_dbg(hcd->self.controller,"suspend...\n"); sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA; sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); break; @@ -1338,7 +1347,7 @@ static int sl811h_bus_suspend(struct usb_hcd *hcd) { // SOFs off - DBG("%s\n", __func__); + dev_dbg(hcd->self.controller, "%s\n", __func__); return 0; } @@ -1346,7 +1355,7 @@ static int sl811h_bus_resume(struct usb_hcd *hcd) { // SOFs on - DBG("%s\n", __func__); + dev_dbg(hcd->self.controller, "%s\n", __func__); return 0; } @@ -1360,16 +1369,6 @@ sl811h_bus_resume(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILE - -static inline void create_debug_file(struct sl811 *sl811) { } -static inline void remove_debug_file(struct sl811 *sl811) { } - -#else - -#include <linux/proc_fs.h> -#include <linux/seq_file.h> - static void dump_irq(struct seq_file *s, char *label, u8 mask) { seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask, @@ -1381,7 +1380,7 @@ static void dump_irq(struct seq_file *s, char *label, u8 mask) (mask & SL11H_INTMASK_DP) ? " dp" : ""); } -static int proc_sl811h_show(struct seq_file *s, void *unused) +static int sl811h_show(struct seq_file *s, void *unused) { struct sl811 *sl811 = s->private; struct sl811h_ep *ep; @@ -1413,7 +1412,7 @@ static int proc_sl811h_show(struct seq_file *s, void *unused) case SL11H_CTL1MASK_SE0: s = " se0/reset"; break; case SL11H_CTL1MASK_K: s = " k/resume"; break; default: s = "j"; break; - }; s; }), + } s; }), (t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "", (t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : ""); @@ -1446,7 +1445,7 @@ static int proc_sl811h_show(struct seq_file *s, void *unused) case USB_PID_SETUP: s = "setup"; break; case USB_PID_ACK: s = "status"; break; default: s = "?"; break; - }; s;}), + } s;}), ep->maxpacket, ep->nak_count, ep->error_count); list_for_each_entry (urb, &ep->hep->urb_list, urb_list) { @@ -1492,34 +1491,31 @@ static int proc_sl811h_show(struct seq_file *s, void *unused) return 0; } -static int proc_sl811h_open(struct inode *inode, struct file *file) +static int sl811h_open(struct inode *inode, struct file *file) { - return single_open(file, proc_sl811h_show, PDE_DATA(inode)); + return single_open(file, sl811h_show, inode->i_private); } -static const struct file_operations proc_ops = { - .open = proc_sl811h_open, +static const struct file_operations debug_ops = { + .open = sl811h_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; /* expect just one sl811 per system */ -static const char proc_filename[] = "driver/sl811h"; - static void create_debug_file(struct sl811 *sl811) { - sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811); + sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO, + usb_debug_root, sl811, + &debug_ops); } static void remove_debug_file(struct sl811 *sl811) { - if (sl811->pde) - remove_proc_entry(proc_filename, NULL); + debugfs_remove(sl811->debug_file); } -#endif - /*-------------------------------------------------------------------------*/ static void @@ -1648,7 +1644,7 @@ sl811h_probe(struct platform_device *dev) /* refuse to confuse usbcore */ if (dev->dev.dma_mask) { - DBG("no we won't dma\n"); + dev_dbg(&dev->dev, "no we won't dma\n"); return -EINVAL; } @@ -1694,7 +1690,7 @@ sl811h_probe(struct platform_device *dev) spin_lock_init(&sl811->lock); INIT_LIST_HEAD(&sl811->async); - sl811->board = dev->dev.platform_data; + sl811->board = dev_get_platdata(&dev->dev); init_timer(&sl811->timer); sl811->timer.function = sl811h_timer; sl811->timer.data = (unsigned long) sl811; @@ -1716,7 +1712,7 @@ sl811h_probe(struct platform_device *dev) break; default: /* reject case 0, SL11S is less functional */ - DBG("chiprev %02x\n", tmp); + dev_dbg(&dev->dev, "chiprev %02x\n", tmp); retval = -ENXIO; goto err6; } @@ -1735,6 +1731,8 @@ sl811h_probe(struct platform_device *dev) if (retval != 0) goto err6; + device_wakeup_enable(hcd->self.controller); + create_debug_file(sl811); return retval; @@ -1747,7 +1745,7 @@ sl811h_probe(struct platform_device *dev) if (!ioaddr) iounmap(addr_reg); err2: - DBG("init error, %d\n", retval); + dev_dbg(&dev->dev, "init error, %d\n", retval); return retval; } diff --git a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h index b6b8c1f233d..1e23ef49bec 100644 --- a/drivers/usb/host/sl811.h +++ b/drivers/usb/host/sl811.h @@ -122,7 +122,7 @@ struct sl811 { void __iomem *addr_reg; void __iomem *data_reg; struct sl811_platform_data *board; - struct proc_dir_entry *pde; + struct dentry *debug_file; unsigned long stat_insrmv; unsigned long stat_wake; @@ -242,25 +242,8 @@ sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count) /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "sl811: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - -#ifdef VERBOSE -# define VDBG DBG -#else -# define VDBG(stuff...) do{}while(0) -#endif - #ifdef PACKET_TRACE -# define PACKET VDBG +# define PACKET pr_debug("sl811: "stuff) #else # define PACKET(stuff...) do{}while(0) #endif - -#define ERR(stuff...) printk(KERN_ERR "sl811: " stuff) -#define WARNING(stuff...) printk(KERN_WARNING "sl811: " stuff) -#define INFO(stuff...) printk(KERN_INFO "sl811: " stuff) - diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 469564e57a5..88a9bffe93d 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c index 74af2c6287d..0196f766df7 100644 --- a/drivers/usb/host/ssb-hcd.c +++ b/drivers/usb/host/ssb-hcd.c @@ -163,8 +163,7 @@ static int ssb_hcd_probe(struct ssb_device *dev, /* TODO: Probably need checks here; is the core connected? */ - if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || - dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) + if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL); diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5c124bf5d01..c0671750671 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -1809,9 +1809,9 @@ static int u132_hcd_start(struct usb_hcd *hcd) struct platform_device *pdev = to_platform_device(hcd->self.controller); u16 vendor = ((struct u132_platform_data *) - (pdev->dev.platform_data))->vendor; + dev_get_platdata(&pdev->dev))->vendor; u16 device = ((struct u132_platform_data *) - (pdev->dev.platform_data))->device; + dev_get_platdata(&pdev->dev))->device; mutex_lock(&u132->sw_lock); msleep(10); if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { @@ -3034,7 +3034,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) int addrs = MAX_U132_ADDRS; int udevs = MAX_U132_UDEVS; int endps = MAX_U132_ENDPS; - u132->board = pdev->dev.platform_data; + u132->board = dev_get_platdata(&pdev->dev); u132->platform_dev = pdev; u132->power = 0; u132->reset = 0; @@ -3133,6 +3133,7 @@ static int u132_probe(struct platform_device *pdev) u132_u132_put_kref(u132); return retval; } else { + device_wakeup_enable(hcd->self.controller); u132_monitor_queue_work(u132, 100); return 0; } @@ -3217,7 +3218,7 @@ static struct platform_driver u132_platform_driver = { .suspend = u132_suspend, .resume = u132_resume, .driver = { - .name = (char *)hcd_name, + .name = hcd_name, .owner = THIS_MODULE, }, }; diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 45573754652..1b28a000d5c 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -20,7 +20,7 @@ static struct dentry *uhci_debugfs_root; -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG /* Handle REALLY large printks so we don't overflow buffers */ static void lprintk(char *buf) @@ -310,14 +310,14 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) unsigned short portsc1, portsc2; - usbcmd = uhci_readw(uhci, 0); - usbstat = uhci_readw(uhci, 2); - usbint = uhci_readw(uhci, 4); - usbfrnum = uhci_readw(uhci, 6); - flbaseadd = uhci_readl(uhci, 8); - sof = uhci_readb(uhci, 12); - portsc1 = uhci_readw(uhci, 16); - portsc2 = uhci_readw(uhci, 18); + usbcmd = uhci_readw(uhci, USBCMD); + usbstat = uhci_readw(uhci, USBSTS); + usbint = uhci_readw(uhci, USBINTR); + usbfrnum = uhci_readw(uhci, USBFRNUM); + flbaseadd = uhci_readl(uhci, USBFLBASEADD); + sof = uhci_readb(uhci, USBSOF); + portsc1 = uhci_readw(uhci, USBPORTSC1); + portsc2 = uhci_readw(uhci, USBPORTSC2); out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n", usbcmd, @@ -635,7 +635,7 @@ static const struct file_operations uhci_debug_operations = { #endif /* CONFIG_DEBUG_FS */ -#else /* DEBUG */ +#else /* CONFIG_DYNAMIC_DEBUG*/ static inline void lprintk(char *buf) {} diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c index 511bfc46dd7..ab25dc397e8 100644 --- a/drivers/usb/host/uhci-grlib.c +++ b/drivers/usb/host/uhci-grlib.c @@ -141,6 +141,7 @@ static int uhci_hcd_grlib_probe(struct platform_device *op) if (rv) goto err_uhci; + device_wakeup_enable(hcd->self.controller); return 0; err_uhci: @@ -157,9 +158,7 @@ err_rmr: static int uhci_hcd_grlib_remove(struct platform_device *op) { - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - dev_set_drvdata(&op->dev, NULL); + struct usb_hcd *hcd = platform_get_drvdata(op); dev_dbg(&op->dev, "stopping GRLIB GRUSBHC UHCI USB Controller\n"); @@ -183,7 +182,7 @@ static int uhci_hcd_grlib_remove(struct platform_device *op) */ static void uhci_hcd_grlib_shutdown(struct platform_device *op) { - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + struct usb_hcd *hcd = platform_get_drvdata(op); uhci_hc_died(hcd_to_uhci(hcd)); } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 4a86b63745b..27f35e8f161 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -69,18 +69,21 @@ MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications"); * show all queues in /sys/kernel/debug/uhci/[pci_addr] * debug = 3, show all TDs in URBs when dumping */ -#ifdef DEBUG -#define DEBUG_CONFIGURED 1 +#ifdef CONFIG_DYNAMIC_DEBUG + static int debug = 1; module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level"); +static char *errbuf; #else -#define DEBUG_CONFIGURED 0 -#define debug 0 + +#define debug 0 +#define errbuf NULL + #endif -static char *errbuf; + #define ERRBUF_LEN (32 * 1024) static struct kmem_cache *uhci_up_cachep; /* urb_priv */ @@ -516,13 +519,12 @@ static void release_uhci(struct uhci_hcd *uhci) { int i; - if (DEBUG_CONFIGURED) { - spin_lock_irq(&uhci->lock); - uhci->is_initialized = 0; - spin_unlock_irq(&uhci->lock); - debugfs_remove(uhci->dentry); - } + spin_lock_irq(&uhci->lock); + uhci->is_initialized = 0; + spin_unlock_irq(&uhci->lock); + + debugfs_remove(uhci->dentry); for (i = 0; i < UHCI_NUM_SKELQH; i++) uhci_free_qh(uhci, uhci->skelqh[i]); @@ -868,14 +870,14 @@ static int __init uhci_hcd_init(void) ignore_oc ? ", overcurrent ignored" : ""); set_bit(USB_UHCI_LOADED, &usb_hcds_loaded); - if (DEBUG_CONFIGURED) { - errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); - if (!errbuf) - goto errbuf_failed; - uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root); - if (!uhci_debugfs_root) - goto debug_failed; - } +#ifdef CONFIG_DYNAMIC_DEBUG + errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); + if (!errbuf) + goto errbuf_failed; + uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root); + if (!uhci_debugfs_root) + goto debug_failed; +#endif uhci_up_cachep = kmem_cache_create("uhci_urb_priv", sizeof(struct urb_priv), 0, 0, NULL); @@ -906,12 +908,14 @@ clean0: kmem_cache_destroy(uhci_up_cachep); up_failed: +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) debugfs_remove(uhci_debugfs_root); debug_failed: kfree(errbuf); errbuf_failed: +#endif clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded); return retval; @@ -927,7 +931,9 @@ static void __exit uhci_hcd_cleanup(void) #endif kmem_cache_destroy(uhci_up_cachep); debugfs_remove(uhci_debugfs_root); +#ifdef CONFIG_DYNAMIC_DEBUG kfree(errbuf); +#endif clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded); } diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 9189bc984c9..93e17b12fb3 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -75,8 +75,6 @@ static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf) return !!*buf; } -#define OK(x) len = (x); break - #define CLR_RH_PORTSTAT(x) \ status = uhci_readw(uhci, port_addr); \ status &= ~(RWC_BITS|WZ_BITS); \ @@ -244,7 +242,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int status, lstatus, retval = 0, len = 0; + int status, lstatus, retval = 0; unsigned int port = wIndex - 1; unsigned long port_addr = USBPORTSC1 + 2 * port; u16 wPortChange, wPortStatus; @@ -258,7 +256,8 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetHubStatus: *(__le32 *)buf = cpu_to_le32(0); - OK(4); /* hub power */ + retval = 4; /* hub power */ + break; case GetPortStatus: if (port >= uhci->rh_numports) goto err; @@ -311,13 +310,14 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, *(__le16 *)buf = cpu_to_le16(wPortStatus); *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); - OK(4); + retval = 4; + break; case SetHubFeature: /* We don't implement these */ case ClearHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: - OK(0); + break; default: goto err; } @@ -329,7 +329,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case USB_PORT_FEAT_SUSPEND: SET_RH_PORTSTAT(USBPORTSC_SUSP); - OK(0); + break; case USB_PORT_FEAT_RESET: SET_RH_PORTSTAT(USBPORTSC_PR); @@ -338,10 +338,10 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* USB v2.0 7.1.7.5 */ uhci->ports_timeout = jiffies + msecs_to_jiffies(50); - OK(0); + break; case USB_PORT_FEAT_POWER: /* UHCI has no power switching */ - OK(0); + break; default: goto err; } @@ -356,10 +356,10 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* Disable terminates Resume signalling */ uhci_finish_suspend(uhci, port, port_addr); - OK(0); + break; case USB_PORT_FEAT_C_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PEC); - OK(0); + break; case USB_PORT_FEAT_SUSPEND: if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) { @@ -382,32 +382,32 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, uhci->ports_timeout = jiffies + msecs_to_jiffies(20); } - OK(0); + break; case USB_PORT_FEAT_C_SUSPEND: clear_bit(port, &uhci->port_c_suspend); - OK(0); + break; case USB_PORT_FEAT_POWER: /* UHCI has no power switching */ goto err; case USB_PORT_FEAT_C_CONNECTION: CLR_RH_PORTSTAT(USBPORTSC_CSC); - OK(0); + break; case USB_PORT_FEAT_C_OVER_CURRENT: CLR_RH_PORTSTAT(USBPORTSC_OCC); - OK(0); + break; case USB_PORT_FEAT_C_RESET: /* this driver won't report these */ - OK(0); + break; default: goto err; } break; case GetHubDescriptor: - len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); - memcpy(buf, root_hub_hub_des, len); - if (len > 2) + retval = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); + memcpy(buf, root_hub_hub_des, retval); + if (retval > 2) buf[2] = uhci->rh_numports; - OK(len); + break; default: err: retval = -EPIPE; diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index c300bd2f7d1..940304c3322 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -162,6 +162,8 @@ static void uhci_shutdown(struct pci_dev *pdev) #ifdef CONFIG_PM +static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated); + static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -174,12 +176,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) goto done_okay; /* Already suspended or dead */ - if (uhci->rh_state > UHCI_RH_SUSPENDED) { - dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); - rc = -EBUSY; - goto done; - }; - /* All PCI host controllers are required to disable IRQ generation * at the source, so we must turn off PIRQ. */ @@ -195,8 +191,15 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) done_okay: clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); -done: spin_unlock_irq(&uhci->lock); + + synchronize_irq(hcd->irq); + + /* Check for race with a wakeup request */ + if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { + uhci_pci_resume(hcd, false); + rc = -EBUSY; + } return rc; } @@ -276,7 +279,7 @@ static const struct hc_driver uhci_driver = { .hub_control = uhci_hub_control, }; -static DEFINE_PCI_DEVICE_TABLE(uhci_pci_ids) = { { +static const struct pci_device_id uhci_pci_ids[] = { { /* handle any USB UHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0), .driver_data = (unsigned long) &uhci_driver, @@ -293,9 +296,11 @@ static struct pci_driver uhci_pci_driver = { .remove = usb_hcd_pci_remove, .shutdown = uhci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, #endif }; + +MODULE_SOFTDEP("pre: ehci_pci"); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index f1db61ada6a..01833ab2b5c 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -75,10 +75,9 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) * 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 = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, pdev->name); @@ -105,11 +104,11 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) uhci->regs = hcd->regs; - ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED | - IRQF_SHARED); + ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); if (ret) goto err_uhci; + device_wakeup_enable(hcd->self.controller); return 0; err_uhci: @@ -130,7 +129,6 @@ static int uhci_hcd_platform_remove(struct platform_device *pdev) iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); return 0; } @@ -144,12 +142,13 @@ static int uhci_hcd_platform_remove(struct platform_device *pdev) */ static void uhci_hcd_platform_shutdown(struct platform_device *op) { - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + struct usb_hcd *hcd = platform_get_drvdata(op); uhci_hc_died(hcd_to_uhci(hcd)); } static const struct of_device_id platform_uhci_ids[] = { + { .compatible = "generic-uhci", }, { .compatible = "platform-uhci", }, {} }; @@ -161,6 +160,6 @@ static struct platform_driver uhci_platform_driver = { .driver = { .name = "platform-uhci", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(platform_uhci_ids), + .of_match_table = platform_uhci_ids, }, }; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 041c6ddb695..da6f56d996c 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1303,7 +1303,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, } /* Fell behind? */ - if (uhci_frame_before_eq(frame, next)) { + if (!uhci_frame_before_eq(next, frame)) { /* USB_ISO_ASAP: Round up to the first available slot */ if (urb->transfer_flags & URB_ISO_ASAP) @@ -1311,13 +1311,17 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, -qh->period; /* - * Not ASAP: Use the next slot in the stream. If - * the entire URB falls before the threshold, fail. + * Not ASAP: Use the next slot in the stream, + * no matter what. */ else if (!uhci_frame_before_eq(next, frame + (urb->number_of_packets - 1) * qh->period)) - return -EXDEV; + dev_dbg(uhci_dev(uhci), "iso underrun %p (%u+%u < %u)\n", + urb, frame, + (urb->number_of_packets - 1) * + qh->period, + next); } } diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index c3a647816af..d7b363a418d 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -134,7 +134,7 @@ static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, default: ret = asl_urb_enqueue(whc, urb, mem_flags); break; - }; + } return ret; } @@ -160,7 +160,7 @@ static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status) default: ret = asl_urb_dequeue(whc, urb, status); break; - }; + } return ret; } @@ -231,8 +231,6 @@ static struct hc_driver whc_hc_driver = { .hub_status_data = wusbhc_rh_status_data, .hub_control = wusbhc_rh_control, - .bus_suspend = wusbhc_rh_suspend, - .bus_resume = wusbhc_rh_resume, .start_port_reset = wusbhc_rh_start_port_reset, }; @@ -295,6 +293,7 @@ static int whc_probe(struct umc_dev *umc) dev_err(dev, "cannot add HCD: %d\n", ret); goto error_usb_add_hcd; } + device_wakeup_enable(usb_hcd->self.controller); ret = wusbhc_b_create(wusbhc); if (ret) { diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c index 6aae7002810..0c086b2790d 100644 --- a/drivers/usb/host/whci/int.c +++ b/drivers/usb/host/whci/int.c @@ -16,7 +16,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/uwb/umc.h> #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c index f24efdebad1..8d276268286 100644 --- a/drivers/usb/host/whci/wusb.c +++ b/drivers/usb/host/whci/wusb.c @@ -16,7 +16,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/uwb/umc.h> #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 5f3a7c74aa8..eb009a457fb 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -32,7 +32,7 @@ void xhci_dbg_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, "// xHCI capability registers at %p:\n", xhci->cap_regs); - temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); + temp = readl(&xhci->cap_regs->hc_capbase); xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n", &xhci->cap_regs->hc_capbase, temp); xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n", @@ -44,13 +44,13 @@ void xhci_dbg_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs); - temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); + temp = readl(&xhci->cap_regs->run_regs_off); xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n", &xhci->cap_regs->run_regs_off, (unsigned int) temp & RTSOFF_MASK); xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs); - temp = xhci_readl(xhci, &xhci->cap_regs->db_off); + temp = readl(&xhci->cap_regs->db_off); xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp); xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba); } @@ -61,7 +61,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs); - temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); + temp = readl(&xhci->cap_regs->hc_capbase); xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, "CAPLENGTH: 0x%x\n", @@ -69,7 +69,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, "HCIVERSION: 0x%x\n", (unsigned int) HC_VERSION(temp)); - temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); + temp = readl(&xhci->cap_regs->hcs_params1); xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Max device slots: %u\n", @@ -79,7 +79,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, " Max ports: %u\n", (unsigned int) HCS_MAX_PORTS(temp)); - temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); + temp = readl(&xhci->cap_regs->hcs_params2); xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Isoc scheduling threshold: %u\n", @@ -87,7 +87,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n", (unsigned int) HCS_ERST_MAX(temp)); - temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); + temp = readl(&xhci->cap_regs->hcs_params3); xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n", @@ -95,14 +95,14 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n", (unsigned int) HCS_U2_LATENCY(temp)); - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); + temp = readl(&xhci->cap_regs->hcc_params); xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC generates %s bit addresses\n", HCC_64BIT_ADDR(temp) ? "64" : "32"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); - temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); + temp = readl(&xhci->cap_regs->run_regs_off); xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK); } @@ -110,7 +110,7 @@ static void xhci_print_command_reg(struct xhci_hcd *xhci) { u32 temp; - temp = xhci_readl(xhci, &xhci->op_regs->command); + temp = readl(&xhci->op_regs->command); xhci_dbg(xhci, "USBCMD 0x%x:\n", temp); xhci_dbg(xhci, " HC is %s\n", (temp & CMD_RUN) ? "running" : "being stopped"); @@ -128,7 +128,7 @@ static void xhci_print_status(struct xhci_hcd *xhci) { u32 temp; - temp = xhci_readl(xhci, &xhci->op_regs->status); + temp = readl(&xhci->op_regs->status); xhci_dbg(xhci, "USBSTS 0x%x:\n", temp); xhci_dbg(xhci, " Event ring is %sempty\n", (temp & STS_EINT) ? "not " : ""); @@ -163,7 +163,7 @@ static void xhci_print_ports(struct xhci_hcd *xhci) for (j = 0; j < NUM_PORT_REGS; ++j) { xhci_dbg(xhci, "%p port %s reg = 0x%x\n", addr, names[j], - (unsigned int) xhci_readl(xhci, addr)); + (unsigned int) readl(addr)); addr++; } } @@ -177,7 +177,7 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num) u64 temp_64; addr = &ir_set->irq_pending; - temp = xhci_readl(xhci, addr); + temp = readl(addr); if (temp == XHCI_INIT_VALUE) return; @@ -187,17 +187,17 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num) (unsigned int)temp); addr = &ir_set->irq_control; - temp = xhci_readl(xhci, addr); + temp = readl(addr); xhci_dbg(xhci, " %p: ir_set.control = 0x%x\n", addr, (unsigned int)temp); addr = &ir_set->erst_size; - temp = xhci_readl(xhci, addr); + temp = readl(addr); xhci_dbg(xhci, " %p: ir_set.erst_size = 0x%x\n", addr, (unsigned int)temp); addr = &ir_set->rsvd; - temp = xhci_readl(xhci, addr); + temp = readl(addr); if (temp != XHCI_INIT_VALUE) xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n", addr, (unsigned int)temp); @@ -219,12 +219,12 @@ void xhci_print_run_regs(struct xhci_hcd *xhci) int i; xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs); - temp = xhci_readl(xhci, &xhci->run_regs->microframe_index); + temp = readl(&xhci->run_regs->microframe_index); xhci_dbg(xhci, " %p: Microframe index = 0x%x\n", &xhci->run_regs->microframe_index, (unsigned int) temp); for (i = 0; i < 7; ++i) { - temp = xhci_readl(xhci, &xhci->run_regs->rsvd[i]); + temp = readl(&xhci->run_regs->rsvd[i]); if (temp != XHCI_INIT_VALUE) xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n", &xhci->run_regs->rsvd[i], @@ -503,11 +503,14 @@ static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, if (last_ep < 31) last_ep_ctx = last_ep + 1; for (i = 0; i < last_ep_ctx; ++i) { + unsigned int epaddr = xhci_get_endpoint_address(i); struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); dma_addr_t dma = ctx->dma + ((unsigned long)ep_ctx - (unsigned long)ctx->bytes); - xhci_dbg(xhci, "Endpoint %02d Context:\n", i); + xhci_dbg(xhci, "%s Endpoint %02d Context (ep_index %02d):\n", + usb_endpoint_out(epaddr) ? "OUT" : "IN", + epaddr & USB_ENDPOINT_NUMBER_MASK, i); xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", &ep_ctx->ep_info, (unsigned long long)dma, ep_ctx->ep_info); @@ -550,6 +553,11 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, if (ctx->type == XHCI_CTX_TYPE_INPUT) { struct xhci_input_control_ctx *ctrl_ctx = xhci_get_input_control_ctx(xhci, ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "Could not get input context, bad type.\n"); + return; + } + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", &ctrl_ctx->drop_flags, (unsigned long long)dma, ctrl_ctx->drop_flags); @@ -572,3 +580,17 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, xhci_dbg_slot_ctx(xhci, ctx); xhci_dbg_ep_ctx(xhci, ctx, last_ep); } + +void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *), + const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + xhci_dbg(xhci, "%pV\n", &vaf); + trace(&vaf); + va_end(args); +} diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index 377f4242dab..9fe3225e6c6 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -71,6 +71,7 @@ /* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */ #define XHCI_HLC (1 << 19) +#define XHCI_BLC (1 << 20) /* command register values to disable interrupts and halt the HC */ /* start/stop HC execution - do not write unless HC is halted*/ diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 187a3ec1069..aa79e874904 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,10 +20,13 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/gfp.h> + +#include <linux/slab.h> +#include <linux/device.h> #include <asm/unaligned.h> #include "xhci.h" +#include "xhci-trace.h" #define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E) #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ @@ -93,7 +96,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, */ memset(port_removable, 0, sizeof(port_removable)); for (i = 0; i < ports; i++) { - portsc = xhci_readl(xhci, xhci->usb2_ports[i]); + portsc = readl(xhci->usb2_ports[i]); /* If a device is removable, PORTSC reports a 0, same as in the * hub descriptor DeviceRemovable bits. */ @@ -147,7 +150,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, port_removable = 0; /* bit 0 is reserved, bit 1 is for port 1, etc. */ for (i = 0; i < ports; i++) { - portsc = xhci_readl(xhci, xhci->usb3_ports[i]); + portsc = readl(xhci->usb3_ports[i]); if (portsc & PORT_DEV_REMOVE) port_removable |= 1 << (i + 1); } @@ -269,7 +272,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) struct xhci_virt_device *virt_dev; struct xhci_command *cmd; unsigned long flags; - int timeleft; int ret; int i; @@ -283,34 +285,31 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) spin_lock_irqsave(&xhci->lock, flags); for (i = LAST_EP_INDEX; i > 0; i--) { - if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) - xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); + if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) { + struct xhci_command *command; + command = xhci_alloc_command(xhci, false, false, + GFP_NOWAIT); + if (!command) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_free_command(xhci, cmd); + return -ENOMEM; + + } + xhci_queue_stop_endpoint(xhci, command, slot_id, i, + suspend); + } } - cmd->command_trb = xhci->cmd_ring->enqueue; - list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); - xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); + xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend); xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); /* Wait for last stop endpoint command to finish */ - timeleft = wait_for_completion_interruptible_timeout( - cmd->completion, - USB_CTRL_SET_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for stop endpoint command\n", - timeleft == 0 ? "Timeout" : "Signal"); - spin_lock_irqsave(&xhci->lock, flags); - /* The timeout might have raced with the event ring handler, so - * only delete from the list if the item isn't poisoned. - */ - if (cmd->cmd_list.next != LIST_POISON1) - list_del(&cmd->cmd_list); - spin_unlock_irqrestore(&xhci->lock, flags); + wait_for_completion(cmd->completion); + + if (cmd->status == COMP_CMD_ABORT || cmd->status == COMP_CMD_STOP) { + xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n"); ret = -ETIME; - goto command_cleanup; } - -command_cleanup: xhci_free_command(xhci, cmd); return ret; } @@ -341,8 +340,8 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, } /* Write 1 to disable the port */ - xhci_writel(xhci, port_status | PORT_PE, addr); - port_status = xhci_readl(xhci, addr); + writel(port_status | PORT_PE, addr); + port_status = readl(addr); xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n", wIndex, port_status); } @@ -387,8 +386,8 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, return; } /* Change bits are all write 1 to clear */ - xhci_writel(xhci, port_status | status, addr); - port_status = xhci_readl(xhci, addr); + writel(port_status | status, addr); + port_status = readl(addr); xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n", port_change_bit, wIndex, port_status); } @@ -414,11 +413,11 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, { u32 temp; - temp = xhci_readl(xhci, port_array[port_id]); + temp = readl(port_array[port_id]); temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | link_state; - xhci_writel(xhci, temp, port_array[port_id]); + writel(temp, port_array[port_id]); } static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, @@ -426,7 +425,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, { u32 temp; - temp = xhci_readl(xhci, port_array[port_id]); + temp = readl(port_array[port_id]); temp = xhci_port_state_to_neutral(temp); if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT) @@ -444,7 +443,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, else temp &= ~PORT_WKOC_E; - xhci_writel(xhci, temp, port_array[port_id]); + writel(temp, port_array[port_id]); } /* Test and clear port RWC bit */ @@ -453,16 +452,23 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, { u32 temp; - temp = xhci_readl(xhci, port_array[port_id]); + temp = readl(port_array[port_id]); if (temp & port_bit) { temp = xhci_port_state_to_neutral(temp); temp |= port_bit; - xhci_writel(xhci, temp, port_array[port_id]); + writel(temp, port_array[port_id]); } } +/* Updates Link Status for USB 2.1 port */ +static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg) +{ + if ((status_reg & PORT_PLS_MASK) == XDEV_U2) + *status |= USB_PORT_STAT_L1; +} + /* Updates Link Status for super Speed port */ -static void xhci_hub_report_link_state(u32 *status, u32 status_reg) +static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg) { u32 pls = status_reg & PORT_PLS_MASK; @@ -516,7 +522,8 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg) * the compliance mode timer is deleted. A port won't enter * compliance mode if it has previously entered U0. */ -void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) +static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, + u16 wIndex) { u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1); bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); @@ -528,12 +535,152 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) xhci->port_status_u0 |= 1 << wIndex; if (xhci->port_status_u0 == all_ports_seen_u0) { del_timer_sync(&xhci->comp_mode_recovery_timer); - xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n"); - xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "All USB3 ports have entered U0 already!"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Compliance Mode Recovery Timer Deleted."); } } } +/* + * Converts a raw xHCI port status into the format that external USB 2.0 or USB + * 3.0 hubs use. + * + * Possible side effects: + * - Mark a port as being done with device resume, + * and ring the endpoint doorbells. + * - Stop the Synopsys redriver Compliance Mode polling. + * - Drop and reacquire the xHCI lock, in order to wait for port resume. + */ +static u32 xhci_get_port_status(struct usb_hcd *hcd, + struct xhci_bus_state *bus_state, + __le32 __iomem **port_array, + u16 wIndex, u32 raw_port_status, + unsigned long flags) + __releases(&xhci->lock) + __acquires(&xhci->lock) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + u32 status = 0; + int slot_id; + + /* wPortChange bits */ + if (raw_port_status & PORT_CSC) + status |= USB_PORT_STAT_C_CONNECTION << 16; + if (raw_port_status & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + if ((raw_port_status & PORT_OCC)) + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + if ((raw_port_status & PORT_RC)) + status |= USB_PORT_STAT_C_RESET << 16; + /* USB3.0 only */ + if (hcd->speed == HCD_USB3) { + if ((raw_port_status & PORT_PLC)) + status |= USB_PORT_STAT_C_LINK_STATE << 16; + if ((raw_port_status & PORT_WRC)) + status |= USB_PORT_STAT_C_BH_RESET << 16; + } + + if (hcd->speed != HCD_USB3) { + if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3 + && (raw_port_status & PORT_POWER)) + status |= USB_PORT_STAT_SUSPEND; + } + if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME && + !DEV_SUPERSPEED(raw_port_status)) { + if ((raw_port_status & PORT_RESET) || + !(raw_port_status & PORT_PE)) + return 0xffffffff; + if (time_after_eq(jiffies, + bus_state->resume_done[wIndex])) { + int time_left; + + xhci_dbg(xhci, "Resume USB2 port %d\n", + wIndex + 1); + bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); + + set_bit(wIndex, &bus_state->rexit_ports); + xhci_set_link_state(xhci, port_array, wIndex, + XDEV_U0); + + spin_unlock_irqrestore(&xhci->lock, flags); + time_left = wait_for_completion_timeout( + &bus_state->rexit_done[wIndex], + msecs_to_jiffies( + XHCI_MAX_REXIT_TIMEOUT)); + spin_lock_irqsave(&xhci->lock, flags); + + if (time_left) { + slot_id = xhci_find_slot_id_by_port(hcd, + xhci, wIndex + 1); + if (!slot_id) { + xhci_dbg(xhci, "slot_id is zero\n"); + return 0xffffffff; + } + xhci_ring_device(xhci, slot_id); + } else { + int port_status = readl(port_array[wIndex]); + xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", + XHCI_MAX_REXIT_TIMEOUT, + port_status); + status |= USB_PORT_STAT_SUSPEND; + clear_bit(wIndex, &bus_state->rexit_ports); + } + + bus_state->port_c_suspend |= 1 << wIndex; + bus_state->suspended_ports &= ~(1 << wIndex); + } else { + /* + * The resume has been signaling for less than + * 20ms. Report the port status as SUSPEND, + * let the usbcore check port status again + * and clear resume signaling later. + */ + status |= USB_PORT_STAT_SUSPEND; + } + } + if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 + && (raw_port_status & PORT_POWER) + && (bus_state->suspended_ports & (1 << wIndex))) { + bus_state->suspended_ports &= ~(1 << wIndex); + if (hcd->speed != HCD_USB3) + bus_state->port_c_suspend |= 1 << wIndex; + } + if (raw_port_status & PORT_CONNECT) { + status |= USB_PORT_STAT_CONNECTION; + status |= xhci_port_speed(raw_port_status); + } + if (raw_port_status & PORT_PE) + status |= USB_PORT_STAT_ENABLE; + if (raw_port_status & PORT_OC) + status |= USB_PORT_STAT_OVERCURRENT; + if (raw_port_status & PORT_RESET) + status |= USB_PORT_STAT_RESET; + if (raw_port_status & PORT_POWER) { + if (hcd->speed == HCD_USB3) + status |= USB_SS_PORT_STAT_POWER; + else + status |= USB_PORT_STAT_POWER; + } + /* Update Port Link State */ + if (hcd->speed == HCD_USB3) { + xhci_hub_report_usb3_link_state(&status, raw_port_status); + /* + * Verify if all USB3 Ports Have entered U0 already. + * Delete Compliance Mode Timer if so. + */ + xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex); + } else { + xhci_hub_report_usb2_link_state(&status, raw_port_status); + } + if (bus_state->port_c_suspend & (1 << wIndex)) + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + + return status; +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -583,12 +730,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* Set the U1 and U2 exit latencies. */ memcpy(buf, &usb_bos_descriptor, USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); - temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); - buf[12] = HCS_U1_LATENCY(temp); - put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); + if ((xhci->quirks & XHCI_LPM_SUPPORT)) { + temp = readl(&xhci->cap_regs->hcs_params3); + buf[12] = HCS_U1_LATENCY(temp); + put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); + } /* Indicate whether the host has LTM support. */ - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); + temp = readl(&xhci->cap_regs->hcc_params); if (HCC_LTC(temp)) buf[8] |= USB_LTM_SUPPORT; @@ -598,104 +747,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if (!wIndex || wIndex > max_ports) goto error; wIndex--; - status = 0; - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } - xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); - - /* wPortChange bits */ - if (temp & PORT_CSC) - status |= USB_PORT_STAT_C_CONNECTION << 16; - if (temp & PORT_PEC) - status |= USB_PORT_STAT_C_ENABLE << 16; - if ((temp & PORT_OCC)) - status |= USB_PORT_STAT_C_OVERCURRENT << 16; - if ((temp & PORT_RC)) - status |= USB_PORT_STAT_C_RESET << 16; - /* USB3.0 only */ - if (hcd->speed == HCD_USB3) { - if ((temp & PORT_PLC)) - status |= USB_PORT_STAT_C_LINK_STATE << 16; - if ((temp & PORT_WRC)) - status |= USB_PORT_STAT_C_BH_RESET << 16; - } + status = xhci_get_port_status(hcd, bus_state, port_array, + wIndex, temp, flags); + if (status == 0xffffffff) + goto error; - if (hcd->speed != HCD_USB3) { - if ((temp & PORT_PLS_MASK) == XDEV_U3 - && (temp & PORT_POWER)) - status |= USB_PORT_STAT_SUSPEND; - } - if ((temp & PORT_PLS_MASK) == XDEV_RESUME && - !DEV_SUPERSPEED(temp)) { - if ((temp & PORT_RESET) || !(temp & PORT_PE)) - goto error; - if (time_after_eq(jiffies, - bus_state->resume_done[wIndex])) { - xhci_dbg(xhci, "Resume USB2 port %d\n", - wIndex + 1); - bus_state->resume_done[wIndex] = 0; - clear_bit(wIndex, &bus_state->resuming_ports); - xhci_set_link_state(xhci, port_array, wIndex, - XDEV_U0); - xhci_dbg(xhci, "set port %d resume\n", - wIndex + 1); - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (!slot_id) { - xhci_dbg(xhci, "slot_id is zero\n"); - goto error; - } - xhci_ring_device(xhci, slot_id); - bus_state->port_c_suspend |= 1 << wIndex; - bus_state->suspended_ports &= ~(1 << wIndex); - } else { - /* - * The resume has been signaling for less than - * 20ms. Report the port status as SUSPEND, - * let the usbcore check port status again - * and clear resume signaling later. - */ - status |= USB_PORT_STAT_SUSPEND; - } - } - if ((temp & PORT_PLS_MASK) == XDEV_U0 - && (temp & PORT_POWER) - && (bus_state->suspended_ports & (1 << wIndex))) { - bus_state->suspended_ports &= ~(1 << wIndex); - if (hcd->speed != HCD_USB3) - bus_state->port_c_suspend |= 1 << wIndex; - } - if (temp & PORT_CONNECT) { - status |= USB_PORT_STAT_CONNECTION; - status |= xhci_port_speed(temp); - } - if (temp & PORT_PE) - status |= USB_PORT_STAT_ENABLE; - if (temp & PORT_OC) - status |= USB_PORT_STAT_OVERCURRENT; - if (temp & PORT_RESET) - status |= USB_PORT_STAT_RESET; - if (temp & PORT_POWER) { - if (hcd->speed == HCD_USB3) - status |= USB_SS_PORT_STAT_POWER; - else - status |= USB_PORT_STAT_POWER; - } - /* Update Port Link State for super speed ports*/ - if (hcd->speed == HCD_USB3) { - xhci_hub_report_link_state(&status, temp); - /* - * Verify if all USB3 Ports Have entered U0 already. - * Delete Compliance Mode Timer if so. - */ - xhci_del_comp_mod_timer(xhci, temp, wIndex); - } - if (bus_state->port_c_suspend & (1 << wIndex)) - status |= 1 << USB_PORT_FEAT_C_SUSPEND; + xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", + wIndex, temp); xhci_dbg(xhci, "Get port status returned 0x%x\n", status); + put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: @@ -709,7 +774,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if (!wIndex || wIndex > max_ports) goto error; wIndex--; - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; @@ -718,7 +783,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* FIXME: What new port features do we need to support? */ switch (wValue) { case USB_PORT_FEAT_SUSPEND: - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); if ((temp & PORT_PLS_MASK) != XDEV_U0) { /* Resume the port to U0 first */ xhci_set_link_state(xhci, port_array, wIndex, @@ -731,7 +796,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * a port unless the port reports that it is in the * enabled (PED = ‘1’,PLS < ‘3’) state. */ - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) || (temp & PORT_PLS_MASK) >= XDEV_U3) { xhci_warn(xhci, "USB core suspending device " @@ -756,11 +821,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, msleep(10); /* wait device to enter */ spin_lock_irqsave(&xhci->lock, flags); - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); bus_state->suspended_ports |= 1 << wIndex; break; case USB_PORT_FEAT_LINK_STATE: - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); /* Disable port */ if (link_state == USB_SS_PORT_LS_SS_DISABLED) { @@ -773,9 +838,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp |= PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | PORT_RC | PORT_PLC | PORT_CEC; - xhci_writel(xhci, temp | PORT_PE, - port_array[wIndex]); - temp = xhci_readl(xhci, port_array[wIndex]); + writel(temp | PORT_PE, port_array[wIndex]); + temp = readl(port_array[wIndex]); break; } @@ -784,7 +848,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_dbg(xhci, "Enable port %d\n", wIndex); xhci_set_link_state(xhci, port_array, wIndex, link_state); - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); break; } @@ -818,7 +882,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, msleep(20); /* wait device to enter */ spin_lock_irqsave(&xhci->lock, flags); - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); if (link_state == USB_SS_PORT_LS_U3) bus_state->suspended_ports |= 1 << wIndex; break; @@ -829,10 +893,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * However, khubd will ignore the roothub events until * the roothub is registered. */ - xhci_writel(xhci, temp | PORT_POWER, - port_array[wIndex]); + writel(temp | PORT_POWER, port_array[wIndex]); - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); spin_unlock_irqrestore(&xhci->lock, flags); @@ -845,52 +908,52 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); - xhci_writel(xhci, temp, port_array[wIndex]); + writel(temp, port_array[wIndex]); - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_REMOTE_WAKE_MASK: xhci_set_remote_wake_mask(xhci, port_array, wIndex, wake_mask); - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); xhci_dbg(xhci, "set port remote wake mask, " "actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_BH_PORT_RESET: temp |= PORT_WR; - xhci_writel(xhci, temp, port_array[wIndex]); + writel(temp, port_array[wIndex]); - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); break; case USB_PORT_FEAT_U1_TIMEOUT: if (hcd->speed != HCD_USB3) goto error; - temp = xhci_readl(xhci, port_array[wIndex] + 1); + temp = readl(port_array[wIndex] + PORTPMSC); temp &= ~PORT_U1_TIMEOUT_MASK; temp |= PORT_U1_TIMEOUT(timeout); - xhci_writel(xhci, temp, port_array[wIndex] + 1); + writel(temp, port_array[wIndex] + PORTPMSC); break; case USB_PORT_FEAT_U2_TIMEOUT: if (hcd->speed != HCD_USB3) goto error; - temp = xhci_readl(xhci, port_array[wIndex] + 1); + temp = readl(port_array[wIndex] + PORTPMSC); temp &= ~PORT_U2_TIMEOUT_MASK; temp |= PORT_U2_TIMEOUT(timeout); - xhci_writel(xhci, temp, port_array[wIndex] + 1); + writel(temp, port_array[wIndex] + PORTPMSC); break; default: goto error; } /* unblock any posted writes */ - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); break; case ClearPortFeature: if (!wIndex || wIndex > max_ports) goto error; wIndex--; - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; @@ -899,7 +962,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = xhci_port_state_to_neutral(temp); switch (wValue) { case USB_PORT_FEAT_SUSPEND: - temp = xhci_readl(xhci, port_array[wIndex]); + temp = readl(port_array[wIndex]); xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n"); xhci_dbg(xhci, "PORTSC %04x\n", temp); if (temp & PORT_RESET) @@ -942,8 +1005,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, port_array[wIndex], temp); break; case USB_PORT_FEAT_POWER: - xhci_writel(xhci, temp & ~PORT_POWER, - port_array[wIndex]); + writel(temp & ~PORT_POWER, port_array[wIndex]); spin_unlock_irqrestore(&xhci->lock, flags); temp = usb_acpi_power_manageable(hcd->self.root_hub, @@ -1004,7 +1066,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) spin_lock_irqsave(&xhci->lock, flags); /* For each port, did anything change? If so, set that bit in buf. */ for (i = 0; i < max_ports; i++) { - temp = xhci_readl(xhci, port_array[i]); + temp = readl(port_array[i]); if (temp == 0xffffffff) { retval = -ENODEV; break; @@ -1058,7 +1120,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) u32 t1, t2; int slot_id; - t1 = xhci_readl(xhci, port_array[port_index]); + t1 = readl(port_array[port_index]); t2 = xhci_port_state_to_neutral(t1); if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { @@ -1078,7 +1140,9 @@ int xhci_bus_suspend(struct usb_hcd *hcd) * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME * is enabled, so also enable remote wake here. */ - if (hcd->self.root_hub->do_remote_wakeup) { + if (hcd->self.root_hub->do_remote_wakeup + && device_may_wakeup(hcd->self.controller)) { + if (t1 & PORT_CONNECT) { t2 |= PORT_WKOC_E | PORT_WKDISC_E; t2 &= ~PORT_WKCONN_E; @@ -1091,21 +1155,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) t1 = xhci_port_state_to_neutral(t1); if (t1 != t2) - xhci_writel(xhci, t2, port_array[port_index]); - - if (hcd->speed != HCD_USB3) { - /* enable remote wake up for USB 2.0 */ - __le32 __iomem *addr; - u32 tmp; - - /* Add one to the port status register address to get - * the port power control register address. - */ - addr = port_array[port_index] + 1; - tmp = xhci_readl(xhci, addr); - tmp |= PORT_RWE; - xhci_writel(xhci, tmp, addr); - } + writel(t2, port_array[port_index]); } hcd->state = HC_STATE_SUSPENDED; bus_state->next_statechange = jiffies + msecs_to_jiffies(10); @@ -1135,9 +1185,9 @@ int xhci_bus_resume(struct usb_hcd *hcd) } /* delay the irqs */ - temp = xhci_readl(xhci, &xhci->op_regs->command); + temp = readl(&xhci->op_regs->command); temp &= ~CMD_EIE; - xhci_writel(xhci, temp, &xhci->op_regs->command); + writel(temp, &xhci->op_regs->command); port_index = max_ports; while (port_index--) { @@ -1146,7 +1196,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) u32 temp; int slot_id; - temp = xhci_readl(xhci, port_array[port_index]); + temp = readl(port_array[port_index]); if (DEV_SUPERSPEED(temp)) temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); else @@ -1183,31 +1233,17 @@ int xhci_bus_resume(struct usb_hcd *hcd) if (slot_id) xhci_ring_device(xhci, slot_id); } else - xhci_writel(xhci, temp, port_array[port_index]); - - if (hcd->speed != HCD_USB3) { - /* disable remote wake up for USB 2.0 */ - __le32 __iomem *addr; - u32 tmp; - - /* Add one to the port status register address to get - * the port power control register address. - */ - addr = port_array[port_index] + 1; - tmp = xhci_readl(xhci, addr); - tmp &= ~PORT_RWE; - xhci_writel(xhci, tmp, addr); - } + writel(temp, port_array[port_index]); } - (void) xhci_readl(xhci, &xhci->op_regs->command); + (void) readl(&xhci->op_regs->command); bus_state->next_statechange = jiffies + msecs_to_jiffies(5); /* re-enable irqs */ - temp = xhci_readl(xhci, &xhci->op_regs->command); + temp = readl(&xhci->op_regs->command); temp |= CMD_EIE; - xhci_writel(xhci, temp, &xhci->op_regs->command); - temp = xhci_readl(xhci, &xhci->op_regs->command); + writel(temp, &xhci->op_regs->command); + temp = readl(&xhci->op_regs->command); spin_unlock_irqrestore(&xhci->lock, flags); return 0; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fbf75e57628..8056d90690e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -24,8 +24,10 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/dmapool.h> +#include <linux/dma-mapping.h> #include "xhci.h" +#include "xhci-trace.h" /* * Allocates a generic ring segment from the ring pool, sets the dma address, @@ -55,7 +57,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */ if (cycle_state == 0) { for (i = 0; i < TRBS_PER_SEGMENT; i++) - seg->trbs[i].link.control |= TRB_CYCLE; + seg->trbs[i].link.control |= cpu_to_le32(TRB_CYCLE); } seg->dma = dma; seg->next = NULL; @@ -147,14 +149,140 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, } } +/* + * We need a radix tree for mapping physical addresses of TRBs to which stream + * ID they belong to. We need to do this because the host controller won't tell + * us which stream ring the TRB came from. We could store the stream ID in an + * event data TRB, but that doesn't help us for the cancellation case, since the + * endpoint may stop before it reaches that event data TRB. + * + * The radix tree maps the upper portion of the TRB DMA address to a ring + * segment that has the same upper portion of DMA addresses. For example, say I + * have segments of size 1KB, that are always 1KB aligned. A segment may + * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the + * key to the stream ID is 0x43244. I can use the DMA address of the TRB to + * pass the radix tree a key to get the right stream ID: + * + * 0x10c90fff >> 10 = 0x43243 + * 0x10c912c0 >> 10 = 0x43244 + * 0x10c91400 >> 10 = 0x43245 + * + * Obviously, only those TRBs with DMA addresses that are within the segment + * will make the radix tree return the stream ID for that ring. + * + * Caveats for the radix tree: + * + * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an + * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be + * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the + * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit + * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit + * extended systems (where the DMA address can be bigger than 32-bits), + * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that. + */ +static int xhci_insert_segment_mapping(struct radix_tree_root *trb_address_map, + struct xhci_ring *ring, + struct xhci_segment *seg, + gfp_t mem_flags) +{ + unsigned long key; + int ret; + + key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT); + /* Skip any segments that were already added. */ + if (radix_tree_lookup(trb_address_map, key)) + return 0; + + ret = radix_tree_maybe_preload(mem_flags); + if (ret) + return ret; + ret = radix_tree_insert(trb_address_map, + key, ring); + radix_tree_preload_end(); + return ret; +} + +static void xhci_remove_segment_mapping(struct radix_tree_root *trb_address_map, + struct xhci_segment *seg) +{ + unsigned long key; + + key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT); + if (radix_tree_lookup(trb_address_map, key)) + radix_tree_delete(trb_address_map, key); +} + +static int xhci_update_stream_segment_mapping( + struct radix_tree_root *trb_address_map, + struct xhci_ring *ring, + struct xhci_segment *first_seg, + struct xhci_segment *last_seg, + gfp_t mem_flags) +{ + struct xhci_segment *seg; + struct xhci_segment *failed_seg; + int ret; + + if (WARN_ON_ONCE(trb_address_map == NULL)) + return 0; + + seg = first_seg; + do { + ret = xhci_insert_segment_mapping(trb_address_map, + ring, seg, mem_flags); + if (ret) + goto remove_streams; + if (seg == last_seg) + return 0; + seg = seg->next; + } while (seg != first_seg); + + return 0; + +remove_streams: + failed_seg = seg; + seg = first_seg; + do { + xhci_remove_segment_mapping(trb_address_map, seg); + if (seg == failed_seg) + return ret; + seg = seg->next; + } while (seg != first_seg); + + return ret; +} + +static void xhci_remove_stream_mapping(struct xhci_ring *ring) +{ + struct xhci_segment *seg; + + if (WARN_ON_ONCE(ring->trb_address_map == NULL)) + return; + + seg = ring->first_seg; + do { + xhci_remove_segment_mapping(ring->trb_address_map, seg); + seg = seg->next; + } while (seg != ring->first_seg); +} + +static int xhci_update_stream_mapping(struct xhci_ring *ring, gfp_t mem_flags) +{ + return xhci_update_stream_segment_mapping(ring->trb_address_map, ring, + ring->first_seg, ring->last_seg, mem_flags); +} + /* XXX: Do we need the hcd structure in all these functions? */ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) { if (!ring) return; - if (ring->first_seg) + if (ring->first_seg) { + if (ring->type == TYPE_STREAM) + xhci_remove_stream_mapping(ring); xhci_free_segments_for_ring(xhci, ring->first_seg); + } kfree(ring); } @@ -306,7 +434,8 @@ static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, sizeof(union xhci_trb)*TRBS_PER_SEGMENT); if (cycle_state == 0) { for (i = 0; i < TRBS_PER_SEGMENT; i++) - seg->trbs[i].link.control |= TRB_CYCLE; + seg->trbs[i].link.control |= + cpu_to_le32(TRB_CYCLE); } /* All endpoint rings have link TRBs */ xhci_link_segments(xhci, seg, seg->next, type); @@ -346,8 +475,24 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, if (ret) return -ENOMEM; + if (ring->type == TYPE_STREAM) + ret = xhci_update_stream_segment_mapping(ring->trb_address_map, + ring, first, last, flags); + if (ret) { + struct xhci_segment *next; + do { + next = first->next; + xhci_segment_free(xhci, first); + if (first == last) + break; + first = next; + } while (true); + return ret; + } + xhci_link_rings(xhci, ring, first, last, num_segs); - xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion, + "ring expansion succeed, now has %d segments", ring->num_segs); return 0; @@ -358,17 +503,25 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, int type, gfp_t flags) { - struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags); + struct xhci_container_ctx *ctx; + + if ((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)) + return NULL; + + ctx = kzalloc(sizeof(*ctx), flags); if (!ctx) return NULL; - BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)); ctx->type = type; ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024; if (type == XHCI_CTX_TYPE_INPUT) ctx->size += CTX_SIZE(xhci->hcc_params); ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma); + if (!ctx->bytes) { + kfree(ctx); + return NULL; + } memset(ctx->bytes, 0, ctx->size); return ctx; } @@ -385,7 +538,9 @@ static void xhci_free_container_ctx(struct xhci_hcd *xhci, struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) { - BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT); + if (ctx->type != XHCI_CTX_TYPE_INPUT) + return NULL; + return (struct xhci_input_control_ctx *)ctx->bytes; } @@ -419,13 +574,13 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci, unsigned int num_stream_ctxs, struct xhci_stream_ctx *stream_ctx, dma_addr_t dma) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct device *dev = xhci_to_hcd(xhci)->self.controller; + size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; - if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) - dma_free_coherent(&pdev->dev, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs, + if (size > MEDIUM_STREAM_ARRAY_SIZE) + dma_free_coherent(dev, size, stream_ctx, dma); - else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) + else if (size <= SMALL_STREAM_ARRAY_SIZE) return dma_pool_free(xhci->small_streams_pool, stream_ctx, dma); else @@ -447,13 +602,13 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, unsigned int num_stream_ctxs, dma_addr_t *dma, gfp_t mem_flags) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct device *dev = xhci_to_hcd(xhci)->self.controller; + size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; - if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) - return dma_alloc_coherent(&pdev->dev, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs, + if (size > MEDIUM_STREAM_ARRAY_SIZE) + return dma_alloc_coherent(dev, size, dma, mem_flags); - else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) + else if (size <= SMALL_STREAM_ARRAY_SIZE) return dma_pool_alloc(xhci->small_streams_pool, mem_flags, dma); else @@ -471,17 +626,6 @@ struct xhci_ring *xhci_dma_to_transfer_ring( return ep->ring; } -/* Only use this when you know stream_info is valid */ -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -static struct xhci_ring *dma_to_stream_ring( - struct xhci_stream_info *stream_info, - u64 address) -{ - return radix_tree_lookup(&stream_info->trb_address_map, - address >> TRB_SEGMENT_SHIFT); -} -#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ - struct xhci_ring *xhci_stream_id_to_ring( struct xhci_virt_device *dev, unsigned int ep_index, @@ -499,58 +643,6 @@ struct xhci_ring *xhci_stream_id_to_ring( return ep->stream_info->stream_rings[stream_id]; } -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -static int xhci_test_radix_tree(struct xhci_hcd *xhci, - unsigned int num_streams, - struct xhci_stream_info *stream_info) -{ - u32 cur_stream; - struct xhci_ring *cur_ring; - u64 addr; - - for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { - struct xhci_ring *mapped_ring; - int trb_size = sizeof(union xhci_trb); - - cur_ring = stream_info->stream_rings[cur_stream]; - for (addr = cur_ring->first_seg->dma; - addr < cur_ring->first_seg->dma + TRB_SEGMENT_SIZE; - addr += trb_size) { - mapped_ring = dma_to_stream_ring(stream_info, addr); - if (cur_ring != mapped_ring) { - xhci_warn(xhci, "WARN: DMA address 0x%08llx " - "didn't map to stream ID %u; " - "mapped to ring %p\n", - (unsigned long long) addr, - cur_stream, - mapped_ring); - return -EINVAL; - } - } - /* One TRB after the end of the ring segment shouldn't return a - * pointer to the current ring (although it may be a part of a - * different ring). - */ - mapped_ring = dma_to_stream_ring(stream_info, addr); - if (mapped_ring != cur_ring) { - /* One TRB before should also fail */ - addr = cur_ring->first_seg->dma - trb_size; - mapped_ring = dma_to_stream_ring(stream_info, addr); - } - if (mapped_ring == cur_ring) { - xhci_warn(xhci, "WARN: Bad DMA address 0x%08llx " - "mapped to valid stream ID %u; " - "mapped ring = %p\n", - (unsigned long long) addr, - cur_stream, - mapped_ring); - return -EINVAL; - } - } - return 0; -} -#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ - /* * Change an endpoint's internal structure so it supports stream IDs. The * number of requested streams includes stream 0, which cannot be used by device @@ -559,36 +651,6 @@ static int xhci_test_radix_tree(struct xhci_hcd *xhci, * The number of stream contexts in the stream context array may be bigger than * the number of streams the driver wants to use. This is because the number of * stream context array entries must be a power of two. - * - * We need a radix tree for mapping physical addresses of TRBs to which stream - * ID they belong to. We need to do this because the host controller won't tell - * us which stream ring the TRB came from. We could store the stream ID in an - * event data TRB, but that doesn't help us for the cancellation case, since the - * endpoint may stop before it reaches that event data TRB. - * - * The radix tree maps the upper portion of the TRB DMA address to a ring - * segment that has the same upper portion of DMA addresses. For example, say I - * have segments of size 1KB, that are always 64-byte aligned. A segment may - * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the - * key to the stream ID is 0x43244. I can use the DMA address of the TRB to - * pass the radix tree a key to get the right stream ID: - * - * 0x10c90fff >> 10 = 0x43243 - * 0x10c912c0 >> 10 = 0x43244 - * 0x10c91400 >> 10 = 0x43245 - * - * Obviously, only those TRBs with DMA addresses that are within the segment - * will make the radix tree return the stream ID for that ring. - * - * Caveats for the radix tree: - * - * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an - * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be - * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the - * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit - * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit - * extended systems (where the DMA address can be bigger than 32-bits), - * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that. */ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, unsigned int num_stream_ctxs, @@ -597,7 +659,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, struct xhci_stream_info *stream_info; u32 cur_stream; struct xhci_ring *cur_ring; - unsigned long key; u64 addr; int ret; @@ -652,6 +713,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, if (!cur_ring) goto cleanup_rings; cur_ring->stream_id = cur_stream; + cur_ring->trb_address_map = &stream_info->trb_address_map; /* Set deq ptr, cycle bit, and stream context type */ addr = cur_ring->first_seg->dma | SCT_FOR_CTX(SCT_PRI_TR) | @@ -661,10 +723,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, (unsigned long long) addr); - key = (unsigned long) - (cur_ring->first_seg->dma >> TRB_SEGMENT_SHIFT); - ret = radix_tree_insert(&stream_info->trb_address_map, - key, cur_ring); + ret = xhci_update_stream_mapping(cur_ring, mem_flags); if (ret) { xhci_ring_free(xhci, cur_ring); stream_info->stream_rings[cur_stream] = NULL; @@ -677,13 +736,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, * was any other way, the host controller would assume the ring is * "empty" and wait forever for data to be queued to that stream ID). */ -#if XHCI_DEBUG - /* Do a little test on the radix tree to make sure it returns the - * correct values. - */ - if (xhci_test_radix_tree(xhci, num_streams, stream_info)) - goto cleanup_rings; -#endif return stream_info; @@ -691,9 +743,6 @@ cleanup_rings: for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { cur_ring = stream_info->stream_rings[cur_stream]; if (cur_ring) { - addr = cur_ring->first_seg->dma; - radix_tree_delete(&stream_info->trb_address_map, - addr >> TRB_SEGMENT_SHIFT); xhci_ring_free(xhci, cur_ring); stream_info->stream_rings[cur_stream] = NULL; } @@ -721,7 +770,8 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci, * fls(0) = 0, fls(0x1) = 1, fls(0x10) = 2, fls(0x100) = 3, etc. */ max_primary_streams = fls(stream_info->num_stream_ctxs) - 2; - xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Setting number of stream ctx array entries to %u", 1 << (max_primary_streams + 1)); ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK); ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams) @@ -753,7 +803,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci, { int cur_stream; struct xhci_ring *cur_ring; - dma_addr_t addr; if (!stream_info) return; @@ -762,9 +811,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci, cur_stream++) { cur_ring = stream_info->stream_rings[cur_stream]; if (cur_ring) { - addr = cur_ring->first_seg->dma; - radix_tree_delete(&stream_info->trb_address_map, - addr >> TRB_SEGMENT_SHIFT); xhci_ring_free(xhci, cur_ring); stream_info->stream_rings[cur_stream] = NULL; } @@ -777,8 +823,7 @@ void xhci_free_stream_info(struct xhci_hcd *xhci, stream_info->stream_ctx_array, stream_info->ctx_array_dma); - if (stream_info) - kfree(stream_info->stream_rings); + kfree(stream_info->stream_rings); kfree(stream_info); } @@ -975,7 +1020,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, dev->num_rings_cached = 0; init_completion(&dev->cmd_completion); - INIT_LIST_HEAD(&dev->cmd_list); dev->udev = udev; /* Point to output device context in dcbaa. */ @@ -1049,6 +1093,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud struct xhci_ep_ctx *ep0_ctx; struct xhci_slot_ctx *slot_ctx; u32 port_num; + u32 max_packets; struct usb_device *top_dev; dev = xhci->devs[udev->slot_id]; @@ -1066,15 +1111,20 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud switch (udev->speed) { case USB_SPEED_SUPER: slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS); + max_packets = MAX_PACKET(512); break; case USB_SPEED_HIGH: slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS); + max_packets = MAX_PACKET(64); break; + /* USB core guesses at a 64-byte max packet first for FS devices */ case USB_SPEED_FULL: slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS); + max_packets = MAX_PACKET(64); break; case USB_SPEED_LOW: slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_LS); + max_packets = MAX_PACKET(8); break; case USB_SPEED_WIRELESS: xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); @@ -1082,7 +1132,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud break; default: /* Speed was set earlier, this shouldn't happen. */ - BUG(); + return -EINVAL; } /* Find the root hub port this device is under */ port_num = xhci_find_real_port_number(xhci, udev); @@ -1141,31 +1191,10 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud /* Step 4 - ring already allocated */ /* Step 5 */ ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP)); - /* - * XXX: Not sure about wireless USB devices. - */ - switch (udev->speed) { - case USB_SPEED_SUPER: - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512)); - break; - case USB_SPEED_HIGH: - /* USB core guesses at a 64-byte max packet first for FS devices */ - case USB_SPEED_FULL: - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64)); - break; - case USB_SPEED_LOW: - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8)); - break; - case USB_SPEED_WIRELESS: - xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); - return -EINVAL; - break; - default: - /* New speed? */ - BUG(); - } + /* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */ - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3)); + ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3) | + max_packets); ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma | dev->eps[0].ring->cycle_state); @@ -1338,7 +1367,7 @@ static u32 xhci_get_endpoint_type(struct usb_device *udev, else type = EP_TYPE(INT_OUT_EP); } else { - BUG(); + type = 0; } return type; } @@ -1384,10 +1413,16 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, unsigned int max_burst; enum xhci_ring_type type; u32 max_esit_payload; + u32 endpoint_type; ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); + endpoint_type = xhci_get_endpoint_type(udev, ep); + if (!endpoint_type) + return -EINVAL; + ep_ctx->ep_info2 = cpu_to_le32(endpoint_type); + type = usb_endpoint_type(&ep->desc); /* Set up the endpoint ring */ virt_dev->eps[ep_index].new_ring = @@ -1416,11 +1451,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, * CErr shall be set to 0 for Isoch endpoints. */ if (!usb_endpoint_xfer_isoc(&ep->desc)) - ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(3)); + ep_ctx->ep_info2 |= cpu_to_le32(ERROR_COUNT(3)); else - ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(0)); - - ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep)); + ep_ctx->ep_info2 |= cpu_to_le32(ERROR_COUNT(0)); /* Set the max packet size and max burst */ max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)); @@ -1614,7 +1647,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) struct device *dev = xhci_to_hcd(xhci)->self.controller; int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); - xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Allocating %d scratchpad buffers", num_sp); if (!num_sp) return 0; @@ -1682,7 +1716,7 @@ static void scratchpad_free(struct xhci_hcd *xhci) { int num_sp; int i; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct device *dev = xhci_to_hcd(xhci)->self.controller; if (!xhci->scratchpad) return; @@ -1690,13 +1724,13 @@ static void scratchpad_free(struct xhci_hcd *xhci) num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); for (i = 0; i < num_sp; i++) { - dma_free_coherent(&pdev->dev, xhci->page_size, + dma_free_coherent(dev, xhci->page_size, xhci->scratchpad->sp_buffers[i], xhci->scratchpad->sp_dma_buffers[i]); } kfree(xhci->scratchpad->sp_dma_buffers); kfree(xhci->scratchpad->sp_buffers); - dma_free_coherent(&pdev->dev, num_sp * sizeof(u64), + dma_free_coherent(dev, num_sp * sizeof(u64), xhci->scratchpad->sp_array, xhci->scratchpad->sp_dma); kfree(xhci->scratchpad); @@ -1758,36 +1792,40 @@ void xhci_free_command(struct xhci_hcd *xhci, void xhci_mem_cleanup(struct xhci_hcd *xhci) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - struct dev_info *dev_info, *next; - struct xhci_cd *cur_cd, *next_cd; - unsigned long flags; + struct device *dev = xhci_to_hcd(xhci)->self.controller; int size; int i, j, num_ports; + del_timer_sync(&xhci->cmd_timer); + /* Free the Event Ring Segment Table and the actual Event Ring */ size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); if (xhci->erst.entries) - dma_free_coherent(&pdev->dev, size, + dma_free_coherent(dev, size, xhci->erst.entries, xhci->erst.erst_dma_addr); xhci->erst.entries = NULL; - xhci_dbg(xhci, "Freed ERST\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST"); if (xhci->event_ring) xhci_ring_free(xhci, xhci->event_ring); xhci->event_ring = NULL; - xhci_dbg(xhci, "Freed event ring\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring"); if (xhci->lpm_command) xhci_free_command(xhci, xhci->lpm_command); - xhci->cmd_ring_reserved_trbs = 0; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; - xhci_dbg(xhci, "Freed command ring\n"); - list_for_each_entry_safe(cur_cd, next_cd, - &xhci->cancel_cmd_list, cancel_cmd_list) { - list_del(&cur_cd->cancel_cmd_list); - kfree(cur_cd); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring"); + xhci_cleanup_command_queue(xhci); + + num_ports = HCS_MAX_PORTS(xhci->hcs_params1); + for (i = 0; i < num_ports; i++) { + struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; + for (j = 0; j < XHCI_MAX_INTERVAL; j++) { + struct list_head *ep = &bwt->interval_bw[j].endpoints; + while (!list_empty(ep)) + list_del_init(ep->next); + } } for (i = 1; i < MAX_HC_SLOTS; ++i) @@ -1796,50 +1834,35 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) if (xhci->segment_pool) dma_pool_destroy(xhci->segment_pool); xhci->segment_pool = NULL; - xhci_dbg(xhci, "Freed segment pool\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed segment pool"); if (xhci->device_pool) dma_pool_destroy(xhci->device_pool); xhci->device_pool = NULL; - xhci_dbg(xhci, "Freed device context pool\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed device context pool"); if (xhci->small_streams_pool) dma_pool_destroy(xhci->small_streams_pool); xhci->small_streams_pool = NULL; - xhci_dbg(xhci, "Freed small stream array pool\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Freed small stream array pool"); if (xhci->medium_streams_pool) dma_pool_destroy(xhci->medium_streams_pool); xhci->medium_streams_pool = NULL; - xhci_dbg(xhci, "Freed medium stream array pool\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Freed medium stream array pool"); if (xhci->dcbaa) - dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa), + dma_free_coherent(dev, sizeof(*xhci->dcbaa), xhci->dcbaa, xhci->dcbaa->dma); xhci->dcbaa = NULL; scratchpad_free(xhci); - spin_lock_irqsave(&xhci->lock, flags); - list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) { - list_del(&dev_info->list); - kfree(dev_info); - } - spin_unlock_irqrestore(&xhci->lock, flags); - if (!xhci->rh_bw) goto no_bw; - num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - for (i = 0; i < num_ports; i++) { - struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; - for (j = 0; j < XHCI_MAX_INTERVAL; j++) { - struct list_head *ep = &bwt->interval_bw[j].endpoints; - while (!list_empty(ep)) - list_del_init(ep->next); - } - } - for (i = 0; i < num_ports; i++) { struct xhci_tt_bw_info *tt, *n; list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) { @@ -1849,6 +1872,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } no_bw: + xhci->cmd_ring_reserved_trbs = 0; xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; xhci->num_active_eps = 0; @@ -1856,6 +1880,7 @@ no_bw: kfree(xhci->usb3_ports); kfree(xhci->port_array); kfree(xhci->rh_bw); + kfree(xhci->ext_caps); xhci->page_size = 0; xhci->page_shift = 0; @@ -2036,14 +2061,15 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) * there might be more events to service. */ temp &= ~ERST_EHB; - xhci_dbg(xhci, "// Write event ring dequeue pointer, " - "preserving EHB bit\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Write event ring dequeue pointer, " + "preserving EHB bit"); xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &xhci->ir_set->erst_dequeue); } static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, - __le32 __iomem *addr, u8 major_revision) + __le32 __iomem *addr, u8 major_revision, int max_caps) { u32 temp, port_offset, port_count; int i; @@ -2057,29 +2083,37 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, } /* Port offset and count in the third dword, see section 7.2 */ - temp = xhci_readl(xhci, addr + 2); + temp = readl(addr + 2); port_offset = XHCI_EXT_PORT_OFF(temp); port_count = XHCI_EXT_PORT_COUNT(temp); - xhci_dbg(xhci, "Ext Cap %p, port offset = %u, " - "count = %u, revision = 0x%x\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Ext Cap %p, port offset = %u, " + "count = %u, revision = 0x%x", addr, port_offset, port_count, major_revision); /* Port count includes the current port offset */ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ return; + /* cache usb2 port capabilities */ + if (major_revision < 0x03 && xhci->num_ext_caps < max_caps) + xhci->ext_caps[xhci->num_ext_caps++] = temp; + /* Check the host's USB2 LPM capability */ if ((xhci->hci_version == 0x96) && (major_revision != 0x03) && (temp & XHCI_L1C)) { - xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "xHCI 0.96: support USB2 software lpm"); xhci->sw_lpm_support = 1; } if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) { - xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "xHCI 1.0: support USB2 software lpm"); xhci->sw_lpm_support = 1; if (temp & XHCI_HLC) { - xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "xHCI 1.0: support USB2 hardware lpm"); xhci->hw_lpm_support = 1; } } @@ -2125,13 +2159,14 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, */ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) { - __le32 __iomem *addr; - u32 offset; + __le32 __iomem *addr, *tmp_addr; + u32 offset, tmp_offset; unsigned int num_ports; int i, j, port_index; + int cap_count = 0; addr = &xhci->cap_regs->hcc_params; - offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); + offset = XHCI_HCC_EXT_CAPS(readl(addr)); if (offset == 0) { xhci_err(xhci, "No Extended Capability registers, " "unable to set up roothub.\n"); @@ -2161,13 +2196,32 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) * See section 5.3.6 for offset calculation. */ addr = &xhci->cap_regs->hc_capbase + offset; + + tmp_addr = addr; + tmp_offset = offset; + + /* count extended protocol capability entries for later caching */ + do { + u32 cap_id; + cap_id = readl(tmp_addr); + if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) + cap_count++; + tmp_offset = XHCI_EXT_CAPS_NEXT(cap_id); + tmp_addr += tmp_offset; + } while (tmp_offset); + + xhci->ext_caps = kzalloc(sizeof(*xhci->ext_caps) * cap_count, flags); + if (!xhci->ext_caps) + return -ENOMEM; + while (1) { u32 cap_id; - cap_id = xhci_readl(xhci, addr); + cap_id = readl(addr); if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) xhci_add_in_port(xhci, num_ports, addr, - (u8) XHCI_EXT_PORT_MAJOR(cap_id)); + (u8) XHCI_EXT_PORT_MAJOR(cap_id), + cap_count); offset = XHCI_EXT_CAPS_NEXT(cap_id); if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) == num_ports) @@ -2183,18 +2237,21 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) xhci_warn(xhci, "No ports on the roothubs?\n"); return -ENODEV; } - xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Found %u USB 2.0 ports and %u USB 3.0 ports.", xhci->num_usb2_ports, xhci->num_usb3_ports); /* Place limits on the number of roothub ports so that the hub * descriptors aren't longer than the USB core will allocate. */ if (xhci->num_usb3_ports > 15) { - xhci_dbg(xhci, "Limiting USB 3.0 roothub ports to 15.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Limiting USB 3.0 roothub ports to 15."); xhci->num_usb3_ports = 15; } if (xhci->num_usb2_ports > USB_MAXCHILDREN) { - xhci_dbg(xhci, "Limiting USB 2.0 roothub ports to %u.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Limiting USB 2.0 roothub ports to %u.", USB_MAXCHILDREN); xhci->num_usb2_ports = USB_MAXCHILDREN; } @@ -2219,8 +2276,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) xhci->usb2_ports[port_index] = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; - xhci_dbg(xhci, "USB 2.0 port at index %u, " - "addr = %p\n", i, + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "USB 2.0 port at index %u, " + "addr = %p", i, xhci->usb2_ports[port_index]); port_index++; if (port_index == xhci->num_usb2_ports) @@ -2239,8 +2297,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) xhci->usb3_ports[port_index] = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; - xhci_dbg(xhci, "USB 3.0 port at index %u, " - "addr = %p\n", i, + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "USB 3.0 port at index %u, " + "addr = %p", i, xhci->usb3_ports[port_index]); port_index++; if (port_index == xhci->num_usb3_ports) @@ -2260,37 +2319,39 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) u32 page_size, temp; int i; - INIT_LIST_HEAD(&xhci->lpm_failed_devs); - INIT_LIST_HEAD(&xhci->cancel_cmd_list); + INIT_LIST_HEAD(&xhci->cmd_list); - page_size = xhci_readl(xhci, &xhci->op_regs->page_size); - xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size); + page_size = readl(&xhci->op_regs->page_size); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Supported page size register = 0x%x", page_size); for (i = 0; i < 16; i++) { if ((0x1 & page_size) != 0) break; page_size = page_size >> 1; } if (i < 16) - xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Supported page size of %iK", (1 << (i+12)) / 1024); else xhci_warn(xhci, "WARN: no supported page size\n"); /* Use 4K pages, since that's common and the minimum the HC supports */ xhci->page_shift = 12; xhci->page_size = 1 << xhci->page_shift; - xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "HCD page size set to %iK", xhci->page_size / 1024); /* * Program the Number of Device Slots Enabled field in the CONFIG * register with the max value of slots the HC can handle. */ - val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1)); - xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n", - (unsigned int) val); - val2 = xhci_readl(xhci, &xhci->op_regs->config_reg); + val = HCS_MAX_SLOTS(readl(&xhci->cap_regs->hcs_params1)); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// xHC can handle at most %d device slots.", val); + val2 = readl(&xhci->op_regs->config_reg); val |= (val2 & ~HCS_SLOTS_MASK); - xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n", - (unsigned int) val); - xhci_writel(xhci, val, &xhci->op_regs->config_reg); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Setting Max device slots reg = 0x%x.", val); + writel(val, &xhci->op_regs->config_reg); /* * Section 5.4.8 - doorbell array must be @@ -2302,18 +2363,20 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa)); xhci->dcbaa->dma = dma; - xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Device context base array address = 0x%llx (DMA), %p (virt)", (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); /* * Initialize the ring segment pool. The ring must be a contiguous * structure comprised of TRBs. The TRBs must be 16 byte aligned, - * however, the command ring segment needs 64-byte aligned segments, - * so we pick the greater alignment need. + * however, the command ring segment needs 64-byte aligned segments + * and our use of dma addresses in the trb_address_map radix tree needs + * TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need. */ xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, - TRB_SEGMENT_SIZE, 64, xhci->page_size); + TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size); /* See Table 46 and Note on Figure 55 */ xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, @@ -2341,8 +2404,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); if (!xhci->cmd_ring) goto fail; - xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); - xhci_dbg(xhci, "First segment DMA is 0x%llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Allocated command ring at %p", xhci->cmd_ring); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx", (unsigned long long)xhci->cmd_ring->first_seg->dma); /* Set the address in the Command Ring Control register */ @@ -2350,7 +2414,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) | xhci->cmd_ring->cycle_state; - xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Setting command ring address to 0x%x", val); xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); xhci_dbg_cmd_ptrs(xhci); @@ -2364,10 +2429,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) */ xhci->cmd_ring_reserved_trbs++; - val = xhci_readl(xhci, &xhci->cap_regs->db_off); + val = readl(&xhci->cap_regs->db_off); val &= DBOFF_MASK; - xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x" - " from cap regs base addr\n", val); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Doorbell array is located at offset 0x%x" + " from cap regs base addr", val); xhci->dba = (void __iomem *) xhci->cap_regs + val; xhci_dbg_regs(xhci); xhci_print_run_regs(xhci); @@ -2378,7 +2444,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * Event ring setup: Allocate a normal ring, but also setup * the event ring segment table (ERST). Section 4.9.3. */ - xhci_dbg(xhci, "// Allocating event ring\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring"); xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, flags); if (!xhci->event_ring) @@ -2391,13 +2457,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) GFP_KERNEL); if (!xhci->erst.entries) goto fail; - xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Allocated event ring segment table at 0x%llx", (unsigned long long)dma); memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS); xhci->erst.num_entries = ERST_NUM_SEGS; xhci->erst.erst_dma_addr = dma; - xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx", xhci->erst.num_entries, xhci->erst.entries, (unsigned long long)xhci->erst.erst_dma_addr); @@ -2412,16 +2480,19 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) } /* set ERST count with the number of entries in the segment table */ - val = xhci_readl(xhci, &xhci->ir_set->erst_size); + val = readl(&xhci->ir_set->erst_size); val &= ERST_SIZE_MASK; val |= ERST_NUM_SEGS; - xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Write ERST size = %i to ir_set 0 (some bits preserved)", val); - xhci_writel(xhci, val, &xhci->ir_set->erst_size); + writel(val, &xhci->ir_set->erst_size); - xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Set ERST entries to point to event ring."); /* set the segment table base address */ - xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Set ERST base address for ir_set 0 = 0x%llx", (unsigned long long)xhci->erst.erst_dma_addr); val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base); val_64 &= ERST_PTR_MASK; @@ -2430,9 +2501,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) /* Set the event ring dequeue address */ xhci_set_hc_event_deq(xhci); - xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Wrote ERST address to ir_set 0."); xhci_print_ir_set(xhci, 0); + /* init command timeout timer */ + init_timer(&xhci->cmd_timer); + xhci->cmd_timer.data = (unsigned long) xhci; + xhci->cmd_timer.function = xhci_handle_command_timeout; + /* * XXX: Might need to set the Interrupter Moderation Register to * something other than the default (~1ms minimum between interrupts). @@ -2444,6 +2521,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) for (i = 0; i < USB_MAXCHILDREN; ++i) { xhci->bus_state[0].resume_done[i] = 0; xhci->bus_state[1].resume_done[i] = 0; + /* Only the USB 2.0 completions will ever be used. */ + init_completion(&xhci->bus_state[1].rexit_done[i]); } if (scratchpad_alloc(xhci, flags)) @@ -2455,10 +2534,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * is necessary for allowing USB 3.0 devices to do remote wakeup from * U3 (device suspend). */ - temp = xhci_readl(xhci, &xhci->op_regs->dev_notification); + temp = readl(&xhci->op_regs->dev_notification); temp &= ~DEV_NOTE_MASK; temp |= DEV_NOTE_FWAKE; - xhci_writel(xhci, temp, &xhci->op_regs->dev_notification); + writel(temp, &xhci->op_regs->dev_notification); return 0; diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c new file mode 100644 index 00000000000..1eefc988192 --- /dev/null +++ b/drivers/usb/host/xhci-mvebu.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 Marvell + * Author: Gregory CLEMENT <gregory.clement@free-electrons.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/io.h> +#include <linux/mbus.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "xhci-mvebu.h" + +#define USB3_MAX_WINDOWS 4 +#define USB3_WIN_CTRL(w) (0x0 + ((w) * 8)) +#define USB3_WIN_BASE(w) (0x4 + ((w) * 8)) + +static void xhci_mvebu_mbus_config(void __iomem *base, + const struct mbus_dram_target_info *dram) +{ + int win; + + /* Clear all existing windows */ + for (win = 0; win < USB3_MAX_WINDOWS; win++) { + writel(0, base + USB3_WIN_CTRL(win)); + writel(0, base + USB3_WIN_BASE(win)); + } + + /* Program each DRAM CS in a seperate window */ + for (win = 0; win < dram->num_cs; win++) { + const struct mbus_dram_window *cs = dram->cs + win; + + writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + base + USB3_WIN_CTRL(win)); + + writel((cs->base & 0xffff0000), base + USB3_WIN_BASE(win)); + } +} + +int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + const struct mbus_dram_target_info *dram; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -ENODEV; + + /* + * We don't use devm_ioremap() because this mapping should + * only exists for the duration of this probe function. + */ + base = ioremap(res->start, resource_size(res)); + if (!base) + return -ENODEV; + + dram = mv_mbus_dram_info(); + xhci_mvebu_mbus_config(base, dram); + + /* + * This memory area was only needed to configure the MBus + * windows, and is therefore no longer useful. + */ + iounmap(base); + + return 0; +} diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h new file mode 100644 index 00000000000..7ede92aa41f --- /dev/null +++ b/drivers/usb/host/xhci-mvebu.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 Marvell + * + * Gregory Clement <gregory.clement@free-electrons.com> + * + * 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. + */ + +#ifndef __LINUX_XHCI_MVEBU_H +#define __LINUX_XHCI_MVEBU_H +#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) +int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev); +#else +static inline int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) +{ + return 0; +} +#endif +#endif /* __LINUX_XHCI_MVEBU_H */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index cc24e39b97d..e20520f4275 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include "xhci.h" +#include "xhci-trace.h" /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 @@ -34,6 +35,9 @@ #define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_DEVICE_ID_ASROCK_P67 0x7023 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 + static const char hcd_name[] = "xhci_hcd"; /* called after powerup, by probe or system-pm "wakeup" */ @@ -64,16 +68,26 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && pdev->revision == 0x0) { xhci->quirks |= XHCI_RESET_EP_QUIRK; - xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" - " endpoint cmd after reset endpoint\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Fresco Logic xHC needs configure" + " endpoint cmd after reset endpoint"); + } + if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && + pdev->revision == 0x4) { + xhci->quirks |= XHCI_SLOW_SUSPEND; + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Fresco Logic xHC revision %u" + "must be suspended extra slowly", + pdev->revision); } /* Fresco Logic confirms: all revisions of this chip do not * support MSI, even though some of them claim to in their PCI * capabilities. */ xhci->quirks |= XHCI_BROKEN_MSI; - xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " - "has broken MSI implementation\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Fresco Logic revision %u " + "has broken MSI implementation", pdev->revision); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } @@ -93,7 +107,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) } if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { - xhci->quirks |= XHCI_SPURIOUS_SUCCESS; xhci->quirks |= XHCI_EP_LIMIT_QUIRK; xhci->limit_active_eps = 64; xhci->quirks |= XHCI_SW_BW_CHECKING; @@ -108,14 +121,38 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SPURIOUS_REBOOT; xhci->quirks |= XHCI_AVOID_BEI; } + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI)) { + /* Workaround for occasional spurious wakeups from S5 (or + * any other sleep) on Haswell machines with LPT and LPT-LP + * with the new Intel BIOS + */ + /* Limit the quirk to only known vendors, as this triggers + * yet another BIOS bug on some other machines + * https://bugzilla.kernel.org/show_bug.cgi?id=66171 + */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP) + xhci->quirks |= XHCI_SPURIOUS_WAKEUP; + } + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) { + xhci->quirks |= XHCI_SPURIOUS_REBOOT; + } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; - xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + pdev->device == 0x0015) + xhci->quirks |= XHCI_RESET_ON_RESUME; if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; + + if (xhci->quirks & XHCI_RESET_ON_RESUME) + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Resetting on resume"); } /* called during probe() after chip reset completes */ @@ -157,6 +194,10 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) struct usb_hcd *hcd; driver = (struct hc_driver *)id->driver_data; + + /* Prevent runtime suspending between USB-2 and USB-3 initialization */ + pm_runtime_get_noresume(&dev->dev); + /* Register the USB 2.0 roothub. * FIXME: USB core must know to register the USB 2.0 roothub first. * This is sort of silly, because we could just set the HCD driver flags @@ -166,7 +207,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) retval = usb_hcd_pci_probe(dev, id); if (retval) - return retval; + goto put_runtime_pm; /* USB 2.0 roothub is stored in the PCI device now. */ hcd = dev_get_drvdata(&dev->dev); @@ -189,11 +230,11 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto put_usb3_hcd; /* Roothub already marked as USB 3.0 speed */ - /* We know the LPM timeout algorithms for this host, let the USB core - * enable and disable LPM for devices under the USB 3.0 roothub. - */ - if (xhci->quirks & XHCI_LPM_SUPPORT) - hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1; + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + + /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ + pm_runtime_put_noidle(&dev->dev); return 0; @@ -201,6 +242,8 @@ put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); dealloc_usb2_hcd: usb_hcd_pci_remove(dev); +put_runtime_pm: + pm_runtime_put_noidle(&dev->dev); return retval; } @@ -214,6 +257,11 @@ static void xhci_pci_remove(struct pci_dev *dev) usb_put_hcd(xhci->shared_hcd); } usb_hcd_pci_remove(dev); + + /* Workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + pci_set_power_state(dev, PCI_D3hot); + kfree(xhci); } @@ -250,13 +298,15 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) * writers. * * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. + * It should not matter whether the EHCI or xHCI controller is + * resumed first. It's enough to do the switchover in xHCI because + * USB core won't notice anything as the hub driver doesn't start + * running again until after all the devices (including both EHCI and + * xHCI host controllers) have been resumed. */ - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); + + if (pdev->vendor == PCI_VENDOR_ID_INTEL) + usb_enable_intel_xhci_ports(pdev); retval = xhci_resume(xhci, hibernated); return retval; @@ -301,6 +351,7 @@ static const struct hc_driver xhci_pci_hc_driver = { .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, .address_device = xhci_address_device, + .enable_device = xhci_enable_device, .update_hub_device = xhci_update_hub_device, .reset_device = xhci_discover_or_reset_device, @@ -346,7 +397,7 @@ static struct pci_driver xhci_pci_driver = { /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index df90fe51b4a..29d8adb5c8d 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -11,11 +11,15 @@ * version 2 as published by the Free Software Foundation. */ -#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/dma-mapping.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include "xhci.h" +#include "xhci-mvebu.h" static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { @@ -24,7 +28,7 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) * here that the generic code does not try to make a pci_dev from our * dev struct in order to setup MSI */ - xhci->quirks |= XHCI_BROKEN_MSI; + xhci->quirks |= XHCI_PLAT; } /* called during probe() after chip reset completes */ @@ -33,6 +37,11 @@ static int xhci_plat_setup(struct usb_hcd *hcd) return xhci_gen_setup(hcd, xhci_plat_quirks); } +static int xhci_plat_start(struct usb_hcd *hcd) +{ + return xhci_run(hcd); +} + static const struct hc_driver xhci_plat_xhci_driver = { .description = "xhci-hcd", .product_desc = "xHCI Host Controller", @@ -48,7 +57,7 @@ static const struct hc_driver xhci_plat_xhci_driver = { * basic lifecycle operations */ .reset = xhci_plat_setup, - .start = xhci_run, + .start = xhci_plat_start, .stop = xhci_stop, .shutdown = xhci_shutdown, @@ -67,6 +76,7 @@ static const struct hc_driver xhci_plat_xhci_driver = { .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, .address_device = xhci_address_device, + .enable_device = xhci_enable_device, .update_hub_device = xhci_update_hub_device, .reset_device = xhci_discover_or_reset_device, @@ -88,6 +98,7 @@ static int xhci_plat_probe(struct platform_device *pdev) struct xhci_hcd *xhci; struct resource *res; struct usb_hcd *hcd; + struct clk *clk; int ret; int irq; @@ -104,6 +115,24 @@ static int xhci_plat_probe(struct platform_device *pdev) if (!res) return -ENODEV; + if (of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-375-xhci") || + of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-380-xhci")) { + ret = xhci_mvebu_mbus_init_quirk(pdev); + if (ret) + return ret; + } + + /* Initialize dma_mask and coherent_dma_mask to 32-bits */ + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + else + dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) return -ENOMEM; @@ -125,13 +154,27 @@ static int xhci_plat_probe(struct platform_device *pdev) goto release_mem_region; } + /* + * Not all platforms have a clk so it is not an error if the + * clock does not exists. + */ + clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(clk)) { + ret = clk_prepare_enable(clk); + if (ret) + goto unmap_registers; + } + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) - goto unmap_registers; + goto disable_clk; + + device_wakeup_enable(hcd->self.controller); /* USB 2.0 roothub is stored in the platform_device now. */ - hcd = dev_get_drvdata(&pdev->dev); + hcd = platform_get_drvdata(pdev); xhci = hcd_to_xhci(hcd); + xhci->clk = clk; xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, dev_name(&pdev->dev), hcd); if (!xhci->shared_hcd) { @@ -145,6 +188,9 @@ static int xhci_plat_probe(struct platform_device *pdev) */ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (ret) goto put_usb3_hcd; @@ -157,6 +203,10 @@ put_usb3_hcd: dealloc_usb2_hcd: usb_remove_hcd(hcd); +disable_clk: + if (!IS_ERR(clk)) + clk_disable_unprepare(clk); + unmap_registers: iounmap(hcd->regs); @@ -173,23 +223,65 @@ static int xhci_plat_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct clk *clk = xhci->clk; usb_remove_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd); usb_remove_hcd(hcd); + if (!IS_ERR(clk)) + clk_disable_unprepare(clk); iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); kfree(xhci); return 0; } +#ifdef CONFIG_PM_SLEEP +static int xhci_plat_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return xhci_suspend(xhci); +} + +static int xhci_plat_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return xhci_resume(xhci, 0); +} + +static const struct dev_pm_ops xhci_plat_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume) +}; +#define DEV_PM_OPS (&xhci_plat_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + +#ifdef CONFIG_OF +static const struct of_device_id usb_xhci_of_match[] = { + { .compatible = "generic-xhci" }, + { .compatible = "xhci-platform" }, + { .compatible = "marvell,armada-375-xhci"}, + { .compatible = "marvell,armada-380-xhci"}, + { }, +}; +MODULE_DEVICE_TABLE(of, usb_xhci_of_match); +#endif + static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, .remove = xhci_plat_remove, .driver = { .name = "xhci-hcd", + .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(usb_xhci_of_match), }, }; MODULE_ALIAS("platform:xhci-hcd"); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 1969c001b3f..749fc68eb5c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -67,10 +67,7 @@ #include <linux/scatterlist.h> #include <linux/slab.h> #include "xhci.h" - -static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - struct xhci_event_cmd *event); +#include "xhci-trace.h" /* * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA @@ -145,8 +142,6 @@ static void next_trb(struct xhci_hcd *xhci, */ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) { - unsigned long long addr; - ring->deq_updates++; /* @@ -167,7 +162,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci, ring, ring->deq_seg, ring->dequeue)) { - ring->cycle_state = (ring->cycle_state ? 0 : 1); + ring->cycle_state ^= 1; } ring->deq_seg = ring->deq_seg->next; ring->dequeue = ring->deq_seg->trbs; @@ -175,8 +170,6 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) ring->dequeue++; } } while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)); - - addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); } /* @@ -201,7 +194,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, { u32 chain; union xhci_trb *next; - unsigned long long addr; chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; /* If this is not event ring, there is one less usable TRB */ @@ -253,7 +245,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, ring->enqueue = ring->enq_seg->trbs; next = ring->enqueue; } - addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue); } /* @@ -284,9 +275,9 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci) return; xhci_dbg(xhci, "// Ding dong!\n"); - xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]); + writel(DB_VALUE_HOST, &xhci->dba->doorbell[0]); /* Flush PCI posted writes */ - xhci_readl(xhci, &xhci->dba->doorbell[0]); + readl(&xhci->dba->doorbell[0]); } static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) @@ -296,17 +287,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) xhci_dbg(xhci, "Abort command ring\n"); - if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) { - xhci_dbg(xhci, "The command ring isn't running, " - "Have the command ring been stopped?\n"); - return 0; - } - temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - if (!(temp_64 & CMD_RING_RUNNING)) { - xhci_dbg(xhci, "Command ring had been stopped\n"); - return 0; - } xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring); @@ -332,71 +313,6 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) return 0; } -static int xhci_queue_cd(struct xhci_hcd *xhci, - struct xhci_command *command, - union xhci_trb *cmd_trb) -{ - struct xhci_cd *cd; - cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC); - if (!cd) - return -ENOMEM; - INIT_LIST_HEAD(&cd->cancel_cmd_list); - - cd->command = command; - cd->cmd_trb = cmd_trb; - list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list); - - return 0; -} - -/* - * Cancel the command which has issue. - * - * Some commands may hang due to waiting for acknowledgement from - * usb device. It is outside of the xHC's ability to control and - * will cause the command ring is blocked. When it occurs software - * should intervene to recover the command ring. - * See Section 4.6.1.1 and 4.6.1.2 - */ -int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, - union xhci_trb *cmd_trb) -{ - int retval = 0; - unsigned long flags; - - spin_lock_irqsave(&xhci->lock, flags); - - if (xhci->xhc_state & XHCI_STATE_DYING) { - xhci_warn(xhci, "Abort the command ring," - " but the xHCI is dead.\n"); - retval = -ESHUTDOWN; - goto fail; - } - - /* queue the cmd desriptor to cancel_cmd_list */ - retval = xhci_queue_cd(xhci, command, cmd_trb); - if (retval) { - xhci_warn(xhci, "Queuing command descriptor failed.\n"); - goto fail; - } - - /* abort command ring */ - retval = xhci_abort_cmd_ring(xhci); - if (retval) { - xhci_err(xhci, "Abort command ring failed\n"); - if (unlikely(retval == -ESHUTDOWN)) { - spin_unlock_irqrestore(&xhci->lock, flags); - usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); - xhci_dbg(xhci, "xHCI host controller is dead.\n"); - return retval; - } - } - -fail: - spin_unlock_irqrestore(&xhci->lock, flags); - return retval; -} - void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, @@ -416,7 +332,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) || (ep_state & EP_HALTED)) return; - xhci_writel(xhci, DB_VALUE(ep_index, stream_id), db_addr); + writel(DB_VALUE(ep_index, stream_id), db_addr); /* The CPU has better things to do at this point than wait for a * write-posting flush. It'll get there soon enough. */ @@ -434,7 +350,7 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci, /* A ring has pending URBs if its TD list is not empty */ if (!(ep->ep_state & EP_HAS_STREAMS)) { - if (!(list_empty(&ep->ring->td_list))) + if (ep->ring && !(list_empty(&ep->ring->td_list))) xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0); return; } @@ -541,10 +457,11 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, struct xhci_dequeue_state *state) { struct xhci_virt_device *dev = xhci->devs[slot_id]; + struct xhci_virt_ep *ep = &dev->eps[ep_index]; struct xhci_ring *ep_ring; struct xhci_generic_trb *trb; - struct xhci_ep_ctx *ep_ctx; dma_addr_t addr; + u64 hw_dequeue; ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id, ep_index, stream_id); @@ -554,56 +471,71 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, stream_id); return; } - state->new_cycle_state = 0; - xhci_dbg(xhci, "Finding segment containing stopped TRB.\n"); - state->new_deq_seg = find_trb_seg(cur_td->start_seg, - dev->eps[ep_index].stopped_trb, - &state->new_cycle_state); - if (!state->new_deq_seg) { - WARN_ON(1); - return; - } /* Dig out the cycle state saved by the xHC during the stop ep cmd */ - xhci_dbg(xhci, "Finding endpoint context\n"); - ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); - state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Finding endpoint context"); + /* 4.6.9 the css flag is written to the stream context for streams */ + if (ep->ep_state & EP_HAS_STREAMS) { + struct xhci_stream_ctx *ctx = + &ep->stream_info->stream_ctx_array[stream_id]; + hw_dequeue = le64_to_cpu(ctx->stream_ring); + } else { + struct xhci_ep_ctx *ep_ctx + = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); + hw_dequeue = le64_to_cpu(ep_ctx->deq); + } + + /* Find virtual address and segment of hardware dequeue pointer */ + state->new_deq_seg = ep_ring->deq_seg; + state->new_deq_ptr = ep_ring->dequeue; + while (xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr) + != (dma_addr_t)(hw_dequeue & ~0xf)) { + next_trb(xhci, ep_ring, &state->new_deq_seg, + &state->new_deq_ptr); + if (state->new_deq_ptr == ep_ring->dequeue) { + WARN_ON(1); + return; + } + } + /* + * Find cycle state for last_trb, starting at old cycle state of + * hw_dequeue. If there is only one segment ring, find_trb_seg() will + * return immediately and cannot toggle the cycle state if this search + * wraps around, so add one more toggle manually in that case. + */ + state->new_cycle_state = hw_dequeue & 0x1; + if (ep_ring->first_seg == ep_ring->first_seg->next && + cur_td->last_trb < state->new_deq_ptr) + state->new_cycle_state ^= 0x1; state->new_deq_ptr = cur_td->last_trb; - xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Finding segment containing last TRB in TD."); state->new_deq_seg = find_trb_seg(state->new_deq_seg, - state->new_deq_ptr, - &state->new_cycle_state); + state->new_deq_ptr, &state->new_cycle_state); if (!state->new_deq_seg) { WARN_ON(1); return; } + /* Increment to find next TRB after last_trb. Cycle if appropriate. */ trb = &state->new_deq_ptr->generic; if (TRB_TYPE_LINK_LE32(trb->field[3]) && (trb->field[3] & cpu_to_le32(LINK_TOGGLE))) state->new_cycle_state ^= 0x1; next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); - /* - * If there is only one segment in a ring, find_trb_seg()'s while loop - * will not run, and it will return before it has a chance to see if it - * needs to toggle the cycle bit. It can't tell if the stalled transfer - * ended just before the link TRB on a one-segment ring, or if the TD - * wrapped around the top of the ring, because it doesn't have the TD in - * question. Look for the one-segment case where stalled TRB's address - * is greater than the new dequeue pointer address. - */ - if (ep_ring->first_seg == ep_ring->first_seg->next && - state->new_deq_ptr < dev->eps[ep_index].stopped_trb) - state->new_cycle_state ^= 0x1; - xhci_dbg(xhci, "Cycle state = 0x%x\n", state->new_cycle_state); - /* Don't update the ring cycle state for the producer (us). */ - xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Cycle state = 0x%x", state->new_cycle_state); + + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "New dequeue segment = %p (virtual)", state->new_deq_seg); addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr); - xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "New dequeue pointer = 0x%llx (DMA)", (unsigned long long) addr); } @@ -631,9 +563,11 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, if (flip_cycle) cur_trb->generic.field[3] ^= cpu_to_le32(TRB_CYCLE); - xhci_dbg(xhci, "Cancel (unchain) link TRB\n"); - xhci_dbg(xhci, "Address = %p (0x%llx dma); " - "in seg %p (0x%llx dma)\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Cancel (unchain) link TRB"); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Address = %p (0x%llx dma); " + "in seg %p (0x%llx dma)", cur_trb, (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb), cur_seg, @@ -651,7 +585,8 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, cpu_to_le32(TRB_CYCLE); cur_trb->generic.field[3] |= cpu_to_le32( TRB_TYPE(TRB_TR_NOOP)); - xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "TRB to noop at offset 0x%llx", (unsigned long long) xhci_trb_virt_to_dma(cur_seg, cur_trb)); } @@ -660,26 +595,29 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } } -static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, +static int queue_set_tr_deq(struct xhci_hcd *xhci, + struct xhci_command *cmd, int slot_id, unsigned int ep_index, unsigned int stream_id, struct xhci_segment *deq_seg, union xhci_trb *deq_ptr, u32 cycle_state); void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, + struct xhci_command *cmd, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id, struct xhci_dequeue_state *deq_state) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; - xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " - "new deq ptr = %p (0x%llx dma), new cycle = %u\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " + "new deq ptr = %p (0x%llx dma), new cycle = %u", deq_state->new_deq_seg, (unsigned long long)deq_state->new_deq_seg->dma, deq_state->new_deq_ptr, (unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr), deq_state->new_cycle_state); - queue_set_tr_deq(xhci, slot_id, ep_index, stream_id, + queue_set_tr_deq(xhci, cmd, slot_id, ep_index, stream_id, deq_state->new_deq_seg, deq_state->new_deq_ptr, (u32) deq_state->new_cycle_state); @@ -705,7 +643,7 @@ static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, /* Must be called with xhci->lock held in interrupt context */ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, - struct xhci_td *cur_td, int status, char *adjective) + struct xhci_td *cur_td, int status) { struct usb_hcd *hcd; struct urb *urb; @@ -744,12 +682,10 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, * 2. Otherwise, we turn all the TRBs in the TD into No-op TRBs (with the chain * bit cleared) so that the HW will skip over them. */ -static void handle_stopped_endpoint(struct xhci_hcd *xhci, +static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, union xhci_trb *trb, struct xhci_event_cmd *event) { - unsigned int slot_id; unsigned int ep_index; - struct xhci_virt_device *virt_dev; struct xhci_ring *ep_ring; struct xhci_virt_ep *ep; struct list_head *entry; @@ -758,15 +694,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, struct xhci_dequeue_state deq_state; - if (unlikely(TRB_TO_SUSPEND_PORT( - le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])))) { - slot_id = TRB_TO_SLOT_ID( - le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); - virt_dev = xhci->devs[slot_id]; - if (virt_dev) - handle_cmd_in_cmd_wait_list(xhci, virt_dev, - event); - else + if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) { + if (!xhci->devs[slot_id]) xhci_warn(xhci, "Stop endpoint command " "completion for disabled slot %u\n", slot_id); @@ -774,14 +703,12 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, } memset(&deq_state, 0, sizeof(deq_state)); - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); ep = &xhci->devs[slot_id]->eps[ep_index]; if (list_empty(&ep->cancelled_td_list)) { xhci_stop_watchdog_timer_in_irq(xhci, ep); ep->stopped_td = NULL; - ep->stopped_trb = NULL; ring_doorbell_for_active_rings(xhci, slot_id, ep_index); return; } @@ -793,7 +720,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, */ list_for_each(entry, &ep->cancelled_td_list) { cur_td = list_entry(entry, struct xhci_td, cancelled_td_list); - xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Removing canceled TD starting at 0x%llx (dma).", (unsigned long long)xhci_trb_virt_to_dma( cur_td->start_seg, cur_td->first_trb)); ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb); @@ -838,7 +766,9 @@ remove_finished_td: /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { - xhci_queue_new_dequeue_state(xhci, + struct xhci_command *command; + command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + xhci_queue_new_dequeue_state(xhci, command, slot_id, ep_index, ep->stopped_td->urb->stream_id, &deq_state); @@ -847,8 +777,10 @@ remove_finished_td: /* Otherwise ring the doorbell(s) to restart queued transfers */ ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } - ep->stopped_td = NULL; - ep->stopped_trb = NULL; + + /* Clear stopped_td if endpoint is not halted */ + if (!(ep->ep_state & EP_HALTED)) + ep->stopped_td = NULL; /* * Drop the lock and complete the URBs in the cancelled TD list. @@ -865,7 +797,7 @@ remove_finished_td: /* Doesn't matter what we pass for status, since the core will * just overwrite it (because the URB has been unlinked). */ - xhci_giveback_urb_in_irq(xhci, cur_td, 0, "cancelled"); + xhci_giveback_urb_in_irq(xhci, cur_td, 0); /* Stop processing the cancelled list if the watchdog timer is * running. @@ -877,6 +809,57 @@ remove_finished_td: /* Return to the event handler with xhci->lock re-acquired */ } +static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ + struct xhci_td *cur_td; + + while (!list_empty(&ring->td_list)) { + cur_td = list_first_entry(&ring->td_list, + struct xhci_td, td_list); + list_del_init(&cur_td->td_list); + if (!list_empty(&cur_td->cancelled_td_list)) + list_del_init(&cur_td->cancelled_td_list); + xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); + } +} + +static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, + int slot_id, int ep_index) +{ + struct xhci_td *cur_td; + struct xhci_virt_ep *ep; + struct xhci_ring *ring; + + ep = &xhci->devs[slot_id]->eps[ep_index]; + if ((ep->ep_state & EP_HAS_STREAMS) || + (ep->ep_state & EP_GETTING_NO_STREAMS)) { + int stream_id; + + for (stream_id = 0; stream_id < ep->stream_info->num_streams; + stream_id++) { + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Killing URBs for slot ID %u, ep index %u, stream %u", + slot_id, ep_index, stream_id + 1); + xhci_kill_ring_urbs(xhci, + ep->stream_info->stream_rings[stream_id]); + } + } else { + ring = ep->ring; + if (!ring) + return; + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Killing URBs for slot ID %u, ep index %u", + slot_id, ep_index); + xhci_kill_ring_urbs(xhci, ring); + } + while (!list_empty(&ep->cancelled_td_list)) { + cur_td = list_first_entry(&ep->cancelled_td_list, + struct xhci_td, cancelled_td_list); + list_del_init(&cur_td->cancelled_td_list); + xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); + } +} + /* Watchdog timer function for when a stop endpoint command fails to complete. * In this case, we assume the host controller is broken or dying or dead. The * host may still be completing some other events, so we have to be careful to @@ -900,9 +883,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) { struct xhci_hcd *xhci; struct xhci_virt_ep *ep; - struct xhci_virt_ep *temp_ep; - struct xhci_ring *ring; - struct xhci_td *cur_td; int ret, i, j; unsigned long flags; @@ -913,14 +893,16 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) ep->stop_cmds_pending--; if (xhci->xhc_state & XHCI_STATE_DYING) { - xhci_dbg(xhci, "Stop EP timer ran, but another timer marked " - "xHCI as DYING, exiting.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Stop EP timer ran, but another timer marked " + "xHCI as DYING, exiting."); spin_unlock_irqrestore(&xhci->lock, flags); return; } if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { - xhci_dbg(xhci, "Stop EP timer ran, but no command pending, " - "exiting.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Stop EP timer ran, but no command pending, " + "exiting."); spin_unlock_irqrestore(&xhci->lock, flags); return; } @@ -957,38 +939,15 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) for (i = 0; i < MAX_HC_SLOTS; i++) { if (!xhci->devs[i]) continue; - for (j = 0; j < 31; j++) { - temp_ep = &xhci->devs[i]->eps[j]; - ring = temp_ep->ring; - if (!ring) - continue; - xhci_dbg(xhci, "Killing URBs for slot ID %u, " - "ep index %u\n", i, j); - while (!list_empty(&ring->td_list)) { - cur_td = list_first_entry(&ring->td_list, - struct xhci_td, - td_list); - list_del_init(&cur_td->td_list); - if (!list_empty(&cur_td->cancelled_td_list)) - list_del_init(&cur_td->cancelled_td_list); - xhci_giveback_urb_in_irq(xhci, cur_td, - -ESHUTDOWN, "killed"); - } - while (!list_empty(&temp_ep->cancelled_td_list)) { - cur_td = list_first_entry( - &temp_ep->cancelled_td_list, - struct xhci_td, - cancelled_td_list); - list_del_init(&cur_td->cancelled_td_list); - xhci_giveback_urb_in_irq(xhci, cur_td, - -ESHUTDOWN, "killed"); - } - } + for (j = 0; j < 31; j++) + xhci_kill_endpoint_urbs(xhci, i, j); } spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "Calling usb_hc_died()\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Calling usb_hc_died()"); usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); - xhci_dbg(xhci, "xHCI host controller is dead.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "xHCI host controller is dead."); } @@ -1046,27 +1005,25 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, * endpoint doorbell to restart the ring, but only if there aren't more * cancellations pending. */ -static void handle_set_deq_completion(struct xhci_hcd *xhci, - struct xhci_event_cmd *event, - union xhci_trb *trb) +static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, + union xhci_trb *trb, u32 cmd_comp_code) { - unsigned int slot_id; unsigned int ep_index; unsigned int stream_id; struct xhci_ring *ep_ring; struct xhci_virt_device *dev; + struct xhci_virt_ep *ep; struct xhci_ep_ctx *ep_ctx; struct xhci_slot_ctx *slot_ctx; - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2])); dev = xhci->devs[slot_id]; + ep = &dev->eps[ep_index]; ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id); if (!ep_ring) { - xhci_warn(xhci, "WARN Set TR deq ptr command for " - "freed stream ID %u\n", + xhci_warn(xhci, "WARN Set TR deq ptr command for freed stream ID %u\n", stream_id); /* XXX: Harmless??? */ dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; @@ -1076,33 +1033,31 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); - if (GET_COMP_CODE(le32_to_cpu(event->status)) != COMP_SUCCESS) { + if (cmd_comp_code != COMP_SUCCESS) { unsigned int ep_state; unsigned int slot_state; - switch (GET_COMP_CODE(le32_to_cpu(event->status))) { + switch (cmd_comp_code) { case COMP_TRB_ERR: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because " - "of stream ID configuration\n"); + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because of stream ID configuration\n"); break; case COMP_CTX_STATE: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due " - "to incorrect slot or ep state.\n"); + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due to incorrect slot or ep state.\n"); ep_state = le32_to_cpu(ep_ctx->ep_info); ep_state &= EP_STATE_MASK; slot_state = le32_to_cpu(slot_ctx->dev_state); slot_state = GET_SLOT_STATE(slot_state); - xhci_dbg(xhci, "Slot state = %u, EP state = %u\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Slot state = %u, EP state = %u", slot_state, ep_state); break; case COMP_EBADSLT: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because " - "slot %u was not enabled.\n", slot_id); + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because slot %u was not enabled.\n", + slot_id); break; default: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown " - "completion code of %u.\n", - GET_COMP_CODE(le32_to_cpu(event->status))); + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown completion code of %u.\n", + cmd_comp_code); break; } /* OK what do we do now? The endpoint state is hosed, and we @@ -1112,22 +1067,28 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, * cancelling URBs, which might not be an error... */ } else { - xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n", - le64_to_cpu(ep_ctx->deq)); - if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg, - dev->eps[ep_index].queued_deq_ptr) == - (le64_to_cpu(ep_ctx->deq) & ~(EP_CTX_CYCLE_MASK))) { + u64 deq; + /* 4.6.10 deq ptr is written to the stream ctx for streams */ + if (ep->ep_state & EP_HAS_STREAMS) { + struct xhci_stream_ctx *ctx = + &ep->stream_info->stream_ctx_array[stream_id]; + deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK; + } else { + deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; + } + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Successful Set TR Deq Ptr cmd, deq = @%08llx", deq); + if (xhci_trb_virt_to_dma(ep->queued_deq_seg, + ep->queued_deq_ptr) == deq) { /* Update the ring's dequeue segment and dequeue pointer * to reflect the new position. */ update_ring_for_set_deq_completion(xhci, dev, ep_ring, ep_index); } else { - xhci_warn(xhci, "Mismatch between completed Set TR Deq " - "Ptr command & xHCI internal state.\n"); + xhci_warn(xhci, "Mismatch between completed Set TR Deq Ptr command & xHCI internal state.\n"); xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n", - dev->eps[ep_index].queued_deq_seg, - dev->eps[ep_index].queued_deq_ptr); + ep->queued_deq_seg, ep->queued_deq_ptr); } } @@ -1138,28 +1099,28 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } -static void handle_reset_ep_completion(struct xhci_hcd *xhci, - struct xhci_event_cmd *event, - union xhci_trb *trb) +static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, + union xhci_trb *trb, u32 cmd_comp_code) { - int slot_id; unsigned int ep_index; - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); /* This command will only fail if the endpoint wasn't halted, * but we don't care. */ - xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n", - GET_COMP_CODE(le32_to_cpu(event->status))); + xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, + "Ignoring reset ep completion code of %u", cmd_comp_code); /* HW with the reset endpoint quirk needs to have a configure endpoint * command complete before the endpoint can be used. Queue that here * because the HW can't handle two commands being queued in a row. */ if (xhci->quirks & XHCI_RESET_EP_QUIRK) { - xhci_dbg(xhci, "Queueing configure endpoint command\n"); - xhci_queue_configure_endpoint(xhci, + struct xhci_command *command; + command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Queueing configure endpoint command"); + xhci_queue_configure_endpoint(xhci, command, xhci->devs[slot_id]->in_ctx->dma, slot_id, false); xhci_ring_cmd_db(xhci); @@ -1170,185 +1131,211 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, } } -/* Complete the command and detele it from the devcie's command queue. - */ -static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, - struct xhci_command *command, u32 status) +static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, + u32 cmd_comp_code) { - command->status = status; - list_del(&command->cmd_list); - if (command->completion) - complete(command->completion); + if (cmd_comp_code == COMP_SUCCESS) + xhci->slot_id = slot_id; else - xhci_free_command(xhci, command); + xhci->slot_id = 0; } - -/* Check to see if a command in the device's command queue matches this one. - * Signal the completion or free the command, and return 1. Return 0 if the - * completed command isn't at the head of the command list. - */ -static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - struct xhci_event_cmd *event) +static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) { - struct xhci_command *command; - - if (list_empty(&virt_dev->cmd_list)) - return 0; - - command = list_entry(virt_dev->cmd_list.next, - struct xhci_command, cmd_list); - if (xhci->cmd_ring->dequeue != command->command_trb) - return 0; + struct xhci_virt_device *virt_dev; - xhci_complete_cmd_in_cmd_wait_list(xhci, command, - GET_COMP_CODE(le32_to_cpu(event->status))); - return 1; + virt_dev = xhci->devs[slot_id]; + if (!virt_dev) + return; + if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) + /* Delete default control endpoint resources */ + xhci_free_device_endpoint_resources(xhci, virt_dev, true); + xhci_free_virt_device(xhci, slot_id); } -/* - * Finding the command trb need to be cancelled and modifying it to - * NO OP command. And if the command is in device's command wait - * list, finishing and freeing it. - * - * If we can't find the command trb, we think it had already been - * executed. - */ -static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd) +static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, + struct xhci_event_cmd *event, u32 cmd_comp_code) { - struct xhci_segment *cur_seg; - union xhci_trb *cmd_trb; - u32 cycle_state; - - if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue) - return; + struct xhci_virt_device *virt_dev; + struct xhci_input_control_ctx *ctrl_ctx; + unsigned int ep_index; + unsigned int ep_state; + u32 add_flags, drop_flags; - /* find the current segment of command ring */ - 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); + /* + * Configure endpoint commands can come from the USB core + * configuration or alt setting changes, or because the HW + * needed an extra configure endpoint command after a reset + * endpoint command or streams were being configured. + * If the command was for a halted endpoint, the xHCI driver + * is not waiting on the configure endpoint command. + */ + virt_dev = xhci->devs[slot_id]; + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "Could not get input context, bad type.\n"); return; } - /* find the command trb matched by cd from command ring */ - for (cmd_trb = xhci->cmd_ring->dequeue; - cmd_trb != xhci->cmd_ring->enqueue; - next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) { - /* If the trb is link trb, continue */ - if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3])) - continue; - - if (cur_cd->cmd_trb == cmd_trb) { + add_flags = le32_to_cpu(ctrl_ctx->add_flags); + drop_flags = le32_to_cpu(ctrl_ctx->drop_flags); + /* Input ctx add_flags are the endpoint index plus one */ + ep_index = xhci_last_valid_endpoint(add_flags) - 1; - /* If the command in device's command list, we should - * finish it and free the command structure. - */ - if (cur_cd->command) - xhci_complete_cmd_in_cmd_wait_list(xhci, - cur_cd->command, COMP_CMD_STOP); - - /* get cycle state from the origin command trb */ - cycle_state = le32_to_cpu(cmd_trb->generic.field[3]) - & TRB_CYCLE; - - /* modify the command trb to NO OP command */ - cmd_trb->generic.field[0] = 0; - cmd_trb->generic.field[1] = 0; - cmd_trb->generic.field[2] = 0; - cmd_trb->generic.field[3] = cpu_to_le32( - TRB_TYPE(TRB_CMD_NOOP) | cycle_state); - break; - } + /* A usb_set_interface() call directly after clearing a halted + * condition may race on this quirky hardware. Not worth + * worrying about, since this is prototype hardware. Not sure + * if this will work for streams, but streams support was + * untested on this prototype. + */ + if (xhci->quirks & XHCI_RESET_EP_QUIRK && + ep_index != (unsigned int) -1 && + add_flags - SLOT_FLAG == drop_flags) { + ep_state = virt_dev->eps[ep_index].ep_state; + if (!(ep_state & EP_HALTED)) + return; + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Completed config ep cmd - " + "last ep index = %d, state = %d", + ep_index, ep_state); + /* Clear internal halted state and restart ring(s) */ + virt_dev->eps[ep_index].ep_state &= ~EP_HALTED; + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); + return; } + return; } -static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci) +static void xhci_handle_cmd_reset_dev(struct xhci_hcd *xhci, int slot_id, + struct xhci_event_cmd *event) { - struct xhci_cd *cur_cd, *next_cd; + xhci_dbg(xhci, "Completed reset device command.\n"); + if (!xhci->devs[slot_id]) + xhci_warn(xhci, "Reset device command completion " + "for disabled slot %u\n", slot_id); +} - if (list_empty(&xhci->cancel_cmd_list)) +static void xhci_handle_cmd_nec_get_fw(struct xhci_hcd *xhci, + struct xhci_event_cmd *event) +{ + if (!(xhci->quirks & XHCI_NEC_HOST)) { + xhci->error_bitmask |= 1 << 6; return; - - list_for_each_entry_safe(cur_cd, next_cd, - &xhci->cancel_cmd_list, cancel_cmd_list) { - xhci_cmd_to_noop(xhci, cur_cd); - list_del(&cur_cd->cancel_cmd_list); - kfree(cur_cd); } + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "NEC firmware version %2x.%02x", + NEC_FW_MAJOR(le32_to_cpu(event->status)), + NEC_FW_MINOR(le32_to_cpu(event->status))); } -/* - * traversing the cancel_cmd_list. If the command descriptor according - * to cmd_trb is found, the function free it and return 1, otherwise - * return 0. - */ -static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci, - union xhci_trb *cmd_trb) +static void xhci_complete_del_and_free_cmd(struct xhci_command *cmd, u32 status) { - struct xhci_cd *cur_cd, *next_cd; - - if (list_empty(&xhci->cancel_cmd_list)) - return 0; + list_del(&cmd->cmd_list); - list_for_each_entry_safe(cur_cd, next_cd, - &xhci->cancel_cmd_list, cancel_cmd_list) { - if (cur_cd->cmd_trb == cmd_trb) { - if (cur_cd->command) - xhci_complete_cmd_in_cmd_wait_list(xhci, - cur_cd->command, COMP_CMD_STOP); - list_del(&cur_cd->cancel_cmd_list); - kfree(cur_cd); - return 1; - } + if (cmd->completion) { + cmd->status = status; + complete(cmd->completion); + } else { + kfree(cmd); } +} - return 0; +void xhci_cleanup_command_queue(struct xhci_hcd *xhci) +{ + struct xhci_command *cur_cmd, *tmp_cmd; + list_for_each_entry_safe(cur_cmd, tmp_cmd, &xhci->cmd_list, cmd_list) + xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT); } /* - * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the - * trb pointed by the command ring dequeue pointer is the trb we want to - * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will - * traverse the cancel_cmd_list to trun the all of the commands according - * to command descriptor to NO-OP trb. + * Turn all commands on command ring with status set to "aborted" to no-op trbs. + * If there are other commands waiting then restart the ring and kick the timer. + * This must be called with command ring stopped and xhci->lock held. */ -static int handle_stopped_cmd_ring(struct xhci_hcd *xhci, - int cmd_trb_comp_code) +static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, + struct xhci_command *cur_cmd) { - int cur_trb_is_good = 0; + struct xhci_command *i_cmd, *tmp_cmd; + u32 cycle_state; - /* Searching the cmd trb pointed by the command ring dequeue - * pointer in command descriptor list. If it is found, free it. - */ - cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci, - xhci->cmd_ring->dequeue); + /* Turn all aborted commands in list to no-ops, then restart */ + list_for_each_entry_safe(i_cmd, tmp_cmd, &xhci->cmd_list, + cmd_list) { - if (cmd_trb_comp_code == COMP_CMD_ABORT) - xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; - else if (cmd_trb_comp_code == COMP_CMD_STOP) { - /* traversing the cancel_cmd_list and canceling - * the command according to command descriptor - */ - xhci_cancel_cmd_in_cd_list(xhci); + if (i_cmd->status != COMP_CMD_ABORT) + continue; + + i_cmd->status = COMP_CMD_STOP; + + xhci_dbg(xhci, "Turn aborted command %p to no-op\n", + i_cmd->command_trb); + /* get cycle state from the original cmd trb */ + cycle_state = le32_to_cpu( + i_cmd->command_trb->generic.field[3]) & TRB_CYCLE; + /* modify the command trb to no-op command */ + i_cmd->command_trb->generic.field[0] = 0; + i_cmd->command_trb->generic.field[1] = 0; + i_cmd->command_trb->generic.field[2] = 0; + i_cmd->command_trb->generic.field[3] = cpu_to_le32( + TRB_TYPE(TRB_CMD_NOOP) | cycle_state); - xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; /* - * ring command ring doorbell again to restart the - * command ring + * caller waiting for completion is called when command + * completion event is received for these no-op commands */ - if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) - xhci_ring_cmd_db(xhci); } - return cur_trb_is_good; + + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; + + /* ring command ring doorbell to restart the command ring */ + if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) && + !(xhci->xhc_state & XHCI_STATE_DYING)) { + xhci->current_cmd = cur_cmd; + mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); + xhci_ring_cmd_db(xhci); + } + return; +} + + +void xhci_handle_command_timeout(unsigned long data) +{ + struct xhci_hcd *xhci; + int ret; + unsigned long flags; + u64 hw_ring_state; + struct xhci_command *cur_cmd = NULL; + xhci = (struct xhci_hcd *) data; + + /* mark this command to be cancelled */ + spin_lock_irqsave(&xhci->lock, flags); + if (xhci->current_cmd) { + cur_cmd = xhci->current_cmd; + cur_cmd->status = COMP_CMD_ABORT; + } + + + /* Make sure command ring is running before aborting it */ + hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) && + (hw_ring_state & CMD_RING_RUNNING)) { + + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "Command timeout\n"); + ret = xhci_abort_cmd_ring(xhci); + if (unlikely(ret == -ESHUTDOWN)) { + xhci_err(xhci, "Abort command ring failed\n"); + xhci_cleanup_command_queue(xhci); + usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); + xhci_dbg(xhci, "xHCI host controller is dead.\n"); + } + return; + } + /* command timeout on stopped ring, ring can't be aborted */ + xhci_dbg(xhci, "Command timeout on stopped ring\n"); + xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd); + spin_unlock_irqrestore(&xhci->lock, flags); + return; } static void handle_cmd_completion(struct xhci_hcd *xhci, @@ -1357,15 +1344,15 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, int slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); u64 cmd_dma; dma_addr_t cmd_dequeue_dma; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_virt_device *virt_dev; - unsigned int ep_index; - struct xhci_ring *ep_ring; - unsigned int ep_state; + u32 cmd_comp_code; + union xhci_trb *cmd_trb; + struct xhci_command *cmd; + u32 cmd_type; cmd_dma = le64_to_cpu(event->cmd_trb); + cmd_trb = xhci->cmd_ring->dequeue; cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, - xhci->cmd_ring->dequeue); + cmd_trb); /* Is the command ring deq ptr out of sync with the deq seg ptr? */ if (cmd_dequeue_dma == 0) { xhci->error_bitmask |= 1 << 4; @@ -1377,131 +1364,101 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, return; } - if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) || - (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) { - /* If the return value is 0, we think the trb pointed by - * command ring dequeue pointer is a good trb. The good - * trb means we don't want to cancel the trb, but it have - * been stopped by host. So we should handle it normally. - * Otherwise, driver should invoke inc_deq() and return. - */ - if (handle_stopped_cmd_ring(xhci, - GET_COMP_CODE(le32_to_cpu(event->status)))) { - inc_deq(xhci, xhci->cmd_ring); - return; - } + cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list); + + if (cmd->command_trb != xhci->cmd_ring->dequeue) { + xhci_err(xhci, + "Command completion event does not match command\n"); + return; } - switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) - & TRB_TYPE_BITMASK) { - case TRB_TYPE(TRB_ENABLE_SLOT): - if (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_SUCCESS) - xhci->slot_id = slot_id; - else - xhci->slot_id = 0; - complete(&xhci->addr_dev); + del_timer(&xhci->cmd_timer); + + trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event); + + cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status)); + + /* If CMD ring stopped we own the trbs between enqueue and dequeue */ + if (cmd_comp_code == COMP_CMD_STOP) { + xhci_handle_stopped_cmd_ring(xhci, cmd); + return; + } + /* + * Host aborted the command ring, check if the current command was + * supposed to be aborted, otherwise continue normally. + * The command ring is stopped now, but the xHC will issue a Command + * Ring Stopped event which will cause us to restart it. + */ + if (cmd_comp_code == COMP_CMD_ABORT) { + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + if (cmd->status == COMP_CMD_ABORT) + goto event_handled; + } + + cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3])); + switch (cmd_type) { + case TRB_ENABLE_SLOT: + xhci_handle_cmd_enable_slot(xhci, slot_id, cmd_comp_code); break; - case TRB_TYPE(TRB_DISABLE_SLOT): - if (xhci->devs[slot_id]) { - if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) - /* Delete default control endpoint resources */ - xhci_free_device_endpoint_resources(xhci, - xhci->devs[slot_id], true); - xhci_free_virt_device(xhci, slot_id); - } + case TRB_DISABLE_SLOT: + xhci_handle_cmd_disable_slot(xhci, slot_id); break; - case TRB_TYPE(TRB_CONFIG_EP): - virt_dev = xhci->devs[slot_id]; - if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) - break; - /* - * Configure endpoint commands can come from the USB core - * configuration or alt setting changes, or because the HW - * needed an extra configure endpoint command after a reset - * endpoint command or streams were being configured. - * If the command was for a halted endpoint, the xHCI driver - * is not waiting on the configure endpoint command. - */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, - virt_dev->in_ctx); - /* Input ctx add_flags are the endpoint index plus one */ - ep_index = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags)) - 1; - /* A usb_set_interface() call directly after clearing a halted - * condition may race on this quirky hardware. Not worth - * worrying about, since this is prototype hardware. Not sure - * if this will work for streams, but streams support was - * untested on this prototype. - */ - if (xhci->quirks & XHCI_RESET_EP_QUIRK && - ep_index != (unsigned int) -1 && - le32_to_cpu(ctrl_ctx->add_flags) - SLOT_FLAG == - le32_to_cpu(ctrl_ctx->drop_flags)) { - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; - ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; - if (!(ep_state & EP_HALTED)) - goto bandwidth_change; - xhci_dbg(xhci, "Completed config ep cmd - " - "last ep index = %d, state = %d\n", - ep_index, ep_state); - /* Clear internal halted state and restart ring(s) */ - xhci->devs[slot_id]->eps[ep_index].ep_state &= - ~EP_HALTED; - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - break; - } -bandwidth_change: - xhci_dbg(xhci, "Completed config ep cmd\n"); - xhci->devs[slot_id]->cmd_status = - GET_COMP_CODE(le32_to_cpu(event->status)); - complete(&xhci->devs[slot_id]->cmd_completion); + case TRB_CONFIG_EP: + if (!cmd->completion) + xhci_handle_cmd_config_ep(xhci, slot_id, event, + cmd_comp_code); break; - case TRB_TYPE(TRB_EVAL_CONTEXT): - virt_dev = xhci->devs[slot_id]; - if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) - break; - xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); - complete(&xhci->devs[slot_id]->cmd_completion); + case TRB_EVAL_CONTEXT: break; - case TRB_TYPE(TRB_ADDR_DEV): - xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); - complete(&xhci->addr_dev); + case TRB_ADDR_DEV: break; - case TRB_TYPE(TRB_STOP_RING): - handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue, event); + case TRB_STOP_RING: + WARN_ON(slot_id != TRB_TO_SLOT_ID( + le32_to_cpu(cmd_trb->generic.field[3]))); + xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event); break; - case TRB_TYPE(TRB_SET_DEQ): - handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue); + case TRB_SET_DEQ: + WARN_ON(slot_id != TRB_TO_SLOT_ID( + le32_to_cpu(cmd_trb->generic.field[3]))); + xhci_handle_cmd_set_deq(xhci, slot_id, cmd_trb, cmd_comp_code); break; - case TRB_TYPE(TRB_CMD_NOOP): + case TRB_CMD_NOOP: + /* Is this an aborted command turned to NO-OP? */ + if (cmd->status == COMP_CMD_STOP) + cmd_comp_code = COMP_CMD_STOP; break; - case TRB_TYPE(TRB_RESET_EP): - handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); + case TRB_RESET_EP: + WARN_ON(slot_id != TRB_TO_SLOT_ID( + le32_to_cpu(cmd_trb->generic.field[3]))); + xhci_handle_cmd_reset_ep(xhci, slot_id, cmd_trb, cmd_comp_code); break; - case TRB_TYPE(TRB_RESET_DEV): - xhci_dbg(xhci, "Completed reset device command.\n"); + case TRB_RESET_DEV: + /* SLOT_ID field in reset device cmd completion event TRB is 0. + * Use the SLOT_ID from the command TRB instead (xhci 4.6.11) + */ slot_id = TRB_TO_SLOT_ID( - le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); - virt_dev = xhci->devs[slot_id]; - if (virt_dev) - handle_cmd_in_cmd_wait_list(xhci, virt_dev, event); - else - xhci_warn(xhci, "Reset device command completion " - "for disabled slot %u\n", slot_id); + le32_to_cpu(cmd_trb->generic.field[3])); + xhci_handle_cmd_reset_dev(xhci, slot_id, event); break; - case TRB_TYPE(TRB_NEC_GET_FW): - if (!(xhci->quirks & XHCI_NEC_HOST)) { - xhci->error_bitmask |= 1 << 6; - break; - } - xhci_dbg(xhci, "NEC firmware version %2x.%02x\n", - NEC_FW_MAJOR(le32_to_cpu(event->status)), - NEC_FW_MINOR(le32_to_cpu(event->status))); + case TRB_NEC_GET_FW: + xhci_handle_cmd_nec_get_fw(xhci, event); break; default: /* Skip over unknown commands on the event ring */ xhci->error_bitmask |= 1 << 6; break; } + + /* restart timer if this wasn't the last command */ + if (cmd->cmd_list.next != &xhci->cmd_list) { + xhci->current_cmd = list_entry(cmd->cmd_list.next, + struct xhci_command, cmd_list); + mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); + } + +event_handled: + xhci_complete_del_and_free_cmd(cmd, cmd_comp_code); + inc_deq(xhci, xhci->cmd_ring); } @@ -1560,7 +1517,7 @@ static void handle_device_notification(struct xhci_hcd *xhci, u32 slot_id; struct usb_device *udev; - slot_id = TRB_TO_SLOT_ID(event->generic.field[3]); + slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->generic.field[3])); if (!xhci->devs[slot_id]) { xhci_warn(xhci, "Device Notification event for " "unused slot %u\n", slot_id); @@ -1644,7 +1601,7 @@ static void handle_port_status(struct xhci_hcd *xhci, faked_port_index = find_faked_portnum_from_hw_portnum(hcd, xhci, port_id); - temp = xhci_readl(xhci, port_array[faked_port_index]); + temp = readl(port_array[faked_port_index]); if (hcd->state == HC_STATE_SUSPENDED) { xhci_dbg(xhci, "resume root hub\n"); usb_hcd_resume_root_hub(hcd); @@ -1653,7 +1610,7 @@ static void handle_port_status(struct xhci_hcd *xhci, if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) { xhci_dbg(xhci, "port resume event for port %d\n", port_id); - temp1 = xhci_readl(xhci, &xhci->op_regs->command); + temp1 = readl(&xhci->op_regs->command); if (!(temp1 & CMD_RUN)) { xhci_warn(xhci, "xHC is not running.\n"); goto cleanup; @@ -1712,6 +1669,19 @@ static void handle_port_status(struct xhci_hcd *xhci, } } + /* + * Check to see if xhci-hub.c is waiting on RExit to U0 transition (or + * RExit to a disconnect state). If so, let the the driver know it's + * out of the RExit state. + */ + if (!DEV_SUPERSPEED(temp) && + test_and_clear_bit(faked_port_index, + &bus_state->rexit_ports)) { + complete(&bus_state->rexit_done[faked_port_index]); + bogus_port_status = true; + goto cleanup; + } + if (hcd->speed != HCD_USB3) xhci_test_and_clear_bit(xhci, port_array, faked_port_index, PORT_PLC); @@ -1804,16 +1774,19 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, struct xhci_td *td, union xhci_trb *event_trb) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; + struct xhci_command *command; + command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + if (!command) + return; + ep->ep_state |= EP_HALTED; ep->stopped_td = td; - ep->stopped_trb = event_trb; ep->stopped_stream = stream_id; - xhci_queue_reset_ep(xhci, slot_id, ep_index); + xhci_queue_reset_ep(xhci, command, slot_id, ep_index); xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); ep->stopped_td = NULL; - ep->stopped_trb = NULL; ep->stopped_stream = 0; xhci_ring_cmd_db(xhci); @@ -1895,7 +1868,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, * the ring dequeue pointer or take this TD off any lists yet. */ ep->stopped_td = td; - ep->stopped_trb = event_trb; return 0; } else { if (trb_comp_code == COMP_STALL) { @@ -1907,7 +1879,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, * USB class driver clear the stall later. */ ep->stopped_td = td; - ep->stopped_trb = event_trb; ep->stopped_stream = ep_ring->stream_id; } else if (xhci_requires_manual_halt_cleanup(xhci, ep_ctx, trb_comp_code)) { @@ -2524,7 +2495,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, * successful event after a short transfer. * Ignore it. */ - if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && + if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && ep_ring->last_td_was_short) { ep_ring->last_td_was_short = false; ret = 0; @@ -2723,7 +2694,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) spin_lock(&xhci->lock); /* Check if the xHC generated the interrupt, or the irq is shared */ - status = xhci_readl(xhci, &xhci->op_regs->status); + status = readl(&xhci->op_regs->status); if (status == 0xffffffff) goto hw_died; @@ -2745,16 +2716,16 @@ hw_died: * Write 1 to clear the interrupt status. */ status |= STS_EINT; - xhci_writel(xhci, status, &xhci->op_regs->status); + writel(status, &xhci->op_regs->status); /* FIXME when MSI-X is supported and there are multiple vectors */ /* Clear the MSI-X event interrupt status */ if (hcd->irq) { u32 irq_pending; /* Acknowledge the PCI interrupt */ - irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); + irq_pending = readl(&xhci->ir_set->irq_pending); irq_pending |= IMAN_IP; - xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending); + writel(irq_pending, &xhci->ir_set->irq_pending); } if (xhci->xhc_state & XHCI_STATE_DYING) { @@ -2799,7 +2770,7 @@ hw_died: return IRQ_HANDLED; } -irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) +irqreturn_t xhci_msi_irq(int irq, void *hcd) { return xhci_irq(hcd); } @@ -2873,8 +2844,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, return -ENOMEM; } - xhci_dbg(xhci, "ERROR no room on ep ring, " - "try ring expansion\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion, + "ERROR no room on ep ring, try ring expansion"); num_trbs_needed = num_trbs - ep_ring->num_trbs_free; if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed, mem_flags)) { @@ -3056,14 +3027,10 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, * to set the polling interval (once the API is added). */ if (xhci_interval != ep_interval) { - if (printk_ratelimit()) - dev_dbg(&urb->dev->dev, "Driver uses different interval" - " (%d microframe%s) than xHCI " - "(%d microframe%s)\n", - ep_interval, - ep_interval == 1 ? "" : "s", - xhci_interval, - xhci_interval == 1 ? "" : "s"); + dev_dbg_ratelimited(&urb->dev->dev, + "Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n", + ep_interval, ep_interval == 1 ? "" : "s", + xhci_interval, xhci_interval == 1 ? "" : "s"); urb->interval = xhci_interval; /* Convert back to frames for LS/FS devices */ if (urb->dev->speed == USB_SPEED_LOW || @@ -3570,7 +3537,7 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci, return 0; max_burst = urb->ep->ss_ep_comp.bMaxBurst; - return roundup(total_packet_count, max_burst + 1) - 1; + return DIV_ROUND_UP(total_packet_count, max_burst + 1) - 1; } /* @@ -3827,7 +3794,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, if (ret) return ret; - start_frame = xhci_readl(xhci, &xhci->run_regs->microframe_index); + start_frame = readl(&xhci->run_regs->microframe_index); start_frame &= 0x3fff; urb->start_frame = start_frame; @@ -3845,14 +3812,10 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, * to set the polling interval (once the API is added). */ if (xhci_interval != ep_interval) { - if (printk_ratelimit()) - dev_dbg(&urb->dev->dev, "Driver uses different interval" - " (%d microframe%s) than xHCI " - "(%d microframe%s)\n", - ep_interval, - ep_interval == 1 ? "" : "s", - xhci_interval, - xhci_interval == 1 ? "" : "s"); + dev_dbg_ratelimited(&urb->dev->dev, + "Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n", + ep_interval, ep_interval == 1 ? "" : "s", + xhci_interval, xhci_interval == 1 ? "" : "s"); urb->interval = xhci_interval; /* Convert back to frames for LS/FS devices */ if (urb->dev->speed == USB_SPEED_LOW || @@ -3874,11 +3837,14 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, * Don't decrement xhci->cmd_ring_reserved_trbs after we've queued the TRB * because the command event handler may want to resubmit a failed command. */ -static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, - u32 field3, u32 field4, bool command_must_succeed) +static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, + u32 field1, u32 field2, + u32 field3, u32 field4, bool command_must_succeed) { int reserved_trbs = xhci->cmd_ring_reserved_trbs; int ret; + if (xhci->xhc_state & XHCI_STATE_DYING) + return -ESHUTDOWN; if (!command_must_succeed) reserved_trbs++; @@ -3892,57 +3858,71 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, "unfailable commands failed.\n"); return ret; } + + cmd->command_trb = xhci->cmd_ring->enqueue; + list_add_tail(&cmd->cmd_list, &xhci->cmd_list); + + /* if there are no other commands queued we start the timeout timer */ + if (xhci->cmd_list.next == &cmd->cmd_list && + !timer_pending(&xhci->cmd_timer)) { + xhci->current_cmd = cmd; + mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); + } + queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, field4 | xhci->cmd_ring->cycle_state); return 0; } /* Queue a slot enable or disable request on the command ring */ -int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id) +int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd, + u32 trb_type, u32 slot_id) { - return queue_command(xhci, 0, 0, 0, + return queue_command(xhci, cmd, 0, 0, 0, TRB_TYPE(trb_type) | SLOT_ID_FOR_TRB(slot_id), false); } /* Queue an address device command TRB */ -int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id) +int xhci_queue_address_device(struct xhci_hcd *xhci, struct xhci_command *cmd, + dma_addr_t in_ctx_ptr, u32 slot_id, enum xhci_setup_dev setup) { - return queue_command(xhci, lower_32_bits(in_ctx_ptr), + return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr), upper_32_bits(in_ctx_ptr), 0, - TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id), - false); + TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id) + | (setup == SETUP_CONTEXT_ONLY ? TRB_BSR : 0), false); } -int xhci_queue_vendor_command(struct xhci_hcd *xhci, +int xhci_queue_vendor_command(struct xhci_hcd *xhci, struct xhci_command *cmd, u32 field1, u32 field2, u32 field3, u32 field4) { - return queue_command(xhci, field1, field2, field3, field4, false); + return queue_command(xhci, cmd, field1, field2, field3, field4, false); } /* Queue a reset device command TRB */ -int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id) +int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd, + u32 slot_id) { - return queue_command(xhci, 0, 0, 0, + return queue_command(xhci, cmd, 0, 0, 0, TRB_TYPE(TRB_RESET_DEV) | SLOT_ID_FOR_TRB(slot_id), false); } /* Queue a configure endpoint command TRB */ -int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, +int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, + struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed) { - return queue_command(xhci, lower_32_bits(in_ctx_ptr), + return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr), upper_32_bits(in_ctx_ptr), 0, TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id), command_must_succeed); } /* Queue an evaluate context command TRB */ -int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id, bool command_must_succeed) +int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd, + dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed) { - return queue_command(xhci, lower_32_bits(in_ctx_ptr), + return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr), upper_32_bits(in_ctx_ptr), 0, TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id), command_must_succeed); @@ -3952,30 +3932,32 @@ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, * Suspend is set to indicate "Stop Endpoint Command" is being issued to stop * activity on an endpoint that is about to be suspended. */ -int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, int suspend) +int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, + int slot_id, unsigned int ep_index, int suspend) { u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); u32 type = TRB_TYPE(TRB_STOP_RING); u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend); - return queue_command(xhci, 0, 0, 0, + return queue_command(xhci, cmd, 0, 0, 0, trb_slot_id | trb_ep_index | type | trb_suspend, false); } /* Set Transfer Ring Dequeue Pointer command. * This should not be used for endpoints that have streams enabled. */ -static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, unsigned int stream_id, - struct xhci_segment *deq_seg, - union xhci_trb *deq_ptr, u32 cycle_state) +static int queue_set_tr_deq(struct xhci_hcd *xhci, struct xhci_command *cmd, + int slot_id, + unsigned int ep_index, unsigned int stream_id, + struct xhci_segment *deq_seg, + union xhci_trb *deq_ptr, u32 cycle_state) { dma_addr_t addr; u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); u32 trb_stream_id = STREAM_ID_FOR_TRB(stream_id); + u32 trb_sct = 0; u32 type = TRB_TYPE(TRB_SET_DEQ); struct xhci_virt_ep *ep; @@ -3994,18 +3976,21 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, } ep->queued_deq_seg = deq_seg; ep->queued_deq_ptr = deq_ptr; - return queue_command(xhci, lower_32_bits(addr) | cycle_state, + if (stream_id) + trb_sct = SCT_FOR_TRB(SCT_PRI_TR); + return queue_command(xhci, cmd, + lower_32_bits(addr) | trb_sct | cycle_state, upper_32_bits(addr), trb_stream_id, trb_slot_id | trb_ep_index | type, false); } -int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index) +int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, + int slot_id, unsigned int ep_index) { u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); u32 type = TRB_TYPE(TRB_RESET_EP); - return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type, - false); + return queue_command(xhci, cmd, 0, 0, 0, + trb_slot_id | trb_ep_index | type, false); } diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c new file mode 100644 index 00000000000..7cf30c83dcf --- /dev/null +++ b/drivers/usb/host/xhci-trace.c @@ -0,0 +1,15 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2013 Xenia Ragiadakou + * + * Author: Xenia Ragiadakou + * Email : burzalodowa@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. + */ + +#define CREATE_TRACE_POINTS +#include "xhci-trace.h" diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h new file mode 100644 index 00000000000..dde3959b7a3 --- /dev/null +++ b/drivers/usb/host/xhci-trace.h @@ -0,0 +1,151 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2013 Xenia Ragiadakou + * + * Author: Xenia Ragiadakou + * Email : burzalodowa@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. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM xhci-hcd + +#if !defined(__XHCI_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __XHCI_TRACE_H + +#include <linux/tracepoint.h> +#include "xhci.h" + +#define XHCI_MSG_MAX 500 + +DECLARE_EVENT_CLASS(xhci_log_msg, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf), + TP_STRUCT__entry(__dynamic_array(char, msg, XHCI_MSG_MAX)), + TP_fast_assign( + vsnprintf(__get_str(msg), XHCI_MSG_MAX, vaf->fmt, *vaf->va); + ), + TP_printk("%s", __get_str(msg)) +); + +DEFINE_EVENT(xhci_log_msg, xhci_dbg_address, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(xhci_log_msg, xhci_dbg_context_change, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(xhci_log_msg, xhci_dbg_quirks, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(xhci_log_msg, xhci_dbg_reset_ep, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(xhci_log_msg, xhci_dbg_cancel_urb, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(xhci_log_msg, xhci_dbg_init, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(xhci_log_msg, xhci_dbg_ring_expansion, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DECLARE_EVENT_CLASS(xhci_log_ctx, + TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, + unsigned int ep_num), + TP_ARGS(xhci, ctx, ep_num), + TP_STRUCT__entry( + __field(int, ctx_64) + __field(unsigned, ctx_type) + __field(dma_addr_t, ctx_dma) + __field(u8 *, ctx_va) + __field(unsigned, ctx_ep_num) + __field(int, slot_id) + __dynamic_array(u32, ctx_data, + ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 8) * + ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1)) + ), + TP_fast_assign( + struct usb_device *udev; + + udev = to_usb_device(xhci_to_hcd(xhci)->self.controller); + __entry->ctx_64 = HCC_64BYTE_CONTEXT(xhci->hcc_params); + __entry->ctx_type = ctx->type; + __entry->ctx_dma = ctx->dma; + __entry->ctx_va = ctx->bytes; + __entry->slot_id = udev->slot_id; + __entry->ctx_ep_num = ep_num; + memcpy(__get_dynamic_array(ctx_data), ctx->bytes, + ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 32) * + ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1)); + ), + TP_printk("\nctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p", + __entry->ctx_64, __entry->ctx_type, + (unsigned long long) __entry->ctx_dma, __entry->ctx_va + ) +); + +DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx, + TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, + unsigned int ep_num), + TP_ARGS(xhci, ctx, ep_num) +); + +DECLARE_EVENT_CLASS(xhci_log_event, + TP_PROTO(void *trb_va, struct xhci_generic_trb *ev), + TP_ARGS(trb_va, ev), + TP_STRUCT__entry( + __field(void *, va) + __field(u64, dma) + __field(u32, status) + __field(u32, flags) + __dynamic_array(u8, trb, sizeof(struct xhci_generic_trb)) + ), + TP_fast_assign( + __entry->va = trb_va; + __entry->dma = ((u64)le32_to_cpu(ev->field[1])) << 32 | + le32_to_cpu(ev->field[0]); + __entry->status = le32_to_cpu(ev->field[2]); + __entry->flags = le32_to_cpu(ev->field[3]); + memcpy(__get_dynamic_array(trb), trb_va, + sizeof(struct xhci_generic_trb)); + ), + TP_printk("\ntrb_dma=@%llx, trb_va=@%p, status=%08x, flags=%08x", + (unsigned long long) __entry->dma, __entry->va, + __entry->status, __entry->flags + ) +); + +DEFINE_EVENT(xhci_log_event, xhci_cmd_completion, + TP_PROTO(void *trb_va, struct xhci_generic_trb *ev), + TP_ARGS(trb_va, ev) +); + +#endif /* __XHCI_TRACE_H */ + +/* this part must be outside header guard */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE xhci-trace + +#include <trace/define_trace.h> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d8f640b12dd..7436d5f5e67 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -27,8 +27,10 @@ #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/dmi.h> +#include <linux/dma-mapping.h> #include "xhci.h" +#include "xhci-trace.h" #define DRIVER_AUTHOR "Sarah Sharp" #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" @@ -38,6 +40,10 @@ static int link_quirk; module_param(link_quirk, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); +static unsigned int quirks; +module_param(quirks, uint, S_IRUGO); +MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default"); + /* TODO: copied from ehci-hcd.c - can this be refactored? */ /* * xhci_handshake - spin reading hc until handshake completes or fails @@ -58,7 +64,7 @@ int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr, u32 result; do { - result = xhci_readl(xhci, ptr); + result = readl(ptr); if (result == ~(u32)0) /* card removed */ return -ENODEV; result &= mask; @@ -80,13 +86,13 @@ void xhci_quiesce(struct xhci_hcd *xhci) u32 mask; mask = ~(XHCI_IRQS); - halted = xhci_readl(xhci, &xhci->op_regs->status) & STS_HALT; + halted = readl(&xhci->op_regs->status) & STS_HALT; if (!halted) mask &= ~CMD_RUN; - cmd = xhci_readl(xhci, &xhci->op_regs->command); + cmd = readl(&xhci->op_regs->command); cmd &= mask; - xhci_writel(xhci, cmd, &xhci->op_regs->command); + writel(cmd, &xhci->op_regs->command); } /* @@ -100,7 +106,7 @@ void xhci_quiesce(struct xhci_hcd *xhci) int xhci_halt(struct xhci_hcd *xhci) { int ret; - xhci_dbg(xhci, "// Halt the HC\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC"); xhci_quiesce(xhci); ret = xhci_handshake(xhci, &xhci->op_regs->status, @@ -122,11 +128,11 @@ static int xhci_start(struct xhci_hcd *xhci) u32 temp; int ret; - temp = xhci_readl(xhci, &xhci->op_regs->command); + temp = readl(&xhci->op_regs->command); temp |= (CMD_RUN); - xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.", temp); - xhci_writel(xhci, temp, &xhci->op_regs->command); + writel(temp, &xhci->op_regs->command); /* * Wait for the HCHalted Status bit to be 0 to indicate the host is @@ -156,23 +162,24 @@ int xhci_reset(struct xhci_hcd *xhci) u32 state; int ret, i; - state = xhci_readl(xhci, &xhci->op_regs->status); + state = readl(&xhci->op_regs->status); if ((state & STS_HALT) == 0) { xhci_warn(xhci, "Host controller not halted, aborting reset.\n"); return 0; } - xhci_dbg(xhci, "// Reset the HC\n"); - command = xhci_readl(xhci, &xhci->op_regs->command); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Reset the HC"); + command = readl(&xhci->op_regs->command); command |= CMD_RESET; - xhci_writel(xhci, command, &xhci->op_regs->command); + writel(command, &xhci->op_regs->command); ret = xhci_handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; - xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Wait for controller to be ready for doorbell rings"); /* * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. @@ -214,14 +221,16 @@ static int xhci_setup_msi(struct xhci_hcd *xhci) ret = pci_enable_msi(pdev); if (ret) { - xhci_dbg(xhci, "failed to allocate MSI entry\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "failed to allocate MSI entry"); return ret; } - ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq, + ret = request_irq(pdev->irq, xhci_msi_irq, 0, "xhci_hcd", xhci_to_hcd(xhci)); if (ret) { - xhci_dbg(xhci, "disable MSI interrupt\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "disable MSI interrupt"); pci_disable_msi(pdev); } @@ -282,15 +291,16 @@ static int xhci_setup_msix(struct xhci_hcd *xhci) xhci->msix_entries[i].vector = 0; } - ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); + ret = pci_enable_msix_exact(pdev, xhci->msix_entries, xhci->msix_count); if (ret) { - xhci_dbg(xhci, "Failed to enable MSI-X\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Failed to enable MSI-X"); goto free_entries; } for (i = 0; i < xhci->msix_count; i++) { ret = request_irq(xhci->msix_entries[i].vector, - (irq_handler_t)xhci_msi_irq, + xhci_msi_irq, 0, "xhci_hcd", xhci_to_hcd(xhci)); if (ret) goto disable_msix; @@ -300,7 +310,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci) return ret; disable_msix: - xhci_dbg(xhci, "disable MSI-X interrupt\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); xhci_free_irq(xhci); pci_disable_msix(pdev); free_entries: @@ -315,6 +325,9 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci) struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + if (xhci->quirks & XHCI_PLAT) + return; + xhci_free_irq(xhci); if (xhci->msix_entries) { @@ -329,7 +342,7 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci) return; } -static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) { int i; @@ -342,9 +355,14 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) static int xhci_try_enable_msi(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct pci_dev *pdev; int ret; + /* The xhci platform device has set up IRQs through usb_add_hcd. */ + if (xhci->quirks & XHCI_PLAT) + return 0; + + pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); /* * Some Fresco Logic host controllers advertise MSI, but fail to * generate interrupts. Don't even try to enable MSI. @@ -372,6 +390,10 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd) } legacy_irq: + if (!strlen(hcd->irq_descr)) + snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", + hcd->driver->description, hcd->self.busnum); + /* fall back to legacy interrupt*/ ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, hcd->irq_descr, hcd); @@ -386,16 +408,16 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd) #else -static int xhci_try_enable_msi(struct usb_hcd *hcd) +static inline int xhci_try_enable_msi(struct usb_hcd *hcd) { return 0; } -static void xhci_cleanup_msix(struct xhci_hcd *xhci) +static inline void xhci_cleanup_msix(struct xhci_hcd *xhci) { } -static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci) { } @@ -411,15 +433,17 @@ static void compliance_mode_recovery(unsigned long arg) xhci = (struct xhci_hcd *)arg; for (i = 0; i < xhci->num_usb3_ports; i++) { - temp = xhci_readl(xhci, xhci->usb3_ports[i]); + temp = readl(xhci->usb3_ports[i]); if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) { /* * Compliance Mode Detected. Letting USB Core * handle the Warm Reset */ - xhci_dbg(xhci, "Compliance mode detected->port %d\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Compliance mode detected->port %d", i + 1); - xhci_dbg(xhci, "Attempting compliance mode recovery\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Attempting compliance mode recovery"); hcd = xhci->shared_hcd; if (hcd->state == HC_STATE_SUSPENDED) @@ -457,7 +481,8 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) set_timer_slack(&xhci->comp_mode_recovery_timer, msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); add_timer(&xhci->comp_mode_recovery_timer); - xhci_dbg(xhci, "Compliance mode recovery timer initialized\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Compliance mode recovery timer initialized"); } /* @@ -505,16 +530,18 @@ int xhci_init(struct usb_hcd *hcd) struct xhci_hcd *xhci = hcd_to_xhci(hcd); int retval = 0; - xhci_dbg(xhci, "xhci_init\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init"); spin_lock_init(&xhci->lock); if (xhci->hci_version == 0x95 && link_quirk) { - xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Not clearing Link TRB chain bits."); xhci->quirks |= XHCI_LINK_TRB_QUIRK; } else { - xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "xHCI doesn't need link TRB QUIRK"); } retval = xhci_mem_init(xhci, GFP_KERNEL); - xhci_dbg(xhci, "Finished xhci_init\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init"); /* Initializing Compliance Mode Recovery Data If Needed */ if (xhci_compliance_mode_recovery_timer_quirk_check()) { @@ -528,57 +555,6 @@ int xhci_init(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -static void xhci_event_ring_work(unsigned long arg) -{ - unsigned long flags; - int temp; - u64 temp_64; - struct xhci_hcd *xhci = (struct xhci_hcd *) arg; - int i, j; - - xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies); - - spin_lock_irqsave(&xhci->lock, flags); - temp = xhci_readl(xhci, &xhci->op_regs->status); - xhci_dbg(xhci, "op reg status = 0x%x\n", temp); - if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || - (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "HW died, polling stopped.\n"); - spin_unlock_irqrestore(&xhci->lock, flags); - return; - } - - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); - xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask); - xhci->error_bitmask = 0; - xhci_dbg(xhci, "Event ring:\n"); - xhci_debug_segment(xhci, xhci->event_ring->deq_seg); - xhci_dbg_ring_ptrs(xhci, xhci->event_ring); - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - temp_64 &= ~ERST_PTR_MASK; - xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); - xhci_dbg(xhci, "Command ring:\n"); - xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg); - xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); - xhci_dbg_cmd_ptrs(xhci); - for (i = 0; i < MAX_HC_SLOTS; ++i) { - if (!xhci->devs[i]) - continue; - for (j = 0; j < 31; ++j) { - xhci_dbg_ep_rings(xhci, i, j, &xhci->devs[i]->eps[j]); - } - } - spin_unlock_irqrestore(&xhci->lock, flags); - - if (!xhci->zombie) - mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ); - else - xhci_dbg(xhci, "Quit polling the event ring.\n"); -} -#endif - static int xhci_run_finished(struct xhci_hcd *xhci) { if (xhci_start(xhci)) { @@ -591,7 +567,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci) if (xhci->quirks & XHCI_NEC_HOST) xhci_ring_cmd_db(xhci); - xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Finished xhci_run for USB3 roothub"); return 0; } @@ -622,23 +599,12 @@ int xhci_run(struct usb_hcd *hcd) if (!usb_hcd_is_primary_hcd(hcd)) return xhci_run_finished(xhci); - xhci_dbg(xhci, "xhci_run\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run"); ret = xhci_try_enable_msi(hcd); if (ret) return ret; -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - init_timer(&xhci->event_ring_timer); - xhci->event_ring_timer.data = (unsigned long) xhci; - xhci->event_ring_timer.function = xhci_event_ring_work; - /* Poll the event ring */ - xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ; - xhci->zombie = 0; - xhci_dbg(xhci, "Setting event ring polling timer\n"); - add_timer(&xhci->event_ring_timer); -#endif - xhci_dbg(xhci, "Command ring memory map follows:\n"); xhci_debug_ring(xhci, xhci->cmd_ring); xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); @@ -651,33 +617,40 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg_ring_ptrs(xhci, xhci->event_ring); temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; - xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "ERST deq = 64'h%0lx", (long unsigned int) temp_64); - xhci_dbg(xhci, "// Set the interrupt modulation register\n"); - temp = xhci_readl(xhci, &xhci->ir_set->irq_control); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Set the interrupt modulation register"); + temp = readl(&xhci->ir_set->irq_control); temp &= ~ER_IRQ_INTERVAL_MASK; temp |= (u32) 160; - xhci_writel(xhci, temp, &xhci->ir_set->irq_control); + writel(temp, &xhci->ir_set->irq_control); /* Set the HCD state before we enable the irqs */ - temp = xhci_readl(xhci, &xhci->op_regs->command); + temp = readl(&xhci->op_regs->command); temp |= (CMD_EIE); - xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n", - temp); - xhci_writel(xhci, temp, &xhci->op_regs->command); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Enable interrupts, cmd = 0x%x.", temp); + writel(temp, &xhci->op_regs->command); - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n", + temp = readl(&xhci->ir_set->irq_pending); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Enabling event ring interrupter %p by writing 0x%x to irq_pending", xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp)); - xhci_writel(xhci, ER_IRQ_ENABLE(temp), - &xhci->ir_set->irq_pending); + writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending); xhci_print_ir_set(xhci, 0); - if (xhci->quirks & XHCI_NEC_HOST) - xhci_queue_vendor_command(xhci, 0, 0, 0, + if (xhci->quirks & XHCI_NEC_HOST) { + struct xhci_command *command; + command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); + if (!command) + return -ENOMEM; + xhci_queue_vendor_command(xhci, command, 0, 0, 0, TRB_TYPE(TRB_NEC_GET_FW)); - - xhci_dbg(xhci, "Finished xhci_run for USB2 roothub\n"); + } + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Finished xhci_run for USB2 roothub"); return 0; } @@ -725,35 +698,31 @@ void xhci_stop(struct usb_hcd *hcd) xhci_cleanup_msix(xhci); -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - /* Tell the event ring poll function not to reschedule */ - xhci->zombie = 1; - del_timer_sync(&xhci->event_ring_timer); -#endif - /* Deleting Compliance Mode Recovery Timer */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { del_timer_sync(&xhci->comp_mode_recovery_timer); - xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "%s: compliance mode recovery timer deleted", __func__); } if (xhci->quirks & XHCI_AMD_PLL_FIX) usb_amd_dev_put(); - xhci_dbg(xhci, "// Disabling event ring interrupts\n"); - temp = xhci_readl(xhci, &xhci->op_regs->status); - xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_writel(xhci, ER_IRQ_DISABLE(temp), - &xhci->ir_set->irq_pending); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Disabling event ring interrupts"); + temp = readl(&xhci->op_regs->status); + writel(temp & ~STS_EINT, &xhci->op_regs->status); + temp = readl(&xhci->ir_set->irq_pending); + writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); xhci_print_ir_set(xhci, 0); - xhci_dbg(xhci, "cleaning up memory\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory"); xhci_mem_cleanup(xhci); - xhci_dbg(xhci, "xhci_stop completed - status = %x\n", - xhci_readl(xhci, &xhci->op_regs->status)); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "xhci_stop completed - status = %x", + readl(&xhci->op_regs->status)); } /* @@ -774,39 +743,47 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_lock_irq(&xhci->lock); xhci_halt(xhci); + /* Workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + xhci_reset(xhci); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); - xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", - xhci_readl(xhci, &xhci->op_regs->status)); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "xhci_shutdown completed - status = %x", + readl(&xhci->op_regs->status)); + + /* Yet another workaround for spurious wakeups at shutdown with HSW */ + if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot); } #ifdef CONFIG_PM static void xhci_save_registers(struct xhci_hcd *xhci) { - xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command); - xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification); + xhci->s3.command = readl(&xhci->op_regs->command); + xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification); xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); - xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg); - xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size); + xhci->s3.config_reg = readl(&xhci->op_regs->config_reg); + xhci->s3.erst_size = readl(&xhci->ir_set->erst_size); xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base); xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control); + xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending); + xhci->s3.irq_control = readl(&xhci->ir_set->irq_control); } static void xhci_restore_registers(struct xhci_hcd *xhci) { - xhci_writel(xhci, xhci->s3.command, &xhci->op_regs->command); - xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification); + writel(xhci->s3.command, &xhci->op_regs->command); + writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification); xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); - xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg); - xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size); + writel(xhci->s3.config_reg, &xhci->op_regs->config_reg); + writel(xhci->s3.erst_size, &xhci->ir_set->erst_size); xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base); xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue); - xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending); - xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control); + writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending); + writel(xhci->s3.irq_control, &xhci->ir_set->irq_control); } static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) @@ -820,7 +797,8 @@ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) xhci->cmd_ring->dequeue) & (u64) ~CMD_RING_RSVD_BITS) | xhci->cmd_ring->cycle_state; - xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Setting command ring address to 0x%llx", (long unsigned long) val_64); xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); } @@ -881,6 +859,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) int xhci_suspend(struct xhci_hcd *xhci) { int rc = 0; + unsigned int delay = XHCI_MAX_HALT_USEC; struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; @@ -900,11 +879,15 @@ int xhci_suspend(struct xhci_hcd *xhci) /* skipped assuming that port suspend has done */ /* step 2: clear Run/Stop bit */ - command = xhci_readl(xhci, &xhci->op_regs->command); + command = readl(&xhci->op_regs->command); command &= ~CMD_RUN; - xhci_writel(xhci, command, &xhci->op_regs->command); + writel(command, &xhci->op_regs->command); + + /* Some chips from Fresco Logic need an extraordinary delay */ + delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1; + if (xhci_handshake(xhci, &xhci->op_regs->status, - STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { + STS_HALT, STS_HALT, delay)) { xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; @@ -915,9 +898,9 @@ int xhci_suspend(struct xhci_hcd *xhci) xhci_save_registers(xhci); /* step 4: set CSS flag */ - command = xhci_readl(xhci, &xhci->op_regs->command); + command = readl(&xhci->op_regs->command); command |= CMD_CSS; - xhci_writel(xhci, command, &xhci->op_regs->command); + writel(command, &xhci->op_regs->command); if (xhci_handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10 * 1000)) { xhci_warn(xhci, "WARN: xHC save state timeout\n"); @@ -933,7 +916,8 @@ int xhci_suspend(struct xhci_hcd *xhci) if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { del_timer_sync(&xhci->comp_mode_recovery_timer); - xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "%s: compliance mode recovery timer deleted", __func__); } @@ -952,7 +936,7 @@ int xhci_suspend(struct xhci_hcd *xhci) */ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) { - u32 command, temp = 0; + u32 command, temp = 0, status; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; @@ -980,16 +964,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_set_cmd_ring_deq(xhci); /* step 3: restore state and start state*/ /* step 3: set CRS flag */ - command = xhci_readl(xhci, &xhci->op_regs->command); + command = readl(&xhci->op_regs->command); command |= CMD_CRS; - xhci_writel(xhci, command, &xhci->op_regs->command); + writel(command, &xhci->op_regs->command); if (xhci_handshake(xhci, &xhci->op_regs->status, STS_RESTORE, 0, 10 * 1000)) { xhci_warn(xhci, "WARN: xHC restore state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } - temp = xhci_readl(xhci, &xhci->op_regs->status); + temp = readl(&xhci->op_regs->status); } /* If restore operation fails, re-initialize the HC during resume */ @@ -998,7 +982,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !(xhci_all_ports_seen_u0(xhci))) { del_timer_sync(&xhci->comp_mode_recovery_timer); - xhci_dbg(xhci, "Compliance Mode Recovery Timer deleted!\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Compliance Mode Recovery Timer deleted!"); } /* Let the USB core know _both_ roothubs lost power. */ @@ -1011,24 +996,17 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - /* Tell the event ring poll function not to reschedule */ - xhci->zombie = 1; - del_timer_sync(&xhci->event_ring_timer); -#endif - xhci_dbg(xhci, "// Disabling event ring interrupts\n"); - temp = xhci_readl(xhci, &xhci->op_regs->status); - xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_writel(xhci, ER_IRQ_DISABLE(temp), - &xhci->ir_set->irq_pending); + temp = readl(&xhci->op_regs->status); + writel(temp & ~STS_EINT, &xhci->op_regs->status); + temp = readl(&xhci->ir_set->irq_pending); + writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); xhci_print_ir_set(xhci, 0); xhci_dbg(xhci, "cleaning up memory\n"); xhci_mem_cleanup(xhci); xhci_dbg(xhci, "xhci_stop completed - status = %x\n", - xhci_readl(xhci, &xhci->op_regs->status)); + readl(&xhci->op_regs->status)); /* USB core calls the PCI reinit and start functions twice: * first with the primary HCD, and then with the secondary HCD. @@ -1057,9 +1035,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) } /* step 4: set Run/Stop bit */ - command = xhci_readl(xhci, &xhci->op_regs->command); + command = readl(&xhci->op_regs->command); command |= CMD_RUN; - xhci_writel(xhci, command, &xhci->op_regs->command); + writel(command, &xhci->op_regs->command); xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT, 0, 250 * 1000); @@ -1076,8 +1054,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) done: if (retval == 0) { - usb_hcd_resume_root_hub(hcd); - usb_hcd_resume_root_hub(xhci->shared_hcd); + /* Resume root hubs only when have pending events. */ + status = readl(&xhci->op_regs->status); + if (status & STS_EINT) { + usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(xhci->shared_hcd); + } } /* @@ -1121,6 +1103,16 @@ unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc) return index; } +/* The reverse operation to xhci_get_endpoint_index. Calculate the USB endpoint + * address from the XHCI endpoint index. + */ +unsigned int xhci_get_endpoint_address(unsigned int ep_index) +{ + unsigned int number = DIV_ROUND_UP(ep_index, 2); + unsigned int direction = ep_index % 2 ? USB_DIR_OUT : USB_DIR_IN; + return direction | number; +} + /* Find the flag for this endpoint (for use in the control context). Use the * endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is * bit 1, etc. @@ -1160,35 +1152,33 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, struct xhci_virt_device *virt_dev; if (!hcd || (check_ep && !ep) || !udev) { - printk(KERN_DEBUG "xHCI %s called with invalid args\n", - func); + pr_debug("xHCI %s called with invalid args\n", func); return -EINVAL; } if (!udev->parent) { - printk(KERN_DEBUG "xHCI %s called for root hub\n", - func); + pr_debug("xHCI %s called for root hub\n", func); return 0; } xhci = hcd_to_xhci(hcd); - if (xhci->xhc_state & XHCI_STATE_HALTED) - return -ENODEV; - if (check_virt_dev) { if (!udev->slot_id || !xhci->devs[udev->slot_id]) { - printk(KERN_DEBUG "xHCI %s called with unaddressed " - "device\n", func); + xhci_dbg(xhci, "xHCI %s called with unaddressed device\n", + func); return -EINVAL; } virt_dev = xhci->devs[udev->slot_id]; if (virt_dev->udev != udev) { - printk(KERN_DEBUG "xHCI %s called with udev and " + xhci_dbg(xhci, "xHCI %s called with udev and " "virt_dev does not match\n", func); return -EINVAL; } } + if (xhci->xhc_state & XHCI_STATE_HALTED) + return -ENODEV; + return 1; } @@ -1205,10 +1195,10 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct urb *urb) { - struct xhci_container_ctx *in_ctx; struct xhci_container_ctx *out_ctx; struct xhci_input_control_ctx *ctrl_ctx; struct xhci_ep_ctx *ep_ctx; + struct xhci_command *command; int max_packet_size; int hw_max_packet_size; int ret = 0; @@ -1218,41 +1208,60 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc); if (hw_max_packet_size != max_packet_size) { - xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n"); - xhci_dbg(xhci, "Max packet size in usb_device = %d\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Max Packet Size for ep 0 changed."); + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Max packet size in usb_device = %d", max_packet_size); - xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Max packet size in xHCI HW = %d", hw_max_packet_size); - xhci_dbg(xhci, "Issuing evaluate context command.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Issuing evaluate context command."); + /* Set up the input context flags for the command */ + /* FIXME: This won't work if a non-default control endpoint + * changes max packet sizes. + */ + + command = xhci_alloc_command(xhci, false, true, GFP_KERNEL); + if (!command) + return -ENOMEM; + + command->in_ctx = xhci->devs[slot_id]->in_ctx; + ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + ret = -ENOMEM; + goto command_cleanup; + } /* Set up the modified control endpoint 0 */ xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, xhci->devs[slot_id]->out_ctx, ep_index); - in_ctx = xhci->devs[slot_id]->in_ctx; - ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); + + ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index); ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK); ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); - /* Set up the input context flags for the command */ - /* FIXME: This won't work if a non-default control endpoint - * changes max packet sizes. - */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG); ctrl_ctx->drop_flags = 0; xhci_dbg(xhci, "Slot %d input context\n", slot_id); - xhci_dbg_ctx(xhci, in_ctx, ep_index); + xhci_dbg_ctx(xhci, command->in_ctx, ep_index); xhci_dbg(xhci, "Slot %d output context\n", slot_id); xhci_dbg_ctx(xhci, out_ctx, ep_index); - ret = xhci_configure_endpoint(xhci, urb->dev, NULL, + ret = xhci_configure_endpoint(xhci, urb->dev, command, true, false); /* Clean up the input context for later use by bandwidth * functions. */ ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); +command_cleanup: + kfree(command->completion); + kfree(command); } return ret; } @@ -1473,6 +1482,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) unsigned int ep_index; struct xhci_ring *ep_ring; struct xhci_virt_ep *ep; + struct xhci_command *command; xhci = hcd_to_xhci(hcd); spin_lock_irqsave(&xhci->lock, flags); @@ -1480,9 +1490,10 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret || !urb->hcpriv) goto done; - temp = xhci_readl(xhci, &xhci->op_regs->status); + temp = readl(&xhci->op_regs->status); if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "HW died, freeing TD.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "HW died, freeing TD."); urb_priv = urb->hcpriv; for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { td = urb_priv->td[i]; @@ -1500,8 +1511,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } if ((xhci->xhc_state & XHCI_STATE_DYING) || (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on " - "non-responsive xHCI host.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Ep 0x%x: URB %p to be canceled on " + "non-responsive xHCI host.", urb->ep->desc.bEndpointAddress, urb); /* Let the stop endpoint command watchdog timer (which set this * state) finish cleaning up the endpoint TD lists. We must @@ -1522,8 +1534,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) urb_priv = urb->hcpriv; i = urb_priv->td_cnt; if (i < urb_priv->length) - xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, " - "starting at offset 0x%llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Cancel URB %p, dev %s, ep 0x%x, " + "starting at offset 0x%llx", urb, urb->dev->devpath, urb->ep->desc.bEndpointAddress, (unsigned long long) xhci_trb_virt_to_dma( @@ -1539,12 +1552,14 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) * the first cancellation to be handled. */ if (!(ep->ep_state & EP_HALT_PENDING)) { + command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); ep->ep_state |= EP_HALT_PENDING; ep->stop_cmds_pending++; ep->stop_cmd_timer.expires = jiffies + XHCI_STOP_EP_CMD_TIMEOUT * HZ; add_timer(&ep->stop_cmd_timer); - xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0); + xhci_queue_stop_endpoint(xhci, command, urb->dev->slot_id, + ep_index, 0); xhci_ring_cmd_db(xhci); } done: @@ -1597,6 +1612,12 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, in_ctx = xhci->devs[udev->slot_id]->in_ctx; out_ctx = xhci->devs[udev->slot_id]->out_ctx; ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return 0; + } + ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); /* If the HC already knows the endpoint is disabled, @@ -1691,8 +1712,13 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, in_ctx = virt_dev->in_ctx; out_ctx = virt_dev->out_ctx; ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - ep_index = xhci_get_endpoint_index(&ep->desc); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return 0; + } + ep_index = xhci_get_endpoint_index(&ep->desc); /* If this endpoint is already in use, and the upper layers are trying * to add it again without dropping it, reject the addition. */ @@ -1765,12 +1791,18 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir struct xhci_slot_ctx *slot_ctx; int i; + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return; + } + /* When a device's add flag and drop flag are zero, any subsequent * configure endpoint command will leave that endpoint's state * untouched. Make sure we don't leave any old state in the input * endpoint contexts. */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ctrl_ctx->drop_flags = 0; ctrl_ctx->add_flags = 0; slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); @@ -1792,6 +1824,11 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, int ret; switch (*cmd_status) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout while waiting for configure endpoint command\n"); + ret = -ETIME; + break; case COMP_ENOMEM: dev_warn(&udev->dev, "Not enough host controller resources " "for new device state.\n"); @@ -1818,7 +1855,8 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, ret = -ENODEV; break; case COMP_SUCCESS: - dev_dbg(&udev->dev, "Successful Endpoint Configure command\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Successful Endpoint Configure command"); ret = 0; break; default: @@ -1837,6 +1875,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; switch (*cmd_status) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout while waiting for evaluate context command\n"); + ret = -ETIME; + break; case COMP_EINVAL: dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate " "context command.\n"); @@ -1864,7 +1907,8 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, ret = -EINVAL; break; case COMP_SUCCESS: - dev_dbg(&udev->dev, "Successful evaluate context command\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Successful evaluate context command"); ret = 0; break; default: @@ -1877,19 +1921,17 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, } static u32 xhci_count_num_new_endpoints(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) + struct xhci_input_control_ctx *ctrl_ctx) { - struct xhci_input_control_ctx *ctrl_ctx; u32 valid_add_flags; u32 valid_drop_flags; - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); /* Ignore the slot flag (bit 0), and the default control endpoint flag * (bit 1). The default control endpoint is added during the Address * Device command and is never removed until the slot is disabled. */ - valid_add_flags = ctrl_ctx->add_flags >> 2; - valid_drop_flags = ctrl_ctx->drop_flags >> 2; + valid_add_flags = le32_to_cpu(ctrl_ctx->add_flags) >> 2; + valid_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags) >> 2; /* Use hweight32 to count the number of ones in the add flags, or * number of endpoints added. Don't count endpoints that are changed @@ -1900,15 +1942,13 @@ static u32 xhci_count_num_new_endpoints(struct xhci_hcd *xhci, } static unsigned int xhci_count_num_dropped_endpoints(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) + struct xhci_input_control_ctx *ctrl_ctx) { - struct xhci_input_control_ctx *ctrl_ctx; u32 valid_add_flags; u32 valid_drop_flags; - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - valid_add_flags = ctrl_ctx->add_flags >> 2; - valid_drop_flags = ctrl_ctx->drop_flags >> 2; + valid_add_flags = le32_to_cpu(ctrl_ctx->add_flags) >> 2; + valid_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags) >> 2; return hweight32(valid_drop_flags) - hweight32(valid_add_flags & valid_drop_flags); @@ -1928,20 +1968,22 @@ static unsigned int xhci_count_num_dropped_endpoints(struct xhci_hcd *xhci, * Must be called with xhci->lock held. */ static int xhci_reserve_host_resources(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) + struct xhci_input_control_ctx *ctrl_ctx) { u32 added_eps; - added_eps = xhci_count_num_new_endpoints(xhci, in_ctx); + added_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx); if (xhci->num_active_eps + added_eps > xhci->limit_active_eps) { - xhci_dbg(xhci, "Not enough ep ctxs: " - "%u active, need to add %u, limit is %u.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Not enough ep ctxs: " + "%u active, need to add %u, limit is %u.", xhci->num_active_eps, added_eps, xhci->limit_active_eps); return -ENOMEM; } xhci->num_active_eps += added_eps; - xhci_dbg(xhci, "Adding %u ep ctxs, %u now active.\n", added_eps, + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Adding %u ep ctxs, %u now active.", added_eps, xhci->num_active_eps); return 0; } @@ -1953,13 +1995,14 @@ static int xhci_reserve_host_resources(struct xhci_hcd *xhci, * Must be called with xhci->lock held. */ static void xhci_free_host_resources(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) + struct xhci_input_control_ctx *ctrl_ctx) { u32 num_failed_eps; - num_failed_eps = xhci_count_num_new_endpoints(xhci, in_ctx); + num_failed_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx); xhci->num_active_eps -= num_failed_eps; - xhci_dbg(xhci, "Removing %u failed ep ctxs, %u now active.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Removing %u failed ep ctxs, %u now active.", num_failed_eps, xhci->num_active_eps); } @@ -1971,14 +2014,15 @@ static void xhci_free_host_resources(struct xhci_hcd *xhci, * Must be called with xhci->lock held. */ static void xhci_finish_resource_reservation(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) + struct xhci_input_control_ctx *ctrl_ctx) { u32 num_dropped_eps; - num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, in_ctx); + num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, ctrl_ctx); xhci->num_active_eps -= num_dropped_eps; if (num_dropped_eps) - xhci_dbg(xhci, "Removing %u dropped ep ctxs, %u now active.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Removing %u dropped ep ctxs, %u now active.", num_dropped_eps, xhci->num_active_eps); } @@ -2139,18 +2183,21 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci, * that the HS bus has enough bandwidth if we are activing a new TT. */ if (virt_dev->tt_info) { - xhci_dbg(xhci, "Recalculating BW for rootport %u\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Recalculating BW for rootport %u", virt_dev->real_port); if (xhci_check_tt_bw_table(xhci, virt_dev, old_active_eps)) { xhci_warn(xhci, "Not enough bandwidth on HS bus for " "newly activated TT.\n"); return -ENOMEM; } - xhci_dbg(xhci, "Recalculating BW for TT slot %u port %u\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Recalculating BW for TT slot %u port %u", virt_dev->tt_info->slot_id, virt_dev->tt_info->ttport); } else { - xhci_dbg(xhci, "Recalculating BW for rootport %u\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Recalculating BW for rootport %u", virt_dev->real_port); } @@ -2258,8 +2305,9 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci, xhci->rh_bw[port_index].num_active_tts; } - xhci_dbg(xhci, "Final bandwidth: %u, Limit: %u, Reserved: %u, " - "Available: %u " "percent\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Final bandwidth: %u, Limit: %u, Reserved: %u, " + "Available: %u " "percent", bw_used, max_bandwidth, bw_reserved, (max_bandwidth - bw_used - bw_reserved) * 100 / max_bandwidth); @@ -2470,6 +2518,11 @@ static int xhci_reserve_bandwidth(struct xhci_hcd *xhci, old_active_eps = virt_dev->tt_info->active_eps; ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return -ENOMEM; + } for (i = 0; i < 31; i++) { if (!EP_IS_ADDED(ctrl_ctx, i) && !EP_IS_DROPPED(ctrl_ctx, i)) @@ -2551,24 +2604,26 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, bool ctx_change, bool must_succeed) { int ret; - int timeleft; unsigned long flags; - struct xhci_container_ctx *in_ctx; - struct completion *cmd_completion; - u32 *cmd_status; + struct xhci_input_control_ctx *ctrl_ctx; struct xhci_virt_device *virt_dev; - union xhci_trb *cmd_trb; + + if (!command) + return -EINVAL; spin_lock_irqsave(&xhci->lock, flags); virt_dev = xhci->devs[udev->slot_id]; - if (command) - in_ctx = command->in_ctx; - else - in_ctx = virt_dev->in_ctx; + ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); + if (!ctrl_ctx) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return -ENOMEM; + } if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) && - xhci_reserve_host_resources(xhci, in_ctx)) { + xhci_reserve_host_resources(xhci, ctrl_ctx)) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_warn(xhci, "Not enough host resources, " "active endpoint contexts = %u\n", @@ -2576,73 +2631,42 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, return -ENOMEM; } if ((xhci->quirks & XHCI_SW_BW_CHECKING) && - xhci_reserve_bandwidth(xhci, virt_dev, in_ctx)) { + xhci_reserve_bandwidth(xhci, virt_dev, command->in_ctx)) { if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) - xhci_free_host_resources(xhci, in_ctx); + xhci_free_host_resources(xhci, ctrl_ctx); spin_unlock_irqrestore(&xhci->lock, flags); xhci_warn(xhci, "Not enough bandwidth\n"); return -ENOMEM; } - if (command) { - cmd_completion = command->completion; - cmd_status = &command->status; - command->command_trb = xhci->cmd_ring->enqueue; - - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(command->command_trb->link.control)) - command->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; - - list_add_tail(&command->cmd_list, &virt_dev->cmd_list); - } else { - cmd_completion = &virt_dev->cmd_completion; - cmd_status = &virt_dev->cmd_status; - } - init_completion(cmd_completion); - - cmd_trb = xhci->cmd_ring->dequeue; if (!ctx_change) - ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, + ret = xhci_queue_configure_endpoint(xhci, command, + command->in_ctx->dma, udev->slot_id, must_succeed); else - ret = xhci_queue_evaluate_context(xhci, in_ctx->dma, + ret = xhci_queue_evaluate_context(xhci, command, + command->in_ctx->dma, udev->slot_id, must_succeed); if (ret < 0) { - if (command) - list_del(&command->cmd_list); if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) - xhci_free_host_resources(xhci, in_ctx); + xhci_free_host_resources(xhci, ctrl_ctx); spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "FIXME allocate a new ring segment\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "FIXME allocate a new ring segment"); return -ENOMEM; } xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); /* Wait for the configure endpoint command to complete */ - timeleft = wait_for_completion_interruptible_timeout( - cmd_completion, - XHCI_CMD_DEFAULT_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for %s command\n", - timeleft == 0 ? "Timeout" : "Signal", - ctx_change == 0 ? - "configure endpoint" : - "evaluate context"); - /* cancel the configure endpoint command */ - ret = xhci_cancel_cmd(xhci, command, cmd_trb); - if (ret < 0) - return ret; - return -ETIME; - } + wait_for_completion(command->completion); if (!ctx_change) - ret = xhci_configure_endpoint_result(xhci, udev, cmd_status); + ret = xhci_configure_endpoint_result(xhci, udev, + &command->status); else - ret = xhci_evaluate_context_result(xhci, udev, cmd_status); + ret = xhci_evaluate_context_result(xhci, udev, + &command->status); if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) { spin_lock_irqsave(&xhci->lock, flags); @@ -2650,14 +2674,28 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, * Otherwise, clean up the estimate to include dropped eps. */ if (ret) - xhci_free_host_resources(xhci, in_ctx); + xhci_free_host_resources(xhci, ctrl_ctx); else - xhci_finish_resource_reservation(xhci, in_ctx); + xhci_finish_resource_reservation(xhci, ctrl_ctx); spin_unlock_irqrestore(&xhci->lock, flags); } return ret; } +static void xhci_check_bw_drop_ep_streams(struct xhci_hcd *xhci, + struct xhci_virt_device *vdev, int i) +{ + struct xhci_virt_ep *ep = &vdev->eps[i]; + + if (ep->ep_state & EP_HAS_STREAMS) { + xhci_warn(xhci, "WARN: endpoint 0x%02x has streams on set_interface, freeing streams.\n", + xhci_get_endpoint_address(i)); + xhci_free_stream_info(xhci, ep->stream_info); + ep->stream_info = NULL; + ep->ep_state &= ~EP_HAS_STREAMS; + } +} + /* Called after one or more calls to xhci_add_endpoint() or * xhci_drop_endpoint(). If this call fails, the USB core is expected * to call xhci_reset_bandwidth(). @@ -2676,6 +2714,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_virt_device *virt_dev; struct xhci_input_control_ctx *ctrl_ctx; struct xhci_slot_ctx *slot_ctx; + struct xhci_command *command; ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); if (ret <= 0) @@ -2687,28 +2726,40 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); virt_dev = xhci->devs[udev->slot_id]; + command = xhci_alloc_command(xhci, false, true, GFP_KERNEL); + if (!command) + return -ENOMEM; + + command->in_ctx = virt_dev->in_ctx; + /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + ret = -ENOMEM; + goto command_cleanup; + } ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG); ctrl_ctx->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG)); /* Don't issue the command if there's no endpoints to update. */ if (ctrl_ctx->add_flags == cpu_to_le32(SLOT_FLAG) && - ctrl_ctx->drop_flags == 0) - return 0; - + ctrl_ctx->drop_flags == 0) { + ret = 0; + goto command_cleanup; + } xhci_dbg(xhci, "New Input Control Context:\n"); slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); xhci_dbg_ctx(xhci, virt_dev->in_ctx, LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info))); - ret = xhci_configure_endpoint(xhci, udev, NULL, + ret = xhci_configure_endpoint(xhci, udev, command, false, false); - if (ret) { + if (ret) /* Callee should call reset_bandwidth() */ - return ret; - } + goto command_cleanup; xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); xhci_dbg_ctx(xhci, virt_dev->out_ctx, @@ -2717,8 +2768,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) /* Free any rings that were dropped, but not changed. */ for (i = 1; i < 31; ++i) { if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) && - !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) + !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) { xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); + xhci_check_bw_drop_ep_streams(xhci, virt_dev, i); + } } xhci_zero_in_ctx(xhci, virt_dev); /* @@ -2734,9 +2787,13 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) if (virt_dev->eps[i].ring) { xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); } + xhci_check_bw_drop_ep_streams(xhci, virt_dev, i); virt_dev->eps[i].ring = virt_dev->eps[i].new_ring; virt_dev->eps[i].new_ring = NULL; } +command_cleanup: + kfree(command->completion); + kfree(command); return ret; } @@ -2767,10 +2824,9 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci, struct xhci_container_ctx *in_ctx, struct xhci_container_ctx *out_ctx, + struct xhci_input_control_ctx *ctrl_ctx, u32 add_flags, u32 drop_flags) { - struct xhci_input_control_ctx *ctrl_ctx; - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ctrl_ctx->add_flags = cpu_to_le32(add_flags); ctrl_ctx->drop_flags = cpu_to_le32(drop_flags); xhci_slot_copy(xhci, in_ctx, out_ctx); @@ -2784,14 +2840,22 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state) { + struct xhci_input_control_ctx *ctrl_ctx; struct xhci_container_ctx *in_ctx; struct xhci_ep_ctx *ep_ctx; u32 added_ctxs; dma_addr_t addr; + in_ctx = xhci->devs[slot_id]->in_ctx; + ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return; + } + xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, xhci->devs[slot_id]->out_ctx, ep_index); - in_ctx = xhci->devs[slot_id]->in_ctx; ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); addr = xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr); @@ -2807,7 +2871,8 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, added_ctxs = xhci_get_endpoint_flag_from_index(ep_index); xhci_setup_input_ctx_for_config_ep(xhci, xhci->devs[slot_id]->in_ctx, - xhci->devs[slot_id]->out_ctx, added_ctxs, added_ctxs); + xhci->devs[slot_id]->out_ctx, ctrl_ctx, + added_ctxs, added_ctxs); } void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, @@ -2816,7 +2881,8 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, struct xhci_dequeue_state deq_state; struct xhci_virt_ep *ep; - xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, + "Cleaning up stalled endpoint ring"); ep = &xhci->devs[udev->slot_id]->eps[ep_index]; /* We need to move the HW's dequeue pointer past this TD, * or it will attempt to resend it on the next doorbell ring. @@ -2829,8 +2895,14 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, * issue a configure endpoint command later. */ if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) { - xhci_dbg(xhci, "Queueing new dequeue state\n"); - xhci_queue_new_dequeue_state(xhci, udev->slot_id, + struct xhci_command *command; + /* Can't sleep if we're called from cleanup_halted_endpoint() */ + command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + if (!command) + return; + xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, + "Queueing new dequeue state"); + xhci_queue_new_dequeue_state(xhci, command, udev->slot_id, ep_index, ep->stopped_stream, &deq_state); } else { /* Better hope no one uses the input context between now and the @@ -2838,8 +2910,9 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, * XXX: No idea how this hardware will react when stream rings * are enabled. */ - xhci_dbg(xhci, "Setting up input context for " - "configure endpoint command\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Setting up input context for " + "configure endpoint command"); xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id, ep_index, &deq_state); } @@ -2860,6 +2933,7 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, unsigned long flags; int ret; struct xhci_virt_ep *virt_ep; + struct xhci_command *command; xhci = hcd_to_xhci(hcd); udev = (struct usb_device *) ep->hcpriv; @@ -2871,18 +2945,25 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, ep_index = xhci_get_endpoint_index(&ep->desc); virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index]; if (!virt_ep->stopped_td) { - xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n", - ep->desc.bEndpointAddress); + xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, + "Endpoint 0x%x not halted, refusing to reset.", + ep->desc.bEndpointAddress); return; } if (usb_endpoint_xfer_control(&ep->desc)) { - xhci_dbg(xhci, "Control endpoint stall already handled.\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, + "Control endpoint stall already handled."); return; } - xhci_dbg(xhci, "Queueing reset endpoint command\n"); + command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + if (!command) + return; + + xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, + "Queueing reset endpoint command"); spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); + ret = xhci_queue_reset_ep(xhci, command, udev->slot_id, ep_index); /* * Can't change the ring dequeue pointer until it's transitioned to the * stopped state, which is only upon a successful reset endpoint @@ -2894,7 +2975,6 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, xhci_ring_cmd_db(xhci); } virt_ep->stopped_td = NULL; - virt_ep->stopped_trb = NULL; virt_ep->stopped_stream = 0; spin_unlock_irqrestore(&xhci->lock, flags); @@ -2915,7 +2995,7 @@ static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__); if (ret <= 0) return -EINVAL; - if (ep->ss_ep_comp.bmAttributes == 0) { + if (usb_ss_max_streams(&ep->ss_ep_comp) == 0) { xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion" " descriptor for ep 0x%x does not support streams\n", ep->desc.bEndpointAddress); @@ -3020,8 +3100,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, /* Are streams already being freed for the endpoint? */ if (ep_state & EP_GETTING_NO_STREAMS) { xhci_warn(xhci, "WARN Can't disable streams for " - "endpoint 0x%x\n, " - "streams are being disabled already.", + "endpoint 0x%x, " + "streams are being disabled already\n", eps[i]->desc.bEndpointAddress); return 0; } @@ -3029,8 +3109,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, if (!(ep_state & EP_HAS_STREAMS) && !(ep_state & EP_GETTING_STREAMS)) { xhci_warn(xhci, "WARN Can't disable streams for " - "endpoint 0x%x\n, " - "streams are already disabled!", + "endpoint 0x%x, " + "streams are already disabled!\n", eps[i]->desc.bEndpointAddress); xhci_warn(xhci, "WARN xhci_free_streams() called " "with non-streams endpoint\n"); @@ -3065,6 +3145,7 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, struct xhci_hcd *xhci; struct xhci_virt_device *vdev; struct xhci_command *config_cmd; + struct xhci_input_control_ctx *ctrl_ctx; unsigned int ep_index; unsigned int num_stream_ctxs; unsigned long flags; @@ -3081,11 +3162,24 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, xhci_dbg(xhci, "Driver wants %u stream IDs (including stream 0).\n", num_streams); + /* MaxPSASize value 0 (2 streams) means streams are not supported */ + if (HCC_MAX_PSA(xhci->hcc_params) < 4) { + xhci_dbg(xhci, "xHCI controller does not support streams.\n"); + return -ENOSYS; + } + config_cmd = xhci_alloc_command(xhci, true, true, mem_flags); if (!config_cmd) { xhci_dbg(xhci, "Could not allocate xHCI command structure.\n"); return -ENOMEM; } + ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + xhci_free_command(xhci, config_cmd); + return -ENOMEM; + } /* Check to make sure all endpoints are not already configured for * streams. While we're at it, find the maximum number of streams that @@ -3152,7 +3246,8 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, * and add the updated copy from the input context. */ xhci_setup_input_ctx_for_config_ep(xhci, config_cmd->in_ctx, - vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask); + vdev->out_ctx, ctrl_ctx, + changed_ep_bitmask, changed_ep_bitmask); /* Issue and wait for the configure endpoint command */ ret = xhci_configure_endpoint(xhci, udev, config_cmd, @@ -3210,6 +3305,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, struct xhci_hcd *xhci; struct xhci_virt_device *vdev; struct xhci_command *command; + struct xhci_input_control_ctx *ctrl_ctx; unsigned int ep_index; unsigned long flags; u32 changed_ep_bitmask; @@ -3232,6 +3328,14 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, */ ep_index = xhci_get_endpoint_index(&eps[0]->desc); command = vdev->eps[ep_index].stream_info->free_streams_command; + ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); + if (!ctrl_ctx) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return -EINVAL; + } + for (i = 0; i < num_eps; i++) { struct xhci_ep_ctx *ep_ctx; @@ -3246,7 +3350,8 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, &vdev->eps[ep_index]); } xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx, - vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask); + vdev->out_ctx, ctrl_ctx, + changed_ep_bitmask, changed_ep_bitmask); spin_unlock_irqrestore(&xhci->lock, flags); /* Issue and wait for the configure endpoint command, @@ -3299,8 +3404,9 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci, } xhci->num_active_eps -= num_dropped_eps; if (num_dropped_eps) - xhci_dbg(xhci, "Dropped %u ep ctxs, flags = 0x%x, " - "%u now active.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Dropped %u ep ctxs, flags = 0x%x, " + "%u now active.", num_dropped_eps, drop_flags, xhci->num_active_eps); } @@ -3331,7 +3437,6 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) unsigned int slot_id; struct xhci_virt_device *virt_dev; struct xhci_command *reset_device_cmd; - int timeleft; int last_freed_endpoint; struct xhci_slot_ctx *slot_ctx; int old_active_eps = 0; @@ -3388,20 +3493,10 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Attempt to submit the Reset Device command to the command ring */ spin_lock_irqsave(&xhci->lock, flags); - reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control)) - reset_device_cmd->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; - - list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); - ret = xhci_queue_reset_device(xhci, slot_id); + ret = xhci_queue_reset_device(xhci, reset_device_cmd, slot_id); if (ret) { xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); - list_del(&reset_device_cmd->cmd_list); spin_unlock_irqrestore(&xhci->lock, flags); goto command_cleanup; } @@ -3409,22 +3504,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) spin_unlock_irqrestore(&xhci->lock, flags); /* Wait for the Reset Device command to finish */ - timeleft = wait_for_completion_interruptible_timeout( - reset_device_cmd->completion, - USB_CTRL_SET_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for reset device command\n", - timeleft == 0 ? "Timeout" : "Signal"); - spin_lock_irqsave(&xhci->lock, flags); - /* The timeout might have raced with the event ring handler, so - * only delete from the list if the item isn't poisoned. - */ - if (reset_device_cmd->cmd_list.next != LIST_POISON1) - list_del(&reset_device_cmd->cmd_list); - spin_unlock_irqrestore(&xhci->lock, flags); - ret = -ETIME; - goto command_cleanup; - } + wait_for_completion(reset_device_cmd->completion); /* The Reset Device command can't fail, according to the 0.95/0.96 spec, * unless we tried to reset a slot ID that wasn't enabled, @@ -3432,12 +3512,17 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) */ ret = reset_device_cmd->status; switch (ret) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout waiting for reset device command\n"); + ret = -ETIME; + goto command_cleanup; case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */ case COMP_CTX_STATE: /* 0.96 completion code for same thing */ - xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n", + xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n", slot_id, xhci_get_slot_state(xhci, virt_dev->out_ctx)); - xhci_info(xhci, "Not freeing device rings.\n"); + xhci_dbg(xhci, "Not freeing device rings.\n"); /* Don't treat this as an error. May change my mind later. */ ret = 0; goto command_cleanup; @@ -3467,6 +3552,8 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_virt_ep *ep = &virt_dev->eps[i]; if (ep->ep_state & EP_HAS_STREAMS) { + xhci_warn(xhci, "WARN: endpoint 0x%02x has streams on device reset, freeing streams.\n", + xhci_get_endpoint_address(i)); xhci_free_stream_info(xhci, ep->stream_info); ep->stream_info = NULL; ep->ep_state &= ~EP_HAS_STREAMS; @@ -3509,13 +3596,30 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) unsigned long flags; u32 state; int i, ret; + struct xhci_command *command; + + command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); + if (!command) + return; + +#ifndef CONFIG_USB_DEFAULT_PERSIST + /* + * We called pm_runtime_get_noresume when the device was attached. + * Decrement the counter here to allow controller to runtime suspend + * if no devices remain. + */ + if (xhci->quirks & XHCI_RESET_ON_RESUME) + pm_runtime_put_noidle(hcd->self.controller); +#endif ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); /* If the host is halted due to driver unload, we still need to free the * device. */ - if (ret <= 0 && ret != -ENODEV) + if (ret <= 0 && ret != -ENODEV) { + kfree(command); return; + } virt_dev = xhci->devs[udev->slot_id]; @@ -3525,28 +3629,26 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); } - if (udev->usb2_hw_lpm_enabled) { - xhci_set_usb2_hardware_lpm(hcd, udev, 0); - udev->usb2_hw_lpm_enabled = 0; - } - spin_lock_irqsave(&xhci->lock, flags); /* Don't disable the slot if the host controller is dead. */ - state = xhci_readl(xhci, &xhci->op_regs->status); + state = readl(&xhci->op_regs->status); if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || (xhci->xhc_state & XHCI_STATE_HALTED)) { xhci_free_virt_device(xhci, udev->slot_id); spin_unlock_irqrestore(&xhci->lock, flags); + kfree(command); return; } - if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { + if (xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, + udev->slot_id)) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); return; } xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); + /* * Event command completion handler will free any data structures * associated with the slot. XXX Can free sleep? @@ -3562,13 +3664,15 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci) { if (xhci->num_active_eps + 1 > xhci->limit_active_eps) { - xhci_dbg(xhci, "Not enough ep ctxs: " - "%u active, need to add 1, limit is %u.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Not enough ep ctxs: " + "%u active, need to add 1, limit is %u.", xhci->num_active_eps, xhci->limit_active_eps); return -ENOMEM; } xhci->num_active_eps += 1; - xhci_dbg(xhci, "Adding 1 ep ctx, %u now active.\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Adding 1 ep ctx, %u now active.", xhci->num_active_eps); return 0; } @@ -3582,33 +3686,33 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); unsigned long flags; - int timeleft; int ret; - union xhci_trb *cmd_trb; + struct xhci_command *command; + + command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); + if (!command) + return 0; spin_lock_irqsave(&xhci->lock, flags); - cmd_trb = xhci->cmd_ring->dequeue; - ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); + command->completion = &xhci->addr_dev; + ret = xhci_queue_slot_control(xhci, command, TRB_ENABLE_SLOT, 0); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); + kfree(command); return 0; } xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); - /* XXX: how much time for xHC slot assignment? */ - timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - XHCI_CMD_DEFAULT_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for a slot\n", - timeleft == 0 ? "Timeout" : "Signal"); - /* cancel the enable slot request */ - return xhci_cancel_cmd(xhci, NULL, cmd_trb); - } + wait_for_completion(command->completion); - if (!xhci->slot_id) { + if (!xhci->slot_id || command->status != COMP_SUCCESS) { xhci_err(xhci, "Error while assigning device slot ID\n"); + xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n", + HCS_MAX_SLOTS( + readl(&xhci->cap_regs->hcs_params1))); + kfree(command); return 0; } @@ -3633,6 +3737,18 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) goto disable_slot; } udev->slot_id = xhci->slot_id; + +#ifndef CONFIG_USB_DEFAULT_PERSIST + /* + * If resetting upon resume, we can't put the controller into runtime + * suspend if there is a device attached. + */ + if (xhci->quirks & XHCI_RESET_ON_RESUME) + pm_runtime_get_noresume(hcd->self.controller); +#endif + + + kfree(command); /* Is this a LS or FS device under a HS hub? */ /* Hub or peripherial? */ return 1; @@ -3640,35 +3756,37 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) disable_slot: /* Disable slot, if we can do it without mem alloc */ spin_lock_irqsave(&xhci->lock, flags); - if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) + command->completion = NULL; + command->status = 0; + if (!xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, + udev->slot_id)) xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); return 0; } /* - * Issue an Address Device command (which will issue a SetAddress request to - * the device). + * Issue an Address Device command and optionally send a corresponding + * SetAddress request to the device. * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so * we should only issue and wait on one address command at the same time. - * - * We add one to the device address issued by the hardware because the USB core - * uses address 1 for the root hubs (even though they're not really devices). */ -int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, + enum xhci_setup_dev setup) { + const char *act = setup == SETUP_CONTEXT_ONLY ? "context" : "address"; unsigned long flags; - int timeleft; struct xhci_virt_device *virt_dev; int ret = 0; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; u64 temp_64; - union xhci_trb *cmd_trb; + struct xhci_command *command; if (!udev->slot_id) { - xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); + xhci_dbg_trace(xhci, trace_xhci_dbg_address, + "Bad Slot ID %d", udev->slot_id); return -EINVAL; } @@ -3685,7 +3803,21 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) return -EINVAL; } + command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); + if (!command) + return -ENOMEM; + + command->in_ctx = virt_dev->in_ctx; + command->completion = &xhci->addr_dev; + slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + kfree(command); + return -EINVAL; + } /* * If this is the first Set Address since device plug-in or * virt_device realloaction after a resume with an xHCI power loss, @@ -3696,83 +3828,89 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* Otherwise, update the control endpoint ring enqueue pointer. */ else xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); ctrl_ctx->drop_flags = 0; xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); + trace_xhci_address_ctx(xhci, virt_dev->in_ctx, + le32_to_cpu(slot_ctx->dev_info) >> 27); spin_lock_irqsave(&xhci->lock, flags); - cmd_trb = xhci->cmd_ring->dequeue; - ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, - udev->slot_id); + ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma, + udev->slot_id, setup); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_address, + "FIXME: allocate a command ring segment"); + kfree(command); return ret; } xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ - timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - XHCI_CMD_DEFAULT_TIMEOUT); + wait_for_completion(command->completion); + /* FIXME: From section 4.3.4: "Software shall be responsible for timing * the SetAddress() "recovery interval" required by USB and aborting the * command on a timeout. */ - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for address device command\n", - timeleft == 0 ? "Timeout" : "Signal"); - /* cancel the address device command */ - ret = xhci_cancel_cmd(xhci, NULL, cmd_trb); - if (ret < 0) - return ret; - return -ETIME; - } - - switch (virt_dev->cmd_status) { + switch (command->status) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout while waiting for setup device command\n"); + ret = -ETIME; + break; case COMP_CTX_STATE: case COMP_EBADSLT: - xhci_err(xhci, "Setup ERROR: address device command for slot %d.\n", - udev->slot_id); + xhci_err(xhci, "Setup ERROR: setup %s command for slot %d.\n", + act, udev->slot_id); ret = -EINVAL; break; case COMP_TX_ERR: - dev_warn(&udev->dev, "Device not responding to set address.\n"); + dev_warn(&udev->dev, "Device not responding to setup %s.\n", act); ret = -EPROTO; break; case COMP_DEV_ERR: - dev_warn(&udev->dev, "ERROR: Incompatible device for address " - "device command.\n"); + dev_warn(&udev->dev, + "ERROR: Incompatible device for setup %s command\n", act); ret = -ENODEV; break; case COMP_SUCCESS: - xhci_dbg(xhci, "Successful Address Device command\n"); + xhci_dbg_trace(xhci, trace_xhci_dbg_address, + "Successful setup %s command", act); break; default: - xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", virt_dev->cmd_status); + xhci_err(xhci, + "ERROR: unexpected setup %s command completion code 0x%x.\n", + act, command->status); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); + trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1); ret = -EINVAL; break; } if (ret) { + kfree(command); return ret; } temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); - xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64); - xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n", - udev->slot_id, - &xhci->dcbaa->dev_context_ptrs[udev->slot_id], - (unsigned long long) - le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id])); - xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", + xhci_dbg_trace(xhci, trace_xhci_dbg_address, + "Op regs DCBAA ptr = %#016llx", temp_64); + xhci_dbg_trace(xhci, trace_xhci_dbg_address, + "Slot ID %d dcbaa entry @%p = %#016llx", + udev->slot_id, + &xhci->dcbaa->dev_context_ptrs[udev->slot_id], + (unsigned long long) + le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id])); + xhci_dbg_trace(xhci, trace_xhci_dbg_address, + "Output Context DMA address = %#08llx", (unsigned long long)virt_dev->out_ctx->dma); xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); + trace_xhci_address_ctx(xhci, virt_dev->in_ctx, + le32_to_cpu(slot_ctx->dev_info) >> 27); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); /* @@ -3780,19 +3918,29 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) * address given back to us by the HC. */ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); - /* Use kernel assigned address for devices; store xHC assigned - * address locally. */ - virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) - + 1; + trace_xhci_address_ctx(xhci, virt_dev->out_ctx, + le32_to_cpu(slot_ctx->dev_info) >> 27); /* Zero the input context control for later use */ ctrl_ctx->add_flags = 0; ctrl_ctx->drop_flags = 0; - xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address); - + xhci_dbg_trace(xhci, trace_xhci_dbg_address, + "Internal device address = %d", + le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK); + kfree(command); return 0; } +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS); +} + +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY); +} + /* * Transfer the port index into real index in the HW port status * registers. Caculate offset between the port's PORTSC register @@ -3815,6 +3963,64 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1) return raw_port; } +/* + * Issue an Evaluate Context command to change the Maximum Exit Latency in the + * slot context. If that succeeds, store the new MEL in the xhci_virt_device. + */ +static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, + struct usb_device *udev, u16 max_exit_latency) +{ + struct xhci_virt_device *virt_dev; + struct xhci_command *command; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_slot_ctx *slot_ctx; + unsigned long flags; + int ret; + + spin_lock_irqsave(&xhci->lock, flags); + if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) { + spin_unlock_irqrestore(&xhci->lock, flags); + return 0; + } + + /* Attempt to issue an Evaluate Context command to change the MEL. */ + virt_dev = xhci->devs[udev->slot_id]; + command = xhci->lpm_command; + ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); + if (!ctrl_ctx) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + return -ENOMEM; + } + + xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx); + spin_unlock_irqrestore(&xhci->lock, flags); + + ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); + slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx); + slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT)); + slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency); + + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Set up evaluate context for LPM MEL change."); + xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, command->in_ctx, 0); + + /* Issue and wait for the evaluate context command. */ + ret = xhci_configure_endpoint(xhci, udev, command, + true, true); + xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0); + + if (!ret) { + spin_lock_irqsave(&xhci->lock, flags); + virt_dev->current_mel = max_exit_latency; + spin_unlock_irqrestore(&xhci->lock, flags); + } + return ret; +} + #ifdef CONFIG_PM_RUNTIME /* BESL to HIRD Encoding array for USB2 LPM */ @@ -3856,131 +4062,26 @@ static int xhci_calculate_hird_besl(struct xhci_hcd *xhci, return besl; } -static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, - struct usb_device *udev) +/* Calculate BESLD, L1 timeout and HIRDM for USB2 PORTHLPMC */ +static int xhci_calculate_usb2_hw_lpm_params(struct usb_device *udev) { - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct dev_info *dev_info; - __le32 __iomem **port_array; - __le32 __iomem *addr, *pm_addr; - u32 temp, dev_id; - unsigned int port_num; - unsigned long flags; - int hird; - int ret; - - if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || - !udev->lpm_capable) - return -EINVAL; - - /* we only support lpm for non-hub device connected to root hub yet */ - if (!udev->parent || udev->parent->parent || - udev->descriptor.bDeviceClass == USB_CLASS_HUB) - return -EINVAL; - - spin_lock_irqsave(&xhci->lock, flags); - - /* Look for devices in lpm_failed_devs list */ - dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 | - le16_to_cpu(udev->descriptor.idProduct); - list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) { - if (dev_info->dev_id == dev_id) { - ret = -EINVAL; - goto finish; - } - } - - port_array = xhci->usb2_ports; - port_num = udev->portnum - 1; - - if (port_num > HCS_MAX_PORTS(xhci->hcs_params1)) { - xhci_dbg(xhci, "invalid port number %d\n", udev->portnum); - ret = -EINVAL; - goto finish; - } - - /* - * Test USB 2.0 software LPM. - * FIXME: some xHCI 1.0 hosts may implement a new register to set up - * hardware-controlled USB 2.0 LPM. See section 5.4.11 and 4.23.5.1.1.1 - * in the June 2011 errata release. - */ - xhci_dbg(xhci, "test port %d software LPM\n", port_num); - /* - * Set L1 Device Slot and HIRD/BESL. - * Check device's USB 2.0 extension descriptor to determine whether - * HIRD or BESL shoule be used. See USB2.0 LPM errata. - */ - pm_addr = port_array[port_num] + 1; - hird = xhci_calculate_hird_besl(xhci, udev); - temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); - xhci_writel(xhci, temp, pm_addr); - - /* Set port link state to U2(L1) */ - addr = port_array[port_num]; - xhci_set_link_state(xhci, port_array, port_num, XDEV_U2); - - /* wait for ACK */ - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(10); - spin_lock_irqsave(&xhci->lock, flags); - - /* Check L1 Status */ - ret = xhci_handshake(xhci, pm_addr, - PORT_L1S_MASK, PORT_L1S_SUCCESS, 125); - if (ret != -ETIMEDOUT) { - /* enter L1 successfully */ - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, "port %d entered L1 state, port status 0x%x\n", - port_num, temp); - ret = 0; - } else { - temp = xhci_readl(xhci, pm_addr); - xhci_dbg(xhci, "port %d software lpm failed, L1 status %d\n", - port_num, temp & PORT_L1S_MASK); - ret = -EINVAL; - } - - /* Resume the port */ - xhci_set_link_state(xhci, port_array, port_num, XDEV_U0); - - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(10); - spin_lock_irqsave(&xhci->lock, flags); + u32 field; + int l1; + int besld = 0; + int hirdm = 0; - /* Clear PLC */ - xhci_test_and_clear_bit(xhci, port_array, port_num, PORT_PLC); + field = le32_to_cpu(udev->bos->ext_cap->bmAttributes); - /* Check PORTSC to make sure the device is in the right state */ - if (!ret) { - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, "resumed port %d status 0x%x\n", port_num, temp); - if (!(temp & PORT_CONNECT) || !(temp & PORT_PE) || - (temp & PORT_PLS_MASK) != XDEV_U0) { - xhci_dbg(xhci, "port L1 resume fail\n"); - ret = -EINVAL; - } - } + /* xHCI l1 is set in steps of 256us, xHCI 1.0 section 5.4.11.2 */ + l1 = udev->l1_params.timeout / 256; - if (ret) { - /* Insert dev to lpm_failed_devs list */ - xhci_warn(xhci, "device LPM test failed, may disconnect and " - "re-enumerate\n"); - dev_info = kzalloc(sizeof(struct dev_info), GFP_ATOMIC); - if (!dev_info) { - ret = -ENOMEM; - goto finish; - } - dev_info->dev_id = dev_id; - INIT_LIST_HEAD(&dev_info->list); - list_add(&dev_info->list, &xhci->lpm_failed_devs); - } else { - xhci_ring_device(xhci, udev->slot_id); + /* device has preferred BESLD */ + if (field & USB_BESL_DEEP_VALID) { + besld = USB_GET_BESL_DEEP(field); + hirdm = 1; } -finish: - spin_unlock_irqrestore(&xhci->lock, flags); - return ret; + return PORT_BESLD(besld) | PORT_L1_TIMEOUT(l1) | PORT_HIRDM(hirdm); } int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, @@ -3988,11 +4089,12 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, { struct xhci_hcd *xhci = hcd_to_xhci(hcd); __le32 __iomem **port_array; - __le32 __iomem *pm_addr; - u32 temp; + __le32 __iomem *pm_addr, *hlpm_addr; + u32 pm_val, hlpm_val, field; unsigned int port_num; unsigned long flags; - int hird; + int hird, exit_latency; + int ret; if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support || !udev->lpm_capable) @@ -4009,44 +4111,126 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, port_array = xhci->usb2_ports; port_num = udev->portnum - 1; - pm_addr = port_array[port_num] + 1; - temp = xhci_readl(xhci, pm_addr); + pm_addr = port_array[port_num] + PORTPMSC; + pm_val = readl(pm_addr); + hlpm_addr = port_array[port_num] + PORTHLPMC; + field = le32_to_cpu(udev->bos->ext_cap->bmAttributes); xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n", - enable ? "enable" : "disable", port_num); - - hird = xhci_calculate_hird_besl(xhci, udev); + enable ? "enable" : "disable", port_num + 1); if (enable) { - temp &= ~PORT_HIRD_MASK; - temp |= PORT_HIRD(hird) | PORT_RWE; - xhci_writel(xhci, temp, pm_addr); - temp = xhci_readl(xhci, pm_addr); - temp |= PORT_HLE; - xhci_writel(xhci, temp, pm_addr); + /* Host supports BESL timeout instead of HIRD */ + if (udev->usb2_hw_lpm_besl_capable) { + /* if device doesn't have a preferred BESL value use a + * default one which works with mixed HIRD and BESL + * systems. See XHCI_DEFAULT_BESL definition in xhci.h + */ + if ((field & USB_BESL_SUPPORT) && + (field & USB_BESL_BASELINE_VALID)) + hird = USB_GET_BESL_BASELINE(field); + else + hird = udev->l1_params.besl; + + exit_latency = xhci_besl_encoding[hird]; + spin_unlock_irqrestore(&xhci->lock, flags); + + /* USB 3.0 code dedicate one xhci->lpm_command->in_ctx + * input context for link powermanagement evaluate + * context commands. It is protected by hcd->bandwidth + * mutex and is shared by all devices. We need to set + * the max ext latency in USB 2 BESL LPM as well, so + * use the same mutex and xhci_change_max_exit_latency() + */ + mutex_lock(hcd->bandwidth_mutex); + ret = xhci_change_max_exit_latency(xhci, udev, + exit_latency); + mutex_unlock(hcd->bandwidth_mutex); + + if (ret < 0) + return ret; + spin_lock_irqsave(&xhci->lock, flags); + + hlpm_val = xhci_calculate_usb2_hw_lpm_params(udev); + writel(hlpm_val, hlpm_addr); + /* flush write */ + readl(hlpm_addr); + } else { + hird = xhci_calculate_hird_besl(xhci, udev); + } + + pm_val &= ~PORT_HIRD_MASK; + pm_val |= PORT_HIRD(hird) | PORT_RWE | PORT_L1DS(udev->slot_id); + writel(pm_val, pm_addr); + pm_val = readl(pm_addr); + pm_val |= PORT_HLE; + writel(pm_val, pm_addr); + /* flush write */ + readl(pm_addr); } else { - temp &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK); - xhci_writel(xhci, temp, pm_addr); + pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK | PORT_L1DS_MASK); + writel(pm_val, pm_addr); + /* flush write */ + readl(pm_addr); + if (udev->usb2_hw_lpm_besl_capable) { + spin_unlock_irqrestore(&xhci->lock, flags); + mutex_lock(hcd->bandwidth_mutex); + xhci_change_max_exit_latency(xhci, udev, 0); + mutex_unlock(hcd->bandwidth_mutex); + return 0; + } } spin_unlock_irqrestore(&xhci->lock, flags); return 0; } +/* check if a usb2 port supports a given extened capability protocol + * only USB2 ports extended protocol capability values are cached. + * Return 1 if capability is supported + */ +static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port, + unsigned capability) +{ + u32 port_offset, port_count; + int i; + + for (i = 0; i < xhci->num_ext_caps; i++) { + if (xhci->ext_caps[i] & capability) { + /* port offsets starts at 1 */ + port_offset = XHCI_EXT_PORT_OFF(xhci->ext_caps[i]) - 1; + port_count = XHCI_EXT_PORT_COUNT(xhci->ext_caps[i]); + if (port >= port_offset && + port < port_offset + port_count) + return 1; + } + } + return 0; +} + int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int ret; + int portnum = udev->portnum - 1; - ret = xhci_usb2_software_lpm_test(hcd, udev); - if (!ret) { - xhci_dbg(xhci, "software LPM test succeed\n"); - if (xhci->hw_lpm_support == 1) { - udev->usb2_hw_lpm_capable = 1; - ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1); - if (!ret) - udev->usb2_hw_lpm_enabled = 1; - } + if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || + !udev->lpm_capable) + return 0; + + /* we only support lpm for non-hub device connected to root hub yet */ + if (!udev->parent || udev->parent->parent || + udev->descriptor.bDeviceClass == USB_CLASS_HUB) + return 0; + + if (xhci->hw_lpm_support == 1 && + xhci_check_usb2_port_capability( + xhci, portnum, XHCI_HLC)) { + udev->usb2_hw_lpm_capable = 1; + udev->l1_params.timeout = XHCI_L1_TIMEOUT; + udev->l1_params.besl = XHCI_DEFAULT_BESL; + if (xhci_check_usb2_port_capability(xhci, portnum, + XHCI_BLC)) + udev->usb2_hw_lpm_besl_capable = 1; } return 0; @@ -4114,7 +4298,7 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, state_name, sel); else dev_dbg(&udev->dev, "Device-initiated %s disabled " - "due to long PEL %llu\n ms", + "due to long PEL %llu ms\n", state_name, pel); return USB3_LPM_DISABLED; } @@ -4341,7 +4525,7 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd, if (!config) return timeout; - for (i = 0; i < USB_MAXINTERFACES; i++) { + for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_driver *driver; struct usb_interface *intf = config->interface[i]; @@ -4373,56 +4557,6 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd, return timeout; } -/* - * Issue an Evaluate Context command to change the Maximum Exit Latency in the - * slot context. If that succeeds, store the new MEL in the xhci_virt_device. - */ -static int xhci_change_max_exit_latency(struct xhci_hcd *xhci, - struct usb_device *udev, u16 max_exit_latency) -{ - struct xhci_virt_device *virt_dev; - struct xhci_command *command; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_slot_ctx *slot_ctx; - unsigned long flags; - int ret; - - spin_lock_irqsave(&xhci->lock, flags); - if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) { - spin_unlock_irqrestore(&xhci->lock, flags); - return 0; - } - - /* Attempt to issue an Evaluate Context command to change the MEL. */ - virt_dev = xhci->devs[udev->slot_id]; - command = xhci->lpm_command; - xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx); - spin_unlock_irqrestore(&xhci->lock, flags); - - ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); - ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); - slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx); - slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT)); - slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency); - - xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n"); - xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, command->in_ctx, 0); - - /* Issue and wait for the evaluate context command. */ - ret = xhci_configure_endpoint(xhci, udev, command, - true, true); - xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0); - - if (!ret) { - spin_lock_irqsave(&xhci->lock, flags); - virt_dev->current_mel = max_exit_latency; - spin_unlock_irqrestore(&xhci->lock, flags); - } - return ret; -} - static int calculate_max_exit_latency(struct usb_device *udev, enum usb3_link_state state_changed, u16 hub_encoded_timeout) @@ -4564,6 +4698,13 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, xhci_dbg(xhci, "Could not allocate xHCI command structure.\n"); return -ENOMEM; } + ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "%s: Could not get input context, bad type.\n", + __func__); + xhci_free_command(xhci, config_cmd); + return -ENOMEM; + } spin_lock_irqsave(&xhci->lock, flags); if (hdev->speed == USB_SPEED_HIGH && @@ -4575,7 +4716,6 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, } xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx); - ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx); ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx); slot_ctx->dev_info |= cpu_to_le32(DEV_HUB); @@ -4634,7 +4774,7 @@ int xhci_get_frame(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); /* EHCI mods by the periodic size. Why? */ - return xhci_readl(xhci, &xhci->run_regs->microframe_index) >> 3; + return readl(&xhci->run_regs->microframe_index) >> 3; } int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) @@ -4642,10 +4782,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) struct xhci_hcd *xhci; struct device *dev = hcd->self.controller; int retval; - u32 temp; /* Accept arbitrarily long scatter-gather lists */ hcd->self.sg_tablesize = ~0; + + /* support to build packet from discontinuous buffers */ + hcd->self.no_sg_constraint = 1; + /* XHCI controllers don't stop the ep queue on short packets :| */ hcd->self.no_stop_on_short = 1; @@ -4670,33 +4813,34 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ - xhci = hcd_to_xhci(hcd); - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - if (HCC_64BIT_ADDR(temp)) { - xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); - } else { - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); - } return 0; } xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + - HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); + HC_LENGTH(readl(&xhci->cap_regs->hc_capbase)); xhci->run_regs = hcd->regs + - (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); + (readl(&xhci->cap_regs->run_regs_off) & RTSOFF_MASK); /* Cache read-only capability registers */ - xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); - xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); - xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); - xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); + xhci->hcs_params1 = readl(&xhci->cap_regs->hcs_params1); + xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2); + xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3); + xhci->hcc_params = readl(&xhci->cap_regs->hc_capbase); xhci->hci_version = HC_VERSION(xhci->hcc_params); - xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); + xhci->hcc_params = readl(&xhci->cap_regs->hcc_params); xhci_print_registers(xhci); + xhci->quirks = quirks; + get_quirks(dev, xhci); + /* In xhci controllers which follow xhci 1.0 spec gives a spurious + * success event after a short transfer. This quirk will ignore such + * spurious event. + */ + if (xhci->hci_version > 0x96) + xhci->quirks |= XHCI_SPURIOUS_SUCCESS; + /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) @@ -4709,12 +4853,12 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) goto error; xhci_dbg(xhci, "Reset complete\n"); - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - if (HCC_64BIT_ADDR(temp)) { + /* Set dma_mask and coherent_dma_mask to 64-bits, + * if xHC supports 64-bit addressing */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && + !dma_set_mask(dev, DMA_BIT_MASK(64))) { xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); - } else { - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); + dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); } xhci_dbg(xhci, "Calling HCD init\n"); @@ -4739,12 +4883,12 @@ static int __init xhci_hcd_init(void) retval = xhci_register_pci(); if (retval < 0) { - printk(KERN_DEBUG "Problem registering PCI driver."); + pr_debug("Problem registering PCI driver.\n"); return retval; } retval = xhci_register_plat(); if (retval < 0) { - printk(KERN_DEBUG "Problem registering platform driver."); + pr_debug("Problem registering platform driver.\n"); goto unreg_pci; } /* diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 77600cefcaf..9ffecd56600 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -132,6 +132,11 @@ struct xhci_cap_regs { /* Number of registers per port */ #define NUM_PORT_REGS 4 +#define PORTSC 0 +#define PORTPMSC 1 +#define PORTLI 2 +#define PORTHLPMC 3 + /** * struct xhci_op_regs - xHCI Host Controller Operational Registers. * @command: USBCMD - xHC command register @@ -378,9 +383,31 @@ struct xhci_op_regs { #define PORT_RWE (1 << 3) #define PORT_HIRD(p) (((p) & 0xf) << 4) #define PORT_HIRD_MASK (0xf << 4) +#define PORT_L1DS_MASK (0xff << 8) #define PORT_L1DS(p) (((p) & 0xff) << 8) #define PORT_HLE (1 << 16) + +/* USB2 Protocol PORTHLPMC */ +#define PORT_HIRDM(p)((p) & 3) +#define PORT_L1_TIMEOUT(p)(((p) & 0xff) << 2) +#define PORT_BESLD(p)(((p) & 0xf) << 10) + +/* use 512 microseconds as USB2 LPM L1 default timeout. */ +#define XHCI_L1_TIMEOUT 512 + +/* Set default HIRD/BESL value to 4 (350/400us) for USB2 L1 LPM resume latency. + * Safe to use with mixed HIRD and BESL systems (host and device) and is used + * by other operating systems. + * + * XHCI 1.0 errata 8/14/12 Table 13 notes: + * "Software should choose xHC BESL/BESLD field values that do not violate a + * device's resume latency requirements, + * e.g. not program values > '4' if BLC = '1' and a HIRD device is attached, + * or not program values < '4' if BLC = '0' and a BESL device is attached. + */ +#define XHCI_DEFAULT_BESL 4 + /** * struct xhci_intr_reg - Interrupt Register Set * @irq_pending: IMAN - Interrupt Management Register. Used to enable @@ -676,6 +703,7 @@ struct xhci_ep_ctx { /* deq bitmasks */ #define EP_CTX_CYCLE_MASK (1 << 0) +#define SCTX_DEQ_MASK (~0xfL) /** @@ -725,7 +753,7 @@ struct xhci_stream_ctx { }; /* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */ -#define SCT_FOR_CTX(p) (((p) << 1) & 0x7) +#define SCT_FOR_CTX(p) (((p) & 0x7) << 1) /* Secondary stream array type, dequeue pointer is to a transfer ring */ #define SCT_SEC_TR 0 /* Primary stream array type, dequeue pointer is to a transfer ring */ @@ -837,8 +865,6 @@ struct xhci_virt_ep { #define EP_GETTING_NO_STREAMS (1 << 5) /* ---- Related to URB cancellation ---- */ struct list_head cancelled_td_list; - /* The TRB that was last reported in a stopped endpoint ring */ - union xhci_trb *stopped_trb; struct xhci_td *stopped_td; unsigned int stopped_stream; /* Watchdog timer for stop endpoint command to cancel URBs */ @@ -908,14 +934,9 @@ struct xhci_virt_device { /* Rings saved to ensure old alt settings can be re-instated */ struct xhci_ring **ring_cache; int num_rings_cached; - /* Store xHC assigned device address */ - int address; #define XHCI_MAX_RINGS_CACHED 31 struct xhci_virt_ep eps[31]; struct completion cmd_completion; - /* Status of the last command issued for this device */ - u32 cmd_status; - struct list_head cmd_list; u8 fake_port; u8 real_port; struct xhci_interval_bw_table *bw_table; @@ -1072,6 +1093,14 @@ struct xhci_event_cmd { }; /* flags bitmasks */ + +/* Address device - disable SetAddress */ +#define TRB_BSR (1<<9) +enum xhci_setup_dev { + SETUP_CONTEXT_ONLY, + SETUP_CONTEXT_ADDRESS, +}; + /* bits 16:23 are the virtual function ID */ /* bits 24:31 are the slot ID */ #define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24) @@ -1085,9 +1114,10 @@ struct xhci_event_cmd { #define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23) #define LAST_EP_INDEX 30 -/* Set TR Dequeue Pointer command TRB fields */ +/* Set TR Dequeue Pointer command TRB fields, 6.4.3.9 */ #define TRB_TO_STREAM_ID(p) ((((p) & (0xffff << 16)) >> 16)) #define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16) +#define SCT_FOR_TRB(p) (((p) << 1) & 0x7) /* Port Status Change Event TRB fields */ @@ -1265,7 +1295,6 @@ struct xhci_td { /* command descriptor */ struct xhci_cd { - struct list_head cancel_cmd_list; struct xhci_command *command; union xhci_trb *cmd_trb; }; @@ -1308,6 +1337,7 @@ struct xhci_ring { unsigned int num_trbs_free_temp; enum xhci_ring_type type; bool last_td_was_short; + struct radix_tree_root *trb_address_map; }; struct xhci_erst_entry { @@ -1386,8 +1416,18 @@ struct xhci_bus_state { unsigned long resume_done[USB_MAXCHILDREN]; /* which ports have started to resume */ unsigned long resuming_ports; + /* Which ports are waiting on RExit to U0 transition. */ + unsigned long rexit_ports; + struct completion rexit_done[USB_MAXCHILDREN]; }; + +/* + * It can take up to 20 ms to transition from RExit to U0 on the + * Intel Lynx Point LP xHCI host. + */ +#define XHCI_MAX_REXIT_TIMEOUT (20 * 1000) + static inline unsigned int hcd_index(struct usb_hcd *hcd) { if (hcd->speed == HCD_USB3) @@ -1432,6 +1472,8 @@ struct xhci_hcd { /* msi-x vectors */ int msix_count; struct msix_entry *msix_entries; + /* optional clock */ + struct clk *clk; /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; @@ -1439,8 +1481,10 @@ struct xhci_hcd { #define CMD_RING_STATE_RUNNING (1 << 0) #define CMD_RING_STATE_ABORTED (1 << 1) #define CMD_RING_STATE_STOPPED (1 << 2) - struct list_head cancel_cmd_list; + struct list_head cmd_list; unsigned int cmd_ring_reserved_trbs; + struct timer_list cmd_timer; + struct xhci_command *current_cmd; struct xhci_ring *event_ring; struct xhci_erst erst; /* Scratchpad */ @@ -1464,11 +1508,6 @@ struct xhci_hcd { struct dma_pool *small_streams_pool; struct dma_pool *medium_streams_pool; -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - /* Poll the rings - for debugging */ - struct timer_list event_ring_timer; - int zombie; -#endif /* Host controller watchdog timer structures */ unsigned int xhc_state; @@ -1516,6 +1555,9 @@ struct xhci_hcd { #define XHCI_SPURIOUS_REBOOT (1 << 13) #define XHCI_COMP_MODE_QUIRK (1 << 14) #define XHCI_AVOID_BEI (1 << 15) +#define XHCI_PLAT (1 << 16) +#define XHCI_SLOW_SUSPEND (1 << 17) +#define XHCI_SPURIOUS_WAKEUP (1 << 18) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ @@ -1532,6 +1574,9 @@ struct xhci_hcd { unsigned sw_lpm_support:1; /* support xHCI 1.0 spec USB2 hardware LPM */ unsigned hw_lpm_support:1; + /* cached usb2 extened protocol capabilites */ + u32 *ext_caps; + unsigned int num_ext_caps; /* Compliance Mode Recovery Data */ struct timer_list comp_mode_recovery_timer; u32 port_status_u0; @@ -1550,16 +1595,8 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) return xhci->main_hcd; } -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -#define XHCI_DEBUG 1 -#else -#define XHCI_DEBUG 0 -#endif - #define xhci_dbg(xhci, fmt, args...) \ - do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) -#define xhci_info(xhci, fmt, args...) \ - do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) + dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args) #define xhci_err(xhci, fmt, args...) \ dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args) #define xhci_warn(xhci, fmt, args...) \ @@ -1567,19 +1604,6 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) #define xhci_warn_ratelimited(xhci, fmt, args...) \ dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args) -/* TODO: copied from ehci.h - can be refactored? */ -/* xHCI spec says all registers are little endian */ -static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, - __le32 __iomem *regs) -{ - return readl(regs); -} -static inline void xhci_writel(struct xhci_hcd *xhci, - const unsigned int val, __le32 __iomem *regs) -{ - writel(val, regs); -} - /* * Registers should always be accessed with double word or quad word accesses. * @@ -1631,6 +1655,8 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci, void xhci_dbg_ep_rings(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_virt_ep *ep); +void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *), + const char *fmt, ...); /* xHCI memory management */ void xhci_mem_cleanup(struct xhci_hcd *xhci); @@ -1641,6 +1667,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, struct usb_device *udev); unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); +unsigned int xhci_get_endpoint_address(unsigned int ep_index); unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index); unsigned int xhci_last_valid_endpoint(u32 added_ctxs); @@ -1711,8 +1738,7 @@ static inline int xhci_register_pci(void) { return 0; } static inline void xhci_unregister_pci(void) {} #endif -#if defined(CONFIG_USB_XHCI_PLATFORM) \ - || defined(CONFIG_USB_XHCI_PLATFORM_MODULE) +#if IS_ENABLED(CONFIG_USB_XHCI_PLATFORM) int xhci_register_plat(void); void xhci_unregister_plat(void); #else @@ -1745,7 +1771,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated); int xhci_get_frame(struct usb_hcd *hcd); irqreturn_t xhci_irq(struct usb_hcd *hcd); -irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd); +irqreturn_t xhci_msi_irq(int irq, void *hcd); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); int xhci_alloc_tt_info(struct xhci_hcd *xhci, @@ -1759,6 +1785,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint **eps, unsigned int num_eps, gfp_t mem_flags); int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, struct usb_device *udev, int enable); @@ -1780,13 +1807,14 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, dma_addr_t suspect_dma); int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code); void xhci_ring_cmd_db(struct xhci_hcd *xhci); -int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); -int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id); -int xhci_queue_vendor_command(struct xhci_hcd *xhci, +int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd, + u32 trb_type, u32 slot_id); +int xhci_queue_address_device(struct xhci_hcd *xhci, struct xhci_command *cmd, + dma_addr_t in_ctx_ptr, u32 slot_id, enum xhci_setup_dev); +int xhci_queue_vendor_command(struct xhci_hcd *xhci, struct xhci_command *cmd, u32 field1, u32 field2, u32 field3, u32 field4); -int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, int suspend); +int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, + int slot_id, unsigned int ep_index, int suspend); int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index); int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, @@ -1795,18 +1823,21 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index); int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index); -int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id, bool command_must_succeed); -int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id, bool command_must_succeed); -int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index); -int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id); +int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, + struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, + bool command_must_succeed); +int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd, + dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed); +int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, + int slot_id, unsigned int ep_index); +int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd, + u32 slot_id); void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id, struct xhci_td *cur_td, struct xhci_dequeue_state *state); void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, + struct xhci_command *cmd, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id, struct xhci_dequeue_state *deq_state); @@ -1816,10 +1847,11 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); void xhci_stop_endpoint_command_watchdog(unsigned long arg); -int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, - union xhci_trb *cmd_trb); +void xhci_handle_command_timeout(unsigned long data); + void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id); +void xhci_cleanup_command_queue(struct xhci_hcd *xhci); /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, |
