diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 19:30:55 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 19:30:55 -0700 |
commit | 362f6729cbb1d6bbab59e069f19441b0622ff7ec (patch) | |
tree | 654070221092c34c97f48fbbdef7d5f02ffc7ba4 /drivers/usb/host | |
parent | 4422d80ed7d4bdb2d6e9fb890c66c3d9250ba694 (diff) | |
parent | 6836796de4019944f4ba4c99a360e8250fd2e735 (diff) |
Merge tag 'usb-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH:
"Here is the big patchset of USB and PHY driver updates for 4.13-rc1.
On the PHY side, they decided to move files around to "make things
easier" in their tree. Hopefully that wasn't a mistake, but in
linux-next testing, we haven't had any reported problems.
There's the usual set of gadget and xhci and musb updates in here as
well, along with a number of smaller updates for a raft of different
USB drivers. Full details in the shortlog, nothing really major.
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (173 commits)
Add USB quirk for HVR-950q to avoid intermittent device resets
USB hub_probe: rework ugly goto-into-compound-statement
usb: host: ohci-pxa27x: Handle return value of clk_prepare_enable
USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
usbip: Fix uninitialized variable bug in vhci
usb: core: read USB ports from DT in the usbport LED trigger driver
dt-bindings: leds: document new trigger-sources property
usb: typec: ucsi: Add ACPI driver
usb: typec: Add support for UCSI interface
usb: musb: compress return logic into one line
USB: serial: propagate late probe errors
USB: serial: refactor port endpoint setup
usb: musb: tusb6010_omap: Convert to DMAengine API
ARM: OMAP2+: DMA: Add slave map entries for 24xx external request lines
usb: musb: tusb6010: Handle DMA TX completion in DMA callback as well
usb: musb: tusb6010_omap: Allocate DMA channels upfront
usb: musb: tusb6010_omap: Create new struct for DMA data/parameters
usb: musb: tusb6010_omap: Use one musb_ep_select call in tusb_omap_dma_program
usb: musb: tusb6010: Add MUSB_G_NO_SKB_RESERVE to quirks
usb: musb: Add quirk to avoid skb reserve in gadget mode
...
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/Kconfig | 12 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-exynos.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-timer.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/fotg210-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ohci-omap3.c | 211 | ||||
-rw-r--r-- | drivers/usb/host/ohci-platform.c | 13 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pxa27x.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 17 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 51 | ||||
-rw-r--r-- | drivers/usb/host/uhci-platform.c | 22 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 81 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 200 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 25 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 22 |
16 files changed, 271 insertions, 404 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ababb91d654a..fa5692dec832 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -473,8 +473,12 @@ config USB_OHCI_HCD_AT91 config USB_OHCI_HCD_OMAP3 tristate "OHCI support for OMAP3 and later chips" depends on (ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5) + select USB_OHCI_HCD_PLATFORM default y - ---help--- + help + This option is deprecated now and the driver was removed, use + USB_OHCI_HCD_PLATFORM instead. + Enables support for the on-chip OHCI controller on OMAP3 and later chips. @@ -627,7 +631,11 @@ config USB_UHCI_SUPPORT_NON_PCI_HC config USB_UHCI_PLATFORM bool - default y if ARCH_VT8500 + default y if (ARCH_VT8500 || ARCH_ASPEED) + +config USB_UHCI_ASPEED + bool + default y if ARCH_ASPEED config USB_UHCI_BIG_ENDIAN_MMIO bool diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index c77b0a38557b..cf2691fffcc0 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -52,7 +52,6 @@ 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_STI) += ohci-st.o obj-$(CONFIG_USB_OHCI_HCD_AT91) += ohci-at91.o diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 7a603f66a9bc..26b641100639 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -279,7 +279,9 @@ static int exynos_ehci_resume(struct device *dev) struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); int ret; - clk_prepare_enable(exynos_ehci->clk); + ret = clk_prepare_enable(exynos_ehci->clk); + if (ret) + return ret; ret = exynos_ehci_phy_enable(dev); if (ret) { diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 980a6b3b2da2..6bc6304672bc 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1105,7 +1105,7 @@ iso_stream_init( addr |= epnum << 8; addr |= dev->devnum; stream->ps.usecs = HS_USECS_ISO(maxp); - think_time = dev->tt ? dev->tt->think_time : 0; + think_time = dev->tt->think_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); diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 3893b5bafd87..0b6cdb723192 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -424,7 +424,7 @@ static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) */ now = ktime_get(); for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) { - if (now >= ehci->hr_timeouts[e]) + if (ktime_compare(now, ehci->hr_timeouts[e]) >= 0) event_handlers[e](ehci); else ehci_enable_event(ehci, e, false); diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index ced08dc229ad..457cc6525abd 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -1380,7 +1380,7 @@ static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t) */ now = ktime_get(); for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) { - if (now >= fotg210->hr_timeouts[e]) + if (ktime_compare(now, fotg210->hr_timeouts[e]) >= 0) event_handlers[e](fotg210); else fotg210_enable_event(fotg210, e, false); diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c deleted file mode 100644 index ec15aebe8786..000000000000 --- a/drivers/usb/host/ohci-omap3.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * ohci-omap3.c - driver for OHCI on OMAP3 and later processors - * - * Bus Glue for OMAP3 USBHOST 3 port OHCI controller - * This controller is also used in later OMAPs and AM35x chips - * - * Copyright (C) 2007-2010 Texas Instruments, Inc. - * Author: Vikram Pandita <vikram.pandita@ti.com> - * Author: Anand Gadiyar <gadiyar@ti.com> - * Author: Keshava Munegowda <keshava_mgowda@ti.com> - * - * Based on ehci-omap.c and some other ohci glue layers - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO (last updated Feb 27, 2011): - * - 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/usb.h> -#include <linux/usb/hcd.h> - -#include "ohci.h" - -#define DRIVER_DESC "OHCI OMAP3 driver" - -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 - * always called with process context; sleeping is OK - */ - -/** - * ohci_hcd_omap3_probe - initialize OMAP-based 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 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; - int irq; - - if (usb_disabled()) - return -ENODEV; - - if (!dev->parent) { - dev_err(dev, "Missing parent device\n"); - return -ENODEV; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "OHCI irq failed\n"); - return -ENODEV; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "UHH OHCI get resource failed\n"); - return -ENOMEM; - } - - regs = ioremap(res->start, resource_size(res)); - if (!regs) { - dev_err(dev, "UHH OHCI ioremap failed\n"); - return -ENOMEM; - } - - /* - * 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. - */ - 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) { - dev_err(dev, "usb_create_hcd failed\n"); - goto err_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = regs; - - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - - 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; - -err_add_hcd: - pm_runtime_put_sync(dev); - usb_put_hcd(hcd); - -err_io: - iounmap(regs); - - return ret; -} - -/* - * may be called without controller electrically present - * may be called with controller, bus, and devices active - */ - -/** - * ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs - * @pdev: USB Host Controller being removed - * - * Reverses the effect of ohci_hcd_omap3_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - */ -static int ohci_hcd_omap3_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd = dev_get_drvdata(dev); - - iounmap(hcd->regs); - usb_remove_hcd(hcd); - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - usb_put_hcd(hcd); - return 0; -} - -static const struct of_device_id omap_ohci_dt_ids[] = { - { .compatible = "ti,ohci-omap3" }, - { } -}; - -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 = usb_hcd_platform_shutdown, - .driver = { - .name = "ohci-omap3", - .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-platform.c b/drivers/usb/host/ohci-platform.c index 6368fce43197..61fe2b985070 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -24,6 +24,7 @@ #include <linux/err.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/reset.h> #include <linux/usb/ohci_pdriver.h> #include <linux/usb.h> @@ -163,6 +164,10 @@ static int ohci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "no-big-frame-no")) ohci->flags |= OHCI_QUIRK_FRAME_NO; + if (of_property_read_bool(dev->dev.of_node, + "remote-wakeup-connected")) + ohci->hc_control = OHCI_CTRL_RWC; + of_property_read_u32(dev->dev.of_node, "num-ports", &ohci->num_ports); @@ -242,6 +247,8 @@ static int ohci_platform_probe(struct platform_device *dev) } #endif + pm_runtime_set_active(&dev->dev); + pm_runtime_enable(&dev->dev); if (pdata->power_on) { err = pdata->power_on(dev); if (err < 0) @@ -271,6 +278,7 @@ err_power: if (pdata->power_off) pdata->power_off(dev); err_reset: + pm_runtime_disable(&dev->dev); while (--rst >= 0) reset_control_assert(priv->resets[rst]); err_put_clks: @@ -292,6 +300,7 @@ static int ohci_platform_remove(struct platform_device *dev) struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); int clk, rst; + pm_runtime_get_sync(&dev->dev); usb_remove_hcd(hcd); if (pdata->power_off) @@ -305,6 +314,9 @@ static int ohci_platform_remove(struct platform_device *dev) usb_put_hcd(hcd); + pm_runtime_put_sync(&dev->dev); + pm_runtime_disable(&dev->dev); + if (pdata == &ohci_platform_defaults) dev->dev.platform_data = NULL; @@ -350,6 +362,7 @@ static int ohci_platform_resume(struct device *dev) static const struct of_device_id ohci_platform_ids[] = { { .compatible = "generic-ohci", }, { .compatible = "cavium,octeon-6335-ohci", }, + { .compatible = "ti,ohci-omap3", }, { } }; MODULE_DEVICE_TABLE(of, ohci_platform_ids); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 79efde8f21e0..21c010ffb03c 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -274,14 +274,16 @@ extern void pxa27x_clear_otgph(void); static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) { - int retval = 0; + int retval; struct pxaohci_platform_data *inf; uint32_t uhchr; struct usb_hcd *hcd = dev_get_drvdata(dev); inf = dev_get_platdata(dev); - clk_prepare_enable(pxa_ohci->clk); + retval = clk_prepare_enable(pxa_ohci->clk); + if (retval) + return retval; pxa27x_reset_hc(pxa_ohci); @@ -296,8 +298,10 @@ static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) if (inf->init) retval = inf->init(dev); - if (retval < 0) + if (retval < 0) { + clk_disable_unprepare(pxa_ohci->clk); return retval; + } if (cpu_is_pxa3xx()) pxa3xx_u2d_start_hc(&hcd->self); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 94b150196d4f..c3267a78c94e 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -265,9 +265,13 @@ static void configure_hc(struct uhci_hcd *uhci) static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) { - /* If we have to ignore overcurrent events then almost by definition - * we can't depend on resume-detect interrupts. */ - if (ignore_oc) + /* + * If we have to ignore overcurrent events then almost by definition + * we can't depend on resume-detect interrupts. + * + * Those interrupts also don't seem to work on ASpeed SoCs. + */ + if (ignore_oc || uhci_is_aspeed(uhci)) return 1; return uhci->resume_detect_interrupts_are_broken ? @@ -384,6 +388,13 @@ static void start_rh(struct uhci_hcd *uhci) { uhci->is_stopped = 0; + /* + * Clear stale status bits on Aspeed as we get a stale HCH + * which causes problems later on + */ + if (uhci_is_aspeed(uhci)) + uhci_writew(uhci, uhci_readw(uhci, USBSTS), USBSTS); + /* Mark it configured and running with a 64-byte max packet. * All interrupts are enabled, even though RESUME won't do anything. */ diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 7fa318a3091d..91b22b2ea3aa 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -48,6 +48,8 @@ /* USB port status and control registers */ #define USBPORTSC1 16 #define USBPORTSC2 18 +#define USBPORTSC3 20 +#define USBPORTSC4 22 #define USBPORTSC_CCS 0x0001 /* Current Connect Status * ("device present") */ #define USBPORTSC_CSC 0x0002 /* Connect Status Change */ @@ -427,6 +429,7 @@ struct uhci_hcd { unsigned int wait_for_hp:1; /* Wait for HP port reset */ unsigned int big_endian_mmio:1; /* Big endian registers */ unsigned int big_endian_desc:1; /* Big endian descriptors */ + unsigned int is_aspeed:1; /* Aspeed impl. workarounds */ /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ @@ -490,6 +493,12 @@ struct urb_priv { #define PCI_VENDOR_ID_GENESYS 0x17a0 #define PCI_DEVICE_ID_GL880S_UHCI 0x8083 +/* Aspeed SoC needs some quirks */ +static inline bool uhci_is_aspeed(const struct uhci_hcd *uhci) +{ + return IS_ENABLED(CONFIG_USB_UHCI_ASPEED) && uhci->is_aspeed; +} + /* * Functions used to access controller registers. The UCHI spec says that host * controller I/O registers are mapped into PCI I/O space. For non-PCI hosts @@ -545,10 +554,42 @@ static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg) #define uhci_big_endian_mmio(u) 0 #endif +static inline int uhci_aspeed_reg(unsigned int reg) +{ + switch (reg) { + case USBCMD: + return 00; + case USBSTS: + return 0x04; + case USBINTR: + return 0x08; + case USBFRNUM: + return 0x80; + case USBFLBASEADD: + return 0x0c; + case USBSOF: + return 0x84; + case USBPORTSC1: + return 0x88; + case USBPORTSC2: + return 0x8c; + case USBPORTSC3: + return 0x90; + case USBPORTSC4: + return 0x94; + default: + pr_warn("UHCI: Unsupported register 0x%02x on Aspeed\n", reg); + /* Return an unimplemented register */ + return 0x10; + } +} + static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg) { if (uhci_has_pci_registers(uhci)) return inl(uhci->io_addr + reg); + else if (uhci_is_aspeed(uhci)) + return readl(uhci->regs + uhci_aspeed_reg(reg)); #ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO else if (uhci_big_endian_mmio(uhci)) return readl_be(uhci->regs + reg); @@ -561,6 +602,8 @@ static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg) { if (uhci_has_pci_registers(uhci)) outl(val, uhci->io_addr + reg); + else if (uhci_is_aspeed(uhci)) + writel(val, uhci->regs + uhci_aspeed_reg(reg)); #ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO else if (uhci_big_endian_mmio(uhci)) writel_be(val, uhci->regs + reg); @@ -573,6 +616,8 @@ static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg) { if (uhci_has_pci_registers(uhci)) return inw(uhci->io_addr + reg); + else if (uhci_is_aspeed(uhci)) + return readl(uhci->regs + uhci_aspeed_reg(reg)); #ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO else if (uhci_big_endian_mmio(uhci)) return readw_be(uhci->regs + reg); @@ -585,6 +630,8 @@ static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg) { if (uhci_has_pci_registers(uhci)) outw(val, uhci->io_addr + reg); + else if (uhci_is_aspeed(uhci)) + writel(val, uhci->regs + uhci_aspeed_reg(reg)); #ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO else if (uhci_big_endian_mmio(uhci)) writew_be(val, uhci->regs + reg); @@ -597,6 +644,8 @@ static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg) { if (uhci_has_pci_registers(uhci)) return inb(uhci->io_addr + reg); + else if (uhci_is_aspeed(uhci)) + return readl(uhci->regs + uhci_aspeed_reg(reg)); #ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO else if (uhci_big_endian_mmio(uhci)) return readb_be(uhci->regs + reg); @@ -609,6 +658,8 @@ static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg) { if (uhci_has_pci_registers(uhci)) outb(val, uhci->io_addr + reg); + else if (uhci_is_aspeed(uhci)) + writel(val, uhci->regs + uhci_aspeed_reg(reg)); #ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO else if (uhci_big_endian_mmio(uhci)) writeb_be(val, uhci->regs + reg); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 32a6f3d8deec..1b4e086c33a0 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -15,7 +15,9 @@ static int uhci_platform_init(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - uhci->rh_numports = uhci_count_ports(hcd); + /* Probe number of ports if not already provided by DT */ + if (!uhci->rh_numports) + uhci->rh_numports = uhci_count_ports(hcd); /* Set up pointers to to generic functions */ uhci->reset_hc = uhci_generic_reset_hc; @@ -63,6 +65,7 @@ static const struct hc_driver uhci_platform_hc_driver = { static int uhci_hcd_platform_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct usb_hcd *hcd; struct uhci_hcd *uhci; struct resource *res; @@ -98,6 +101,23 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) uhci->regs = hcd->regs; + /* Grab some things from the device-tree */ + if (np) { + u32 num_ports; + + if (of_property_read_u32(np, "#ports", &num_ports) == 0) { + uhci->rh_numports = num_ports; + dev_info(&pdev->dev, + "Detected %d ports from device-tree\n", + num_ports); + } + if (of_device_is_compatible(np, "aspeed,ast2400-uhci") || + of_device_is_compatible(np, "aspeed,ast2500-uhci")) { + uhci->is_aspeed = 1; + dev_info(&pdev->dev, + "Enabled Aspeed implementation workarounds\n"); + } + } ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); if (ret) goto err_rmr; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fddf2731f798..2a82c927ded2 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -407,64 +407,17 @@ fail: return NULL; } -void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, +void xhci_free_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, unsigned int ep_index) { - int rings_cached; - - rings_cached = virt_dev->num_rings_cached; - if (rings_cached < XHCI_MAX_RINGS_CACHED) { - virt_dev->ring_cache[rings_cached] = - virt_dev->eps[ep_index].ring; - virt_dev->num_rings_cached++; - xhci_dbg(xhci, "Cached old ring, " - "%d ring%s cached\n", - virt_dev->num_rings_cached, - (virt_dev->num_rings_cached > 1) ? "s" : ""); - } else { - xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); - xhci_dbg(xhci, "Ring cache full (%d rings), " - "freeing ring\n", - virt_dev->num_rings_cached); - } + xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); virt_dev->eps[ep_index].ring = NULL; } -/* Zero an endpoint ring (except for link TRBs) and move the enqueue and dequeue - * pointers to the beginning of the ring. - */ -static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, - struct xhci_ring *ring, unsigned int cycle_state, - enum xhci_ring_type type) -{ - struct xhci_segment *seg = ring->first_seg; - int i; - - do { - memset(seg->trbs, 0, - sizeof(union xhci_trb)*TRBS_PER_SEGMENT); - if (cycle_state == 0) { - for (i = 0; i < TRBS_PER_SEGMENT; i++) - seg->trbs[i].link.control |= - cpu_to_le32(TRB_CYCLE); - } - /* All endpoint rings have link TRBs */ - xhci_link_segments(xhci, seg, seg->next, type); - seg = seg->next; - } while (seg != ring->first_seg); - ring->type = type; - xhci_initialize_ring_info(ring, cycle_state); - /* td list should be empty since all URBs have been cancelled, - * but just in case... - */ - INIT_LIST_HEAD(&ring->td_list); -} - /* * Expand an existing ring. - * Look for a cached ring or allocate a new ring which has same segment numbers - * and link the two rings. + * Allocate a new ring which has same segment numbers and link the two rings. */ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_trbs, gfp_t flags) @@ -968,12 +921,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) /* If necessary, update the number of active TTs on this root port */ xhci_update_tt_active_eps(xhci, dev, old_active_eps); - if (dev->ring_cache) { - for (i = 0; i < dev->num_rings_cached; i++) - xhci_ring_free(xhci, dev->ring_cache[i]); - kfree(dev->ring_cache); - } - if (dev->in_ctx) xhci_free_container_ctx(xhci, dev->in_ctx); if (dev->out_ctx) @@ -1062,14 +1009,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, if (!dev->eps[0].ring) goto fail; - /* Allocate pointers to the ring cache */ - dev->ring_cache = kzalloc( - sizeof(struct xhci_ring *)*XHCI_MAX_RINGS_CACHED, - flags); - if (!dev->ring_cache) - goto fail; - dev->num_rings_cached = 0; - dev->udev = udev; /* Point to output device context in dcbaa. */ @@ -1537,17 +1476,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* Set up the endpoint ring */ virt_dev->eps[ep_index].new_ring = xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags); - if (!virt_dev->eps[ep_index].new_ring) { - /* Attempt to use the ring cache */ - if (virt_dev->num_rings_cached == 0) - return -ENOMEM; - virt_dev->num_rings_cached--; - virt_dev->eps[ep_index].new_ring = - virt_dev->ring_cache[virt_dev->num_rings_cached]; - virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; - xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, - 1, ring_type); - } + if (!virt_dev->eps[ep_index].new_ring) + return -ENOMEM; + virt_dev->eps[ep_index].skip = false; ep_ring = virt_dev->eps[ep_index].new_ring; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 03f63f50afb6..c50c902d009e 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -480,10 +480,34 @@ struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, return NULL; } + +/* + * Get the hw dequeue pointer xHC stopped on, either directly from the + * endpoint context, or if streams are in use from the stream context. + * The returned hw_dequeue contains the lowest four bits with cycle state + * and possbile stream context type. + */ +static u64 xhci_get_hw_deq(struct xhci_hcd *xhci, struct xhci_virt_device *vdev, + unsigned int ep_index, unsigned int stream_id) +{ + struct xhci_ep_ctx *ep_ctx; + struct xhci_stream_ctx *st_ctx; + struct xhci_virt_ep *ep; + + ep = &vdev->eps[ep_index]; + + if (ep->ep_state & EP_HAS_STREAMS) { + st_ctx = &ep->stream_info->stream_ctx_array[stream_id]; + return le64_to_cpu(st_ctx->stream_ring); + } + ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index); + return le64_to_cpu(ep_ctx->deq); +} + /* * Move the xHC's endpoint ring dequeue pointer past cur_td. * Record the new state of the xHC's endpoint ring dequeue segment, - * dequeue pointer, and new consumer cycle state in state. + * dequeue pointer, stream id, and new consumer cycle state in state. * Update our internal representation of the ring's dequeue pointer. * * We do this in three jumps: @@ -521,24 +545,15 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, stream_id); return; } - /* Dig out the cycle state saved by the xHC during the stop ep cmd */ 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); - } + hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id); new_seg = ep_ring->deq_seg; new_deq = ep_ring->dequeue; state->new_cycle_state = hw_dequeue & 0x1; + state->stream_id = stream_id; /* * We want to find the pointer, segment and cycle state of the new trb @@ -691,7 +706,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, struct xhci_td *last_unlinked_td; struct xhci_ep_ctx *ep_ctx; struct xhci_virt_device *vdev; - + u64 hw_deq; struct xhci_dequeue_state deq_state; if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) { @@ -715,7 +730,6 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, if (list_empty(&ep->cancelled_td_list)) { xhci_stop_watchdog_timer_in_irq(xhci, ep); - ep->stopped_td = NULL; ring_doorbell_for_active_rings(xhci, slot_id, ep_index); return; } @@ -753,12 +767,19 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, * If we stopped on the TD we need to cancel, then we have to * move the xHC endpoint ring dequeue pointer past this TD. */ - if (cur_td == ep->stopped_td) + hw_deq = xhci_get_hw_deq(xhci, vdev, ep_index, + cur_td->urb->stream_id); + hw_deq &= ~0xf; + + if (trb_in_td(xhci, cur_td->start_seg, cur_td->first_trb, + cur_td->last_trb, hw_deq, false)) { xhci_find_new_dequeue_state(xhci, slot_id, ep_index, - cur_td->urb->stream_id, - cur_td, &deq_state); - else + cur_td->urb->stream_id, + cur_td, &deq_state); + } else { td_to_noop(xhci, ep_ring, cur_td, false); + } + remove_finished_td: /* * The event handler won't see a completion for this TD anymore, @@ -773,15 +794,13 @@ 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, slot_id, ep_index, - ep->stopped_td->urb->stream_id, &deq_state); + &deq_state); xhci_ring_cmd_db(xhci); } else { /* Otherwise ring the doorbell(s) to restart queued transfers */ ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } - ep->stopped_td = NULL; - /* * Drop the lock and complete the URBs in the cancelled TD list. * New TDs to be cancelled might be added to the end of the list before @@ -1800,7 +1819,8 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id, - struct xhci_td *td, union xhci_trb *ep_trb) + struct xhci_td *td, union xhci_trb *ep_trb, + enum xhci_ep_reset_type reset_type) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; struct xhci_command *command; @@ -1809,12 +1829,11 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, return; ep->ep_state |= EP_HALTED; - ep->stopped_stream = stream_id; - xhci_queue_reset_ep(xhci, command, slot_id, ep_index); - xhci_cleanup_stalled_ring(xhci, ep_index, td); + xhci_queue_reset_ep(xhci, command, slot_id, ep_index, reset_type); - ep->stopped_stream = 0; + if (reset_type == EP_HARD_RESET) + xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td); xhci_ring_cmd_db(xhci); } @@ -1909,7 +1928,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, union xhci_trb *ep_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep, int *status, bool skip) + struct xhci_virt_ep *ep, int *status) { struct xhci_virt_device *xdev; struct xhci_ep_ctx *ep_ctx; @@ -1925,9 +1944,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); - if (skip) - goto td_cleanup; - if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID || trb_comp_code == COMP_STOPPED || trb_comp_code == COMP_STOPPED_SHORT_PACKET) { @@ -1935,7 +1951,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, * stopped TDs. A stopped TD may be restarted, so don't update * the ring dequeue pointer or take this TD off any lists yet. */ - ep->stopped_td = td; return 0; } if (trb_comp_code == COMP_STALL_ERROR || @@ -1947,7 +1962,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, * The class driver clears the device side halt later. */ xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, - ep_ring->stream_id, td, ep_trb); + ep_ring->stream_id, td, ep_trb, + EP_HARD_RESET); } else { /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) @@ -1955,7 +1971,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, inc_deq(xhci, ep_ring); } -td_cleanup: return xhci_td_cleanup(xhci, td, ep_ring, status); } @@ -2075,7 +2090,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length = requested; finish_td: - return finish_td(xhci, td, ep_trb, event, ep, status, false); + return finish_td(xhci, td, ep_trb, event, ep, status); } /* @@ -2162,7 +2177,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length += frame->actual_length; - return finish_td(xhci, td, ep_trb, event, ep, status, false); + return finish_td(xhci, td, ep_trb, event, ep, status); } static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, @@ -2190,7 +2205,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, inc_deq(xhci, ep_ring); inc_deq(xhci, ep_ring); - return finish_td(xhci, td, NULL, event, ep, status, true); + return xhci_td_cleanup(xhci, td, ep_ring, status); } /* @@ -2252,7 +2267,7 @@ finish_td: remaining); td->urb->actual_length = 0; } - return finish_td(xhci, td, ep_trb, event, ep, status, false); + return finish_td(xhci, td, ep_trb, event, ep, status); } /* @@ -2280,39 +2295,46 @@ static int handle_tx_event(struct xhci_hcd *xhci, bool handling_skipped_tds = false; slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); + ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; + trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); + ep_trb_dma = le64_to_cpu(event->buffer); + xdev = xhci->devs[slot_id]; if (!xdev) { xhci_err(xhci, "ERROR Transfer event pointed to bad slot %u\n", slot_id); - xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n", - (unsigned long long) xhci_trb_virt_to_dma( - xhci->event_ring->deq_seg, - xhci->event_ring->dequeue), - lower_32_bits(le64_to_cpu(event->buffer)), - upper_32_bits(le64_to_cpu(event->buffer)), - le32_to_cpu(event->transfer_len), - le32_to_cpu(event->flags)); - return -ENODEV; - } - - /* Endpoint ID is 1 based, our index is zero based */ - ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; + goto err_out; + } + ep = &xdev->eps[ep_index]; - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); + ep_ring = xhci_dma_to_transfer_ring(ep, ep_trb_dma); ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - if (!ep_ring || GET_EP_CTX_STATE(ep_ctx) == EP_STATE_DISABLED) { + + if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_DISABLED) { xhci_err(xhci, - "ERROR Transfer event for disabled endpoint slot %u ep %u or incorrect stream ring\n", + "ERROR Transfer event for disabled endpoint slot %u ep %u\n", slot_id, ep_index); - xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n", - (unsigned long long) xhci_trb_virt_to_dma( - xhci->event_ring->deq_seg, - xhci->event_ring->dequeue), - lower_32_bits(le64_to_cpu(event->buffer)), - upper_32_bits(le64_to_cpu(event->buffer)), - le32_to_cpu(event->transfer_len), - le32_to_cpu(event->flags)); - return -ENODEV; + goto err_out; + } + + /* Some transfer events don't always point to a trb, see xhci 4.17.4 */ + if (!ep_ring) { + switch (trb_comp_code) { + case COMP_STALL_ERROR: + case COMP_USB_TRANSACTION_ERROR: + case COMP_INVALID_STREAM_TYPE_ERROR: + case COMP_INVALID_STREAM_ID_ERROR: + xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, 0, + NULL, NULL, EP_SOFT_RESET); + goto cleanup; + case COMP_RING_UNDERRUN: + case COMP_RING_OVERRUN: + goto cleanup; + default: + xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n", + slot_id, ep_index); + goto err_out; + } } /* Count current td numbers if ep->skip is set */ @@ -2321,8 +2343,6 @@ static int handle_tx_event(struct xhci_hcd *xhci, td_num++; } - ep_trb_dma = le64_to_cpu(event->buffer); - trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); /* Look for common error cases */ switch (trb_comp_code) { /* Skip codes that require special handling depending on @@ -2339,6 +2359,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, slot_id, ep_index); case COMP_SHORT_PACKET: break; + /* Completion codes for endpoint stopped state */ case COMP_STOPPED: xhci_dbg(xhci, "Stopped on Transfer TRB for slot %u ep %u\n", slot_id, ep_index); @@ -2353,18 +2374,13 @@ static int handle_tx_event(struct xhci_hcd *xhci, "Stopped with short packet transfer detected for slot %u ep %u\n", slot_id, ep_index); break; + /* Completion codes for endpoint halted state */ case COMP_STALL_ERROR: xhci_dbg(xhci, "Stalled endpoint for slot %u ep %u\n", slot_id, ep_index); ep->ep_state |= EP_HALTED; status = -EPIPE; break; - case COMP_TRB_ERROR: - xhci_warn(xhci, - "WARN: TRB error for slot %u ep %u on endpoint\n", - slot_id, ep_index); - status = -EILSEQ; - break; case COMP_SPLIT_TRANSACTION_ERROR: case COMP_USB_TRANSACTION_ERROR: xhci_dbg(xhci, "Transfer error for slot %u ep %u on endpoint\n", @@ -2376,6 +2392,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, slot_id, ep_index); status = -EOVERFLOW; break; + /* Completion codes for endpoint error state */ + case COMP_TRB_ERROR: + xhci_warn(xhci, + "WARN: TRB error for slot %u ep %u on endpoint\n", + slot_id, ep_index); + status = -EILSEQ; + break; + /* completion codes not indicating endpoint state change */ case COMP_DATA_BUFFER_ERROR: xhci_warn(xhci, "WARN: HC couldn't access mem fast enough for slot %u ep %u\n", @@ -2413,12 +2437,6 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); goto cleanup; - case COMP_INCOMPATIBLE_DEVICE_ERROR: - xhci_warn(xhci, - "WARN: detect an incompatible device for slot %u ep %u", - slot_id, ep_index); - status = -EPROTO; - break; case COMP_MISSED_SERVICE_ERROR: /* * When encounter missed service error, one or more isoc tds @@ -2437,6 +2455,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, "No Ping response error for slot %u ep %u, Skip one Isoc TD\n", slot_id, ep_index); goto cleanup; + + case COMP_INCOMPATIBLE_DEVICE_ERROR: + /* needs disable slot command to recover */ + xhci_warn(xhci, + "WARN: detect an incompatible device for slot %u ep %u", + slot_id, ep_index); + status = -EPROTO; + break; default: if (xhci_is_vendor_info_code(xhci, trb_comp_code)) { status = 0; @@ -2589,6 +2615,17 @@ cleanup: } while (handling_skipped_tds); return 0; + +err_out: + xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n", + (unsigned long long) xhci_trb_virt_to_dma( + xhci->event_ring->deq_seg, + xhci->event_ring->dequeue), + lower_32_bits(le64_to_cpu(event->buffer)), + upper_32_bits(le64_to_cpu(event->buffer)), + le32_to_cpu(event->transfer_len), + le32_to_cpu(event->flags)); + return -ENODEV; } /* @@ -3963,13 +4000,12 @@ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, /* Set Transfer Ring Dequeue Pointer command */ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, struct xhci_dequeue_state *deq_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_stream_id = STREAM_ID_FOR_TRB(deq_state->stream_id); u32 trb_sct = 0; u32 type = TRB_TYPE(TRB_SET_DEQ); struct xhci_virt_ep *ep; @@ -4007,7 +4043,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, ep->queued_deq_seg = deq_state->new_deq_seg; ep->queued_deq_ptr = deq_state->new_deq_ptr; - if (stream_id) + if (deq_state->stream_id) trb_sct = SCT_FOR_TRB(SCT_PRI_TR); ret = queue_command(xhci, cmd, lower_32_bits(addr) | trb_sct | deq_state->new_cycle_state, @@ -4027,12 +4063,16 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, } int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, - int slot_id, unsigned int ep_index) + int slot_id, unsigned int ep_index, + enum xhci_ep_reset_type reset_type) { 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); + if (reset_type == EP_SOFT_RESET) + type |= TRB_TSP; + return queue_command(xhci, cmd, 0, 0, 0, trb_slot_id | trb_ep_index | type, false); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 30f47d92a610..56f85df013db 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1695,8 +1695,7 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, if (xhci->quirks & XHCI_MTK_HOST) { ret = xhci_mtk_add_ep_quirk(hcd, udev, ep); if (ret < 0) { - xhci_free_or_cache_endpoint_ring(xhci, - virt_dev, ep_index); + xhci_free_endpoint_ring(xhci, virt_dev, ep_index); return ret; } } @@ -2720,23 +2719,23 @@ static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) 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)))) { - xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); + xhci_free_endpoint_ring(xhci, virt_dev, i); xhci_check_bw_drop_ep_streams(xhci, virt_dev, i); } } xhci_zero_in_ctx(xhci, virt_dev); /* * Install any rings for completely new endpoints or changed endpoints, - * and free or cache any old rings from changed endpoints. + * and free any old rings from changed endpoints. */ for (i = 1; i < 31; i++) { if (!virt_dev->eps[i].new_ring) continue; - /* Only cache or free the old ring if it exists. + /* Only free the old ring if it exists. * It may not if this is the first add of an endpoint. */ if (virt_dev->eps[i].ring) { - xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); + xhci_free_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; @@ -2823,8 +2822,8 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, added_ctxs, added_ctxs); } -void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, - unsigned int ep_index, struct xhci_td *td) +void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, + unsigned int stream_id, struct xhci_td *td) { struct xhci_dequeue_state deq_state; struct xhci_virt_ep *ep; @@ -2837,7 +2836,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, * or it will attempt to resend it on the next doorbell ring. */ xhci_find_new_dequeue_state(xhci, udev->slot_id, - ep_index, ep->stopped_stream, td, &deq_state); + ep_index, stream_id, td, &deq_state); if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg) return; @@ -2849,7 +2848,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, "Queueing new dequeue state"); xhci_queue_new_dequeue_state(xhci, udev->slot_id, - ep_index, ep->stopped_stream, &deq_state); + ep_index, &deq_state); } else { /* Better hope no one uses the input context between now and the * reset endpoint completion! @@ -3336,7 +3335,7 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci, * * Wait for the Reset Device command to finish. Remove all structures * associated with the endpoints that were disabled. Clear the input device - * structure? Cache the rings? Reset the control endpoint 0 max packet size? + * structure? Reset the control endpoint 0 max packet size? * * If the virt_dev to be reset does not exist or does not match the udev, * it means the device is lost, possibly due to the xHC restore error and @@ -3466,7 +3465,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, spin_unlock_irqrestore(&xhci->lock, flags); } - /* Everything but endpoint 0 is disabled, so free or cache the rings. */ + /* Everything but endpoint 0 is disabled, so free the rings. */ last_freed_endpoint = 1; for (i = 1; i < 31; i++) { struct xhci_virt_ep *ep = &virt_dev->eps[i]; @@ -3480,7 +3479,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, } if (ep->ring) { - xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); + xhci_free_endpoint_ring(xhci, virt_dev, i); last_freed_endpoint = i; } if (!list_empty(&virt_dev->eps[i].bw_endpoint_list)) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 73a28a986d5e..650a2d9d4aec 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -924,8 +924,6 @@ struct xhci_virt_ep { #define EP_GETTING_NO_STREAMS (1 << 5) /* ---- Related to URB cancellation ---- */ struct list_head cancelled_td_list; - struct xhci_td *stopped_td; - unsigned int stopped_stream; /* Watchdog timer for stop endpoint command to cancel URBs */ struct timer_list stop_cmd_timer; struct xhci_hcd *xhci; @@ -993,10 +991,6 @@ struct xhci_virt_device { struct xhci_container_ctx *out_ctx; /* Used for addressing devices and configuration changes */ struct xhci_container_ctx *in_ctx; - /* Rings saved to ensure old alt settings can be re-instated */ - struct xhci_ring **ring_cache; - int num_rings_cached; -#define XHCI_MAX_RINGS_CACHED 31 struct xhci_virt_ep eps[31]; u8 fake_port; u8 real_port; @@ -1210,6 +1204,11 @@ struct xhci_event_cmd { /* Stop Ring - Transfer State Preserve */ #define TRB_TSP (1<<9) +enum xhci_ep_reset_type { + EP_HARD_RESET, + EP_SOFT_RESET, +}; + /* Force Event */ #define TRB_TO_VF_INTR_TARGET(p) (((p) & (0x3ff << 22)) >> 22) #define TRB_TO_VF_ID(p) (((p) & (0xff << 16)) >> 16) @@ -1527,6 +1526,7 @@ struct xhci_dequeue_state { struct xhci_segment *new_deq_seg; union xhci_trb *new_deq_ptr; int new_cycle_state; + unsigned int stream_id; }; enum xhci_ring_type { @@ -1960,7 +1960,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_trbs, gfp_t flags); -void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, +void xhci_free_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, unsigned int ep_index); struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, @@ -2044,7 +2044,8 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, 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 slot_id, unsigned int ep_index, + enum xhci_ep_reset_type reset_type); 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, @@ -2053,10 +2054,9 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, struct xhci_dequeue_state *state); void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, struct xhci_dequeue_state *deq_state); -void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, - unsigned int ep_index, struct xhci_td *td); +void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, + unsigned int stream_id, struct xhci_td *td); void xhci_stop_endpoint_command_watchdog(unsigned long arg); void xhci_handle_command_timeout(struct work_struct *work); |