diff options
Diffstat (limited to 'drivers/usb/host')
32 files changed, 1152 insertions, 583 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 82800a77550..a8a30b1d416 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -26,6 +26,11 @@ config USB_XHCI_HCD if USB_XHCI_HCD +config USB_XHCI_PCI + tristate + depends on PCI + default y + config USB_XHCI_PLATFORM tristate @@ -126,7 +131,7 @@ config XPS_USB_HCD_XILINX select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO ---help--- - Xilinx xps USB host controller core is EHCI compilant and has + Xilinx xps USB host controller core is EHCI compliant and has transaction translator built-in. It can be configured to either support both high speed and full speed devices, or high speed devices only. @@ -174,6 +179,15 @@ config USB_EHCI_HCD_SPEAR Enables support for the on-chip EHCI controller on ST SPEAr chips. +config USB_EHCI_HCD_STI + tristate "Support for ST STiHxxx on-chip EHCI USB controller" + depends on ARCH_STI && OF + select GENERIC_PHY + select USB_EHCI_HCD_PLATFORM + help + Enable support for the on-chip EHCI controller found on + STMicroelectronics consumer electronics SoC's. + config USB_EHCI_HCD_AT91 tristate "Support for Atmel on-chip EHCI USB controller" depends on USB_EHCI_HCD && ARCH_AT91 @@ -402,6 +416,15 @@ config USB_OHCI_HCD_SPEAR Enables support for the on-chip OHCI controller on ST SPEAr chips. +config USB_OHCI_HCD_STI + tristate "Support for ST STiHxxx on-chip OHCI USB controller" + depends on ARCH_STI && OF + select GENERIC_PHY + select USB_OHCI_HCD_PLATFORM + help + Enable support for the on-chip OHCI controller found on + STMicroelectronics consumer electronics SoC's. + config USB_OHCI_HCD_S3C2410 tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX) @@ -709,7 +732,7 @@ config USB_WHCI_HCD config USB_HWA_HCD tristate "Host Wire Adapter (HWA) driver" - depends on UWB + depends on USB && UWB select USB_WUSB select UWB_HWA help diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 144c038ef70..348c2432156 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -15,22 +15,22 @@ 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 +xhci-plat-hcd-y := xhci-plat.o ifneq ($(CONFIG_USB_XHCI_MVEBU), ) - xhci-hcd-y += xhci-mvebu.o + xhci-plat-hcd-y += xhci-mvebu.o endif ifneq ($(CONFIG_USB_XHCI_RCAR), ) - xhci-hcd-y += xhci-rcar.o -endif + xhci-plat-hcd-y += xhci-rcar.o endif obj-$(CONFIG_USB_WHCI_HCD) += whci/ obj-$(CONFIG_PCI) += pci-quirks.o +obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o +obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o + obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o @@ -38,6 +38,7 @@ 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_HCD_STI) += ehci-st.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 @@ -55,6 +56,7 @@ 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 obj-$(CONFIG_USB_OHCI_HCD_S3C2410) += ohci-s3c2410.o obj-$(CONFIG_USB_OHCI_HCD_LPC32XX) += ohci-nxp.o diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 205f4a33658..cd6d0afb6b8 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -237,7 +237,7 @@ static int bcma_hcd_probe(struct bcma_device *dev) bcma_hcd_init_chip(dev); /* In AI chips EHCI is addrspace 0, OHCI is 1 */ - ohci_addr = dev->addr1; + ohci_addr = dev->addr_s[0]; if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749) && chipinfo->rev == 0) ohci_addr = 0x18009000; diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index cda0a2f5c46..7189f2e32ac 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -21,11 +21,8 @@ #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" @@ -47,9 +44,7 @@ static struct hc_driver __read_mostly exynos_ehci_hc_driver; struct exynos_ehci_hcd { struct clk *clk; - struct usb_phy *phy; - struct usb_otg *otg; - struct phy *phy_g[PHY_NUMBER]; + struct phy *phy[PHY_NUMBER]; }; #define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv) @@ -60,20 +55,9 @@ static int exynos_ehci_get_phy(struct device *dev, 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; - } + int ret; + /* Get PHYs for the controller */ for_each_available_child_of_node(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &phy_number); if (ret) { @@ -89,19 +73,21 @@ static int exynos_ehci_get_phy(struct device *dev, } phy = devm_of_phy_get(dev, child, NULL); + exynos_ehci->phy[phy_number] = phy; 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"); + if (ret == -EPROBE_DEFER) { + return ret; + } else if (ret != -ENOSYS && ret != -ENODEV) { + dev_err(dev, + "Error retrieving usb2 phy: %d\n", ret); return ret; } - dev_dbg(dev, "Failed to get usb2 phy\n"); } - exynos_ehci->phy_g[phy_number] = phy; } - return ret; + return 0; } static int exynos_ehci_phy_enable(struct device *dev) @@ -111,16 +97,13 @@ static int exynos_ehci_phy_enable(struct device *dev) 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 (!IS_ERR(exynos_ehci->phy[i])) + ret = phy_power_on(exynos_ehci->phy[i]); if (ret) for (i--; i >= 0; i--) - if (!IS_ERR(exynos_ehci->phy_g[i])) - phy_power_off(exynos_ehci->phy_g[i]); + if (!IS_ERR(exynos_ehci->phy[i])) + phy_power_off(exynos_ehci->phy[i]); return ret; } @@ -131,14 +114,9 @@ static void exynos_ehci_phy_disable(struct device *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]); + if (!IS_ERR(exynos_ehci->phy[i])) + phy_power_off(exynos_ehci->phy[i]); } static void exynos_setup_vbus_gpio(struct device *dev) @@ -231,9 +209,6 @@ skip_phy: 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"); @@ -273,9 +248,6 @@ static int exynos_ehci_remove(struct platform_device *pdev) 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); @@ -298,9 +270,6 @@ static int exynos_ehci_suspend(struct device *dev) 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); @@ -316,9 +285,6 @@ static int exynos_ehci_resume(struct device *dev) 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"); diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index cf2734b532a..2d2ae8db439 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -136,15 +136,15 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, if (pdata->operating_mode == FSL_USB2_DR_OTG) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2); + hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, phy=0x%p\n", - hcd, ehci, hcd->phy); + hcd, ehci, hcd->usb_phy); - if (!IS_ERR_OR_NULL(hcd->phy)) { - retval = otg_set_host(hcd->phy->otg, + if (!IS_ERR_OR_NULL(hcd->usb_phy)) { + retval = otg_set_host(hcd->usb_phy->otg, &ehci_to_hcd(ehci)->self); if (retval) { - usb_put_phy(hcd->phy); + usb_put_phy(hcd->usb_phy); goto err2; } } else { @@ -181,9 +181,9 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, { 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); - usb_put_phy(hcd->phy); + if (!IS_ERR_OR_NULL(hcd->usb_phy)) { + otg_set_host(hcd->usb_phy->otg, NULL); + usb_put_phy(hcd->usb_phy); } usb_remove_hcd(hcd); @@ -627,7 +627,7 @@ static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port) if (!(status & PORT_CONNECT)) return -ENODEV; - /* khubd will finish the reset later */ + /* hub_wq will finish the reset later */ if (ehci_is_TDI(ehci)) { writel(PORT_RESET | (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)), diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 81cda09b47e..15feaf924b7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -788,7 +788,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) continue; /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to + * and make hub_wq collect PORT_STAT_C_SUSPEND to * stop that signaling. Use 5 ms extra for safety, * like usb_port_resume() does. */ @@ -965,8 +965,6 @@ rescan: } qh->exception = 1; - if (ehci->rh_state < EHCI_RH_RUNNING) - qh->qh_state = QH_STATE_IDLE; switch (qh->qh_state) { case QH_STATE_LINKED: WARN_ON(!list_empty(&qh->qtd_list)); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index cc305c71ac3..5728829cf6e 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -656,7 +656,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) /* * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a + * Otherwise hub_wq wouldn't see the disconnect event when a * high-speed device is switched over to the companion * controller by the user. */ @@ -902,7 +902,7 @@ int ehci_hub_control( /* * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear + * companion controller, hub_wq needs to be able to clear * the port-change status bits (especially * USB_PORT_STAT_C_CONNECTION). */ @@ -922,7 +922,7 @@ int ehci_hub_control( #ifdef CONFIG_USB_OTG if ((hcd->self.otg_port == (wIndex + 1)) && hcd->self.b_hnp_enable) { - otg_start_hnp(hcd->phy->otg); + otg_start_hnp(hcd->usb_phy->otg); break; } #endif @@ -1000,7 +1000,7 @@ int ehci_hub_control( * However, not all EHCI implementations do this * automatically, even if they _do_ support per-port * power switching; they're allowed to just limit the - * current. khubd will turn the power back on. + * current. hub_wq will turn the power back on. */ if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle)) && HCS_PPC(ehci->hcs_params)) { @@ -1085,7 +1085,7 @@ int ehci_hub_control( } /* - * Even if OWNER is set, there's no harm letting khubd + * Even if OWNER is set, there's no harm letting hub_wq * see the wPortStatus values (they should all be 0 except * for PORT_POWER anyway). */ @@ -1230,7 +1230,7 @@ int ehci_hub_control( if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) { spin_unlock_irqrestore(&ehci->lock, flags); retval = ehset_single_step_set_feature(hcd, - wIndex); + wIndex + 1); spin_lock_irqsave(&ehci->lock, flags); break; } diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 934b39d5e44..9dc2118ae80 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -124,7 +124,7 @@ static int ehci_msm_probe(struct platform_device *pdev) goto put_hcd; } - hcd->phy = phy; + hcd->usb_phy = phy; device_init_wakeup(&pdev->dev, 1); /* * OTG device parent of HCD takes care of putting @@ -151,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(hcd->phy->otg, NULL); + otg_set_host(hcd->usb_phy->otg, NULL); /* FIXME: need to call usb_remove_hcd() here? */ diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c new file mode 100644 index 00000000000..7e4bd39cf75 --- /dev/null +++ b/drivers/usb/host/ehci-st.c @@ -0,0 +1,375 @@ +/* + * ST EHCI driver + * + * Copyright (C) 2014 STMicroelectronics – All Rights Reserved + * + * Author: Peter Griffin <peter.griffin@linaro.org> + * + * Derived from ehci-platform.c + * + * 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/clk.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/hrtimer.h> +#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> + +#include "ehci.h" + +#define USB_MAX_CLKS 3 + +struct st_ehci_platform_priv { + struct clk *clks[USB_MAX_CLKS]; + struct clk *clk48; + struct reset_control *rst; + struct reset_control *pwr; + struct phy *phy; +}; + +#define DRIVER_DESC "EHCI STMicroelectronics driver" + +#define hcd_to_ehci_priv(h) \ + ((struct st_ehci_platform_priv *)hcd_to_ehci(h)->priv) + +static const char hcd_name[] = "ehci-st"; + +#define EHCI_CAPS_SIZE 0x10 +#define AHB2STBUS_INSREG01 (EHCI_CAPS_SIZE + 0x84) + +static int st_ehci_platform_reset(struct usb_hcd *hcd) +{ + struct platform_device *pdev = to_platform_device(hcd->self.controller); + struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + u32 threshold; + + /* Set EHCI packet buffer IN/OUT threshold to 128 bytes */ + threshold = 128 | (128 << 16); + writel(threshold, hcd->regs + AHB2STBUS_INSREG01); + + ehci->caps = hcd->regs + pdata->caps_offset; + retval = ehci_setup(hcd); + if (retval) + return retval; + + return 0; +} + +static int st_ehci_platform_power_on(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct st_ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + int clk, ret; + + ret = reset_control_deassert(priv->pwr); + if (ret) + return ret; + + ret = reset_control_deassert(priv->rst); + if (ret) + goto err_assert_power; + + /* some SoCs don't have a dedicated 48Mhz clock, but those that do + need the rate to be explicitly set */ + if (priv->clk48) { + ret = clk_set_rate(priv->clk48, 48000000); + if (ret) + goto err_assert_reset; + } + + for (clk = 0; clk < USB_MAX_CLKS && priv->clks[clk]; clk++) { + ret = clk_prepare_enable(priv->clks[clk]); + if (ret) + goto err_disable_clks; + } + + 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]); +err_assert_reset: + reset_control_assert(priv->rst); +err_assert_power: + reset_control_assert(priv->pwr); + + return ret; +} + +static void st_ehci_platform_power_off(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct st_ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + int clk; + + reset_control_assert(priv->pwr); + + reset_control_assert(priv->rst); + + phy_power_off(priv->phy); + + phy_exit(priv->phy); + + for (clk = USB_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 = st_ehci_platform_reset, + .extra_priv_size = sizeof(struct st_ehci_platform_priv), +}; + +static struct usb_ehci_pdata ehci_platform_defaults = { + .power_on = st_ehci_platform_power_on, + .power_suspend = st_ehci_platform_power_off, + .power_off = st_ehci_platform_power_off, +}; + +static int st_ehci_platform_probe(struct platform_device *dev) +{ + struct usb_hcd *hcd; + struct resource *res_mem; + struct usb_ehci_pdata *pdata = &ehci_platform_defaults; + struct st_ehci_platform_priv *priv; + struct ehci_hcd *ehci; + int err, irq, clk = 0; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + dev_err(&dev->dev, "no irq provided"); + return irq; + } + res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res_mem) { + dev_err(&dev->dev, "no memory resource provided"); + 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); + + priv->phy = devm_phy_get(&dev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); + goto err_put_hcd; + } + + for (clk = 0; clk < USB_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; + } + } + + /* some SoCs don't have a dedicated 48Mhz clock, but those that + do need the rate to be explicitly set */ + priv->clk48 = devm_clk_get(&dev->dev, "clk48"); + if (IS_ERR(priv->clk48)) { + dev_info(&dev->dev, "48MHz clk not found\n"); + priv->clk48 = NULL; + } + + priv->pwr = devm_reset_control_get_optional(&dev->dev, "power"); + if (IS_ERR(priv->pwr)) { + err = PTR_ERR(priv->pwr); + if (err == -EPROBE_DEFER) + goto err_put_clks; + priv->pwr = NULL; + } + + priv->rst = devm_reset_control_get_optional(&dev->dev, "softreset"); + if (IS_ERR(priv->rst)) { + err = PTR_ERR(priv->rst); + if (err == -EPROBE_DEFER) + goto err_put_clks; + priv->rst = NULL; + } + + if (pdata->power_on) { + err = pdata->power_on(dev); + if (err < 0) + goto err_put_clks; + } + + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); + + hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); + if (IS_ERR(hcd->regs)) { + err = PTR_ERR(hcd->regs); + goto err_put_clks; + } + + err = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (err) + goto err_put_clks; + + device_wakeup_enable(hcd->self.controller); + platform_set_drvdata(dev, hcd); + + return err; + +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; +} + +static int st_ehci_platform_remove(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); + struct st_ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + int clk; + + usb_remove_hcd(hcd); + + if (pdata->power_off) + pdata->power_off(dev); + + for (clk = 0; clk < USB_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; + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int st_ehci_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + 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); + + pinctrl_pm_select_sleep_state(dev); + + return ret; +} + +static int st_ehci_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct usb_ehci_pdata *pdata = dev_get_platdata(dev); + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + int err; + + pinctrl_pm_select_default_state(dev); + + if (pdata->power_on) { + err = pdata->power_on(pdev); + if (err < 0) + return err; + } + + ehci_resume(hcd, false); + return 0; +} + +static SIMPLE_DEV_PM_OPS(st_ehci_pm_ops, st_ehci_suspend, st_ehci_resume); + +#endif /* CONFIG_PM_SLEEP */ + +static const struct of_device_id st_ehci_ids[] = { + { .compatible = "st,st-ehci-300x", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, st_ehci_ids); + +static struct platform_driver ehci_platform_driver = { + .probe = st_ehci_platform_probe, + .remove = st_ehci_platform_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "st-ehci", +#ifdef CONFIG_PM_SLEEP + .pm = &st_ehci_pm_ops, +#endif + .of_match_table = st_ehci_ids, + } +}; + +static int __init ehci_platform_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); + return platform_driver_register(&ehci_platform_driver); +} +module_init(ehci_platform_init); + +static void __exit ehci_platform_cleanup(void) +{ + platform_driver_unregister(&ehci_platform_driver); +} +module_exit(ehci_platform_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 7aafb05e7a4..aaa01971efe 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -206,7 +206,7 @@ static int tegra_ehci_hub_control( if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { /* Resume completed, re-enable disconnect detection */ tegra->port_resuming = 0; - tegra_usb_phy_postresume(hcd->phy); + tegra_usb_phy_postresume(hcd->usb_phy); } } @@ -259,7 +259,7 @@ static int tegra_ehci_hub_control( goto done; /* Disable disconnect detection during port resume */ - tegra_usb_phy_preresume(hcd->phy); + tegra_usb_phy_preresume(hcd->usb_phy); ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); @@ -454,7 +454,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) err = PTR_ERR(u_phy); goto cleanup_clk_en; } - hcd->phy = u_phy; + hcd->usb_phy = u_phy; tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, "nvidia,needs-double-reset"); @@ -475,7 +475,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) ehci->caps = hcd->regs + 0x100; ehci->has_hostpc = soc_config->has_hostpc; - err = usb_phy_init(hcd->phy); + err = usb_phy_init(hcd->usb_phy); if (err) { dev_err(&pdev->dev, "Failed to initialize phy\n"); goto cleanup_clk_en; @@ -490,7 +490,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) } u_phy->otg->host = hcd_to_bus(hcd); - err = usb_phy_set_suspend(hcd->phy, 0); + err = usb_phy_set_suspend(hcd->usb_phy, 0); if (err) { dev_err(&pdev->dev, "Failed to power on the phy\n"); goto cleanup_phy; @@ -517,7 +517,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) cleanup_otg_set_host: otg_set_host(u_phy->otg, NULL); cleanup_phy: - usb_phy_shutdown(hcd->phy); + usb_phy_shutdown(hcd->usb_phy); cleanup_clk_en: clk_disable_unprepare(tegra->clk); cleanup_hcd_create: @@ -531,9 +531,9 @@ static int tegra_ehci_remove(struct platform_device *pdev) struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; - otg_set_host(hcd->phy->otg, NULL); + otg_set_host(hcd->usb_phy->otg, NULL); - usb_phy_shutdown(hcd->phy); + usb_phy_shutdown(hcd->usb_phy); usb_remove_hcd(hcd); clk_disable_unprepare(tegra->clk); diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index fe57710753e..a2328361dc8 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -31,6 +31,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_address.h> +#include <linux/of_irq.h> /** * ehci_xilinx_port_handed_over - hand the port out if failed to enable it diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 1cf68eaf2ed..a1a1ef52143 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -360,12 +360,12 @@ static int fhci_start(struct usb_hcd *hcd) hcd->state = HC_STATE_RUNNING; /* - * From here on, khubd concurrently accesses the root + * From here on, hub_wq concurrently accesses the root * hub; drivers will be talking to enumerated devices. - * (On restart paths, khubd already knows about the root + * (On restart paths, hub_wq already knows about the root * hub and could find work as soon as we wrote FLAG_CF.) * - * Before this point the HC was idle/ready. After, khubd + * Before this point the HC was idle/ready. After, hub_wq * and device drivers may start it running. */ fhci_usb_enable(fhci); diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index adcd2050dce..3de1278677d 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -1483,7 +1483,7 @@ fotg210_hub_status_data(struct usb_hcd *hcd, char *buf) /* * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a + * Otherwise hub_wq wouldn't see the disconnect event when a * high-speed device is switched over to the companion * controller by the user. */ @@ -1572,7 +1572,7 @@ static int fotg210_hub_control( /* * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear + * companion controller, hub_wq needs to be able to clear * the port-change status bits (especially * USB_PORT_STAT_C_CONNECTION). */ @@ -1723,7 +1723,7 @@ static int fotg210_hub_control( } /* - * Even if OWNER is set, there's no harm letting khubd + * Even if OWNER is set, there's no harm letting hub_wq * see the wPortStatus values (they should all be 0 except * for PORT_POWER anyway). */ @@ -5445,7 +5445,7 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd) fotg210->reset_done[0] == 0) { /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to + * and make hub_wq collect PORT_STAT_C_SUSPEND to * stop that signaling. Use 5 ms extra for safety, * like usb_port_resume() does. */ diff --git a/drivers/usb/host/fusbh200-hcd.c b/drivers/usb/host/fusbh200-hcd.c index ba9499060f6..abe42f31559 100644 --- a/drivers/usb/host/fusbh200-hcd.c +++ b/drivers/usb/host/fusbh200-hcd.c @@ -1441,7 +1441,7 @@ fusbh200_hub_status_data (struct usb_hcd *hcd, char *buf) /* * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a + * Otherwise hub_wq wouldn't see the disconnect event when a * high-speed device is switched over to the companion * controller by the user. */ @@ -1530,7 +1530,7 @@ static int fusbh200_hub_control ( /* * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear + * companion controller, hub_wq needs to be able to clear * the port-change status bits (especially * USB_PORT_STAT_C_CONNECTION). */ @@ -1678,7 +1678,7 @@ static int fusbh200_hub_control ( } /* - * Even if OWNER is set, there's no harm letting khubd + * Even if OWNER is set, there's no harm letting hub_wq * see the wPortStatus values (they should all be 0 except * for PORT_POWER anyway). */ @@ -5355,7 +5355,7 @@ static irqreturn_t fusbh200_irq (struct usb_hcd *hcd) fusbh200->reset_done[0] == 0) { /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to + * and make hub_wq collect PORT_STAT_C_SUSPEND to * stop that signaling. Use 5 ms extra for safety, * like usb_port_resume() does. */ diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 875bcfd3ec1..4bb37982855 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2616,30 +2616,10 @@ static int isp1362_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - struct resource *res; remove_debug_file(isp1362_hcd); DBG(0, "%s: Removing HCD\n", __func__); usb_remove_hcd(hcd); - - DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, - isp1362_hcd->data_reg); - iounmap(isp1362_hcd->data_reg); - - DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, - isp1362_hcd->addr_reg); - iounmap(isp1362_hcd->addr_reg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - DBG(0, "%s: release mem_region: %08lx\n", __func__, (long unsigned int)res->start); - if (res) - release_mem_region(res->start, resource_size(res)); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - DBG(0, "%s: release mem_region: %08lx\n", __func__, (long unsigned int)res->start); - if (res) - release_mem_region(res->start, resource_size(res)); - DBG(0, "%s: put_hcd\n", __func__); usb_put_hcd(hcd); DBG(0, "%s: Done\n", __func__); @@ -2651,12 +2631,11 @@ static int isp1362_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct isp1362_hcd *isp1362_hcd; - struct resource *addr, *data; + struct resource *addr, *data, *irq_res; void __iomem *addr_reg; void __iomem *data_reg; int irq; int retval = 0; - struct resource *irq_res; unsigned int irq_flags = 0; if (usb_disabled()) @@ -2667,52 +2646,35 @@ static int isp1362_probe(struct platform_device *pdev) * specific platform_data. we don't probe for IRQs, and do only * minimal sanity checking. */ - if (pdev->num_resources < 3) { - retval = -ENODEV; - goto err1; - } - - data = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!addr || !data || !irq_res) { - retval = -ENODEV; - goto err1; - } - irq = irq_res->start; + if (pdev->num_resources < 3) + return -ENODEV; if (pdev->dev.dma_mask) { DBG(1, "won't do DMA"); - retval = -ENODEV; - goto err1; + return -ENODEV; } - if (!request_mem_region(addr->start, resource_size(addr), hcd_name)) { - retval = -EBUSY; - goto err1; - } - addr_reg = ioremap(addr->start, resource_size(addr)); - if (addr_reg == NULL) { - retval = -ENOMEM; - goto err2; - } + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq_res) + return -ENODEV; - if (!request_mem_region(data->start, resource_size(data), hcd_name)) { - retval = -EBUSY; - goto err3; - } - data_reg = ioremap(data->start, resource_size(data)); - if (data_reg == NULL) { - retval = -ENOMEM; - goto err4; - } + irq = irq_res->start; + + addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); + addr_reg = devm_ioremap_resource(&pdev->dev, addr); + if (IS_ERR(addr_reg)) + return PTR_ERR(addr_reg); + + data = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data_reg = devm_ioremap_resource(&pdev->dev, data); + if (IS_ERR(data_reg)) + return PTR_ERR(data_reg); /* allocate and initialize hcd */ hcd = usb_create_hcd(&isp1362_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err5; - } + if (!hcd) + return -ENOMEM; + hcd->rsrc_start = data->start; isp1362_hcd = hcd_to_isp1362_hcd(hcd); isp1362_hcd->data_reg = data_reg; @@ -2729,7 +2691,7 @@ static int isp1362_probe(struct platform_device *pdev) if (!isp1362_hcd->board->delay) { dev_err(hcd->self.controller, "No platform delay function given\n"); retval = -ENODEV; - goto err6; + goto err; } #endif @@ -2744,32 +2706,17 @@ static int isp1362_probe(struct platform_device *pdev) retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_SHARED); if (retval != 0) - goto err6; + goto err; device_wakeup_enable(hcd->self.controller); - pr_info("%s, irq %d\n", hcd->product_desc, irq); + dev_info(&pdev->dev, "%s, irq %d\n", hcd->product_desc, irq); create_debug_file(isp1362_hcd); return 0; - err6: - DBG(0, "%s: Freeing dev %p\n", __func__, isp1362_hcd); + err: usb_put_hcd(hcd); - err5: - DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, data_reg); - iounmap(data_reg); - err4: - DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start); - release_mem_region(data->start, resource_size(data)); - err3: - DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg); - iounmap(addr_reg); - err2: - DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start); - release_mem_region(addr->start, resource_size(addr)); - err1: - pr_err("%s: init error, %d\n", __func__, retval); return retval; } diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 51a0ae9cdd1..e752c3098f3 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1760,7 +1760,7 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) /* * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a + * Otherwise hub_wq wouldn't see the disconnect event when a * high-speed device is switched over to the companion * controller by the user. */ @@ -1871,7 +1871,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, /* * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear + * companion controller, hub_wq needs to be able to clear * the port-change status bits (especially * USB_PORT_STAT_C_CONNECTION). */ @@ -2000,7 +2000,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, reg_read32(hcd->regs, HC_PORTSC1)); } /* - * Even if OWNER is set, there's no harm letting khubd + * Even if OWNER is set, there's no harm letting hub_wq * see the wPortStatus values (they should all be 0 except * for PORT_POWER anyway). */ diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index a72ab8fe8cd..d28b6583ba0 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -19,11 +19,8 @@ #include <linux/of.h> #include <linux/platform_device.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" @@ -38,9 +35,7 @@ static struct hc_driver __read_mostly exynos_ohci_hc_driver; struct exynos_ohci_hcd { struct clk *clk; - struct usb_phy *phy; - struct usb_otg *otg; - struct phy *phy_g[PHY_NUMBER]; + struct phy *phy[PHY_NUMBER]; }; static int exynos_ohci_get_phy(struct device *dev, @@ -49,30 +44,9 @@ static int exynos_ohci_get_phy(struct device *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; - } + int ret; - /* - * 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. - */ + /* Get PHYs for the controller */ for_each_available_child_of_node(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &phy_number); if (ret) { @@ -88,19 +62,21 @@ static int exynos_ohci_get_phy(struct device *dev, } phy = devm_of_phy_get(dev, child, NULL); + exynos_ohci->phy[phy_number] = phy; 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"); + if (ret == -EPROBE_DEFER) { + return ret; + } else if (ret != -ENOSYS && ret != -ENODEV) { + dev_err(dev, + "Error retrieving usb2 phy: %d\n", ret); return ret; } - dev_dbg(dev, "Failed to get usb2 phy\n"); } - exynos_ohci->phy_g[phy_number] = phy; } - return ret; + return 0; } static int exynos_ohci_phy_enable(struct device *dev) @@ -110,16 +86,13 @@ static int exynos_ohci_phy_enable(struct device *dev) 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 (!IS_ERR(exynos_ohci->phy[i])) + ret = phy_power_on(exynos_ohci->phy[i]); if (ret) for (i--; i >= 0; i--) - if (!IS_ERR(exynos_ohci->phy_g[i])) - phy_power_off(exynos_ohci->phy_g[i]); + if (!IS_ERR(exynos_ohci->phy[i])) + phy_power_off(exynos_ohci->phy[i]); return ret; } @@ -130,14 +103,9 @@ static void exynos_ohci_phy_disable(struct device *dev) struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); int i; - if (!IS_ERR(exynos_ohci->phy)) { - usb_phy_shutdown(exynos_ohci->phy); - return; - } - for (i = 0; i < PHY_NUMBER; i++) - if (!IS_ERR(exynos_ohci->phy_g[i])) - phy_power_off(exynos_ohci->phy_g[i]); + if (!IS_ERR(exynos_ohci->phy[i])) + phy_power_off(exynos_ohci->phy[i]); } static int exynos_ohci_probe(struct platform_device *pdev) @@ -209,9 +177,6 @@ skip_phy: goto fail_io; } - if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - platform_set_drvdata(pdev, hcd); err = exynos_ohci_phy_enable(&pdev->dev); @@ -244,9 +209,6 @@ static int exynos_ohci_remove(struct platform_device *pdev) usb_remove_hcd(hcd); - if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - exynos_ohci_phy_disable(&pdev->dev); clk_disable_unprepare(exynos_ohci->clk); @@ -275,9 +237,6 @@ static int exynos_ohci_suspend(struct device *dev) if (rc) return rc; - if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - exynos_ohci_phy_disable(dev); clk_disable_unprepare(exynos_ohci->clk); @@ -293,9 +252,6 @@ static int exynos_ohci_resume(struct device *dev) clk_prepare_enable(exynos_ohci->clk); - if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); - ret = exynos_ohci_phy_enable(dev); if (ret) { dev_err(dev, "Failed to enable USB phy\n"); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 46987735a2e..d664edabf14 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -632,7 +632,7 @@ retry: return -EOVERFLOW; } - /* use rhsc irqs after khubd is fully initialized */ + /* use rhsc irqs after hub_wq is allocated */ set_bit(HCD_FLAG_POLL_RH, &hcd->flags); hcd->uses_new_polling = 1; @@ -909,8 +909,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) * choices for RHSC. Many followed the spec; RHSC triggers * on an edge, like setting and maybe clearing a port status * change bit. With others it's level-triggered, active - * until khubd clears all the port status change bits. We'll - * always disable it here and rely on polling until khubd + * until hub_wq clears all the port status change bits. We'll + * always disable it here and rely on polling until hub_wq * re-enables it. */ ohci_writel(ohci, OHCI_INTR_RHSC, ®s->intrdisable); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 17d32b0ea56..0aa17c93711 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -585,7 +585,7 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port) if (!(status & RH_PS_CCS)) return -ENODEV; - /* khubd will finish the reset later */ + /* hub_wq will finish the reset later */ ohci_writel(ohci, RH_PS_PRS, &ohci->regs->roothub.portstatus [port]); return 0; } @@ -610,7 +610,7 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port) /* wrap-aware logic morphed from <linux/jiffies.h> */ #define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) -/* called from some task, normally khubd */ +/* called from some task, normally hub_wq */ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) { __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index c923cafcaca..0231606d47c 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -180,10 +180,10 @@ static void start_hnp(struct ohci_hcd *ohci) unsigned long flags; u32 l; - otg_start_hnp(hcd->phy->otg); + otg_start_hnp(hcd->usb_phy->otg); local_irq_save(flags); - hcd->phy->state = OTG_STATE_A_SUSPEND; + hcd->usb_phy->state = OTG_STATE_A_SUSPEND; writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]); l = omap_readl(OTG_CTRL); l &= ~OTG_A_BUSREQ; @@ -220,14 +220,14 @@ static int ohci_omap_reset(struct usb_hcd *hcd) #ifdef CONFIG_USB_OTG if (need_transceiver) { - hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2); - if (!IS_ERR_OR_NULL(hcd->phy)) { - int status = otg_set_host(hcd->phy->otg, + hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); + if (!IS_ERR_OR_NULL(hcd->usb_phy)) { + int status = otg_set_host(hcd->usb_phy->otg, &ohci_to_hcd(ohci)->self); dev_dbg(hcd->self.controller, "init %s phy, status %d\n", - hcd->phy->label, status); + hcd->usb_phy->label, status); if (status) { - usb_put_phy(hcd->phy); + usb_put_phy(hcd->usb_phy); return status; } } else { @@ -283,7 +283,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) ohci_to_hcd(ohci)->power_budget = 0; } - /* FIXME khubd hub requests should manage power switching */ + /* FIXME hub_wq hub requests should manage power switching */ omap_ohci_transceiver_power(1); /* board init will have already handled HMC and mux setup. @@ -399,9 +399,9 @@ 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); + if (!IS_ERR_OR_NULL(hcd->usb_phy)) { + (void) otg_set_host(hcd->usb_phy->otg, 0); + usb_put_phy(hcd->usb_phy); } if (machine_is_omap_osk()) gpio_free(9); diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c new file mode 100644 index 00000000000..df9028e0d9b --- /dev/null +++ b/drivers/usb/host/ohci-st.c @@ -0,0 +1,349 @@ +/* + * ST OHCI driver + * + * Copyright (C) 2014 STMicroelectronics – All Rights Reserved + * + * Author: Peter Griffin <peter.griffin@linaro.org> + * + * Derived from ohci-platform.c + * + * 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/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 USB_MAX_CLKS 3 + +struct st_ohci_platform_priv { + struct clk *clks[USB_MAX_CLKS]; + struct clk *clk48; + struct reset_control *rst; + struct reset_control *pwr; + struct phy *phy; +}; + +#define DRIVER_DESC "OHCI STMicroelectronics driver" + +#define hcd_to_ohci_priv(h) \ + ((struct st_ohci_platform_priv *)hcd_to_ohci(h)->priv) + +static const char hcd_name[] = "ohci-st"; + +static int st_ohci_platform_power_on(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct st_ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); + int clk, ret; + + ret = reset_control_deassert(priv->pwr); + if (ret) + return ret; + + ret = reset_control_deassert(priv->rst); + if (ret) + goto err_assert_power; + + /* some SoCs don't have a dedicated 48Mhz clock, but those that do + need the rate to be explicitly set */ + if (priv->clk48) { + ret = clk_set_rate(priv->clk48, 48000000); + if (ret) + goto err_assert_reset; + } + + for (clk = 0; clk < USB_MAX_CLKS && priv->clks[clk]; clk++) { + ret = clk_prepare_enable(priv->clks[clk]); + if (ret) + goto err_disable_clks; + } + + 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]); +err_assert_reset: + reset_control_assert(priv->rst); +err_assert_power: + reset_control_assert(priv->pwr); + + return ret; +} + +static void st_ohci_platform_power_off(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct st_ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); + + int clk; + + reset_control_assert(priv->pwr); + + reset_control_assert(priv->rst); + + phy_power_off(priv->phy); + + phy_exit(priv->phy); + + for (clk = USB_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 = "ST OHCI controller", + .extra_priv_size = sizeof(struct st_ohci_platform_priv), +}; + +static struct usb_ohci_pdata ohci_platform_defaults = { + .power_on = st_ohci_platform_power_on, + .power_suspend = st_ohci_platform_power_off, + .power_off = st_ohci_platform_power_off, +}; + +static int st_ohci_platform_probe(struct platform_device *dev) +{ + struct usb_hcd *hcd; + struct resource *res_mem; + struct usb_ohci_pdata *pdata = &ohci_platform_defaults; + struct st_ohci_platform_priv *priv; + struct ohci_hcd *ohci; + int err, irq, clk = 0; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + dev_err(&dev->dev, "no irq provided"); + return irq; + } + + res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res_mem) { + dev_err(&dev->dev, "no memory resource provided"); + 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); + + priv->phy = devm_phy_get(&dev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); + goto err_put_hcd; + } + + for (clk = 0; clk < USB_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; + } + } + + /* some SoCs don't have a dedicated 48Mhz clock, but those that + do need the rate to be explicitly set */ + priv->clk48 = devm_clk_get(&dev->dev, "clk48"); + if (IS_ERR(priv->clk48)) { + dev_info(&dev->dev, "48MHz clk not found\n"); + priv->clk48 = NULL; + } + + priv->pwr = devm_reset_control_get_optional(&dev->dev, "power"); + if (IS_ERR(priv->pwr)) { + err = PTR_ERR(priv->pwr); + goto err_put_clks; + } + + priv->rst = devm_reset_control_get_optional(&dev->dev, "softreset"); + if (IS_ERR(priv->rst)) { + err = PTR_ERR(priv->rst); + goto err_put_clks; + } + + if (pdata->power_on) { + err = pdata->power_on(dev); + if (err < 0) + goto err_power; + } + + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); + + hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); + if (IS_ERR(hcd->regs)) { + err = PTR_ERR(hcd->regs); + goto err_power; + } + err = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (err) + goto err_power; + + device_wakeup_enable(hcd->self.controller); + + platform_set_drvdata(dev, hcd); + + return err; + +err_power: + if (pdata->power_off) + pdata->power_off(dev); + +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; +} + +static int st_ohci_platform_remove(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); + struct st_ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); + int clk; + + usb_remove_hcd(hcd); + + if (pdata->power_off) + pdata->power_off(dev); + + + for (clk = 0; clk < USB_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; +} + +#ifdef CONFIG_PM_SLEEP + +static int st_ohci_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 ret; +} + +static int st_ohci_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct usb_ohci_pdata *pdata = dev_get_platdata(dev); + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + int err; + + if (pdata->power_on) { + err = pdata->power_on(pdev); + if (err < 0) + return err; + } + + ohci_resume(hcd, false); + return 0; +} + +static SIMPLE_DEV_PM_OPS(st_ohci_pm_ops, st_ohci_suspend, st_ohci_resume); + +#endif /* CONFIG_PM_SLEEP */ + +static const struct of_device_id st_ohci_platform_ids[] = { + { .compatible = "st,st-ohci-300x", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, st_ohci_platform_ids); + +static struct platform_driver ohci_platform_driver = { + .probe = st_ohci_platform_probe, + .remove = st_ohci_platform_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "st-ohci", +#ifdef CONFIG_PM_SLEEP + .pm = &st_ohci_pm_ops, +#endif + .of_match_table = st_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("Peter Griffin <peter.griffin@linaro.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index da5fb0e3c36..4fe79a2d71a 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2046,7 +2046,7 @@ static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh) /* simple/paranoid: always delay, expecting the HC needs to read * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and - * expect khubd to clean up after any CSPLITs we won't issue. + * expect hub_wq to clean up after any CSPLITs we won't issue. * active high speed queues may need bigger delays... */ if (list_empty(&qh->qtd_list) @@ -2501,7 +2501,7 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd) continue; /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to + * and make hub_wq collect PORT_STAT_C_SUSPEND to * stop that signaling. */ oxu->reset_done[i] = jiffies + msecs_to_jiffies(20); @@ -3119,7 +3119,7 @@ static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf) /* * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a + * Otherwise hub_wq wouldn't see the disconnect event when a * high-speed device is switched over to the companion * controller by the user. */ @@ -3194,7 +3194,7 @@ static int oxu_hub_control(struct usb_hcd *hcd, u16 typeReq, /* * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear + * companion controller, hub_wq needs to be able to clear * the port-change status bits (especially * USB_PORT_STAT_C_CONNECTION). */ @@ -3336,7 +3336,7 @@ static int oxu_hub_control(struct usb_hcd *hcd, u16 typeReq, } /* - * Even if OWNER is set, there's no harm letting khubd + * Even if OWNER is set, there's no harm letting hub_wq * see the wPortStatus values (they should all be 0 except * for PORT_POWER anyway). */ diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index a517151867a..ad0c348e68e 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -674,7 +674,7 @@ retry: sl811->next_periodic = sl811->periodic[index]; } - /* khubd manages debouncing and wakeup */ + /* hub_wq manages debouncing and wakeup */ if (irqstat & SL11H_INTMASK_INSRMV) { sl811->stat_insrmv++; @@ -714,7 +714,7 @@ retry: #endif /* port status seems weird until after reset, so - * force the reset and make khubd clean up later. + * force the reset and make hub_wq clean up later. */ if (irqstat & SL11H_INTMASK_RD) sl811->port1 &= ~USB_PORT_STAT_CONNECTION; @@ -1079,7 +1079,7 @@ sl811h_hub_status_data(struct usb_hcd *hcd, char *buf) if (!(sl811->port1 & (0xffff << 16))) return 0; - /* tell khubd port 1 changed */ + /* tell hub_wq port 1 changed */ *buf = (1 << 1); return 1; } @@ -1196,7 +1196,7 @@ sl811h_timer(unsigned long _sl811) sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), SL11H_HCTLMASK_ARM); - /* khubd provides debounce delay */ + /* hub_wq provides debounce delay */ } else { sl811->ctrl1 = 0; } diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index eb009a457fb..bb89175ca6e 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -594,3 +594,4 @@ void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *), trace(&vaf); va_end(args); } +EXPORT_SYMBOL_GPL(xhci_dbg_trace); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index aa79e874904..696160d48ae 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -319,12 +319,19 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) */ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) { - int i; + int i, s; + struct xhci_virt_ep *ep; + + for (i = 0; i < LAST_EP_INDEX + 1; i++) { + ep = &xhci->devs[slot_id]->eps[i]; - for (i = 0; i < LAST_EP_INDEX + 1; i++) - if (xhci->devs[slot_id]->eps[i].ring && - xhci->devs[slot_id]->eps[i].ring->dequeue) + if (ep->ep_state & EP_HAS_STREAMS) { + for (s = 1; s < ep->stream_info->num_streams; s++) + xhci_ring_ep_doorbell(xhci, slot_id, i, s); + } else if (ep->ring && ep->ring->dequeue) { xhci_ring_ep_doorbell(xhci, slot_id, i, 0); + } + } return; } @@ -468,7 +475,8 @@ static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg) } /* Updates Link Status for super Speed port */ -static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg) +static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci, + u32 *status, u32 status_reg) { u32 pls = status_reg & PORT_PLS_MASK; @@ -507,7 +515,8 @@ static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg) * in which sometimes the port enters compliance mode * caused by a delay on the host-device negotiation. */ - if (pls == USB_SS_PORT_LS_COMP_MOD) + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && + (pls == USB_SS_PORT_LS_COMP_MOD)) pls |= USB_PORT_STAT_CONNECTION; } @@ -666,7 +675,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, } /* Update Port Link State */ if (hcd->speed == HCD_USB3) { - xhci_hub_report_usb3_link_state(&status, raw_port_status); + xhci_hub_report_usb3_link_state(xhci, &status, raw_port_status); /* * Verify if all USB3 Ports Have entered U0 already. * Delete Compliance Mode Timer if so. @@ -890,7 +899,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* * Turn on ports, even if there isn't per-port switching. * HC will report connect events even before this is set. - * However, khubd will ignore the roothub events until + * However, hub_wq will ignore the roothub events until * the roothub is registered. */ writel(temp | PORT_POWER, port_array[wIndex]); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8056d90690e..5cb3d7a1001 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1812,6 +1812,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) if (xhci->lpm_command) xhci_free_command(xhci, xhci->lpm_command); + xhci->lpm_command = NULL; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; @@ -1819,7 +1820,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_cleanup_command_queue(xhci); num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - for (i = 0; i < num_ports; i++) { + for (i = 0; i < num_ports && xhci->rh_bw; 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; @@ -1903,7 +1904,7 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci, start_dma = xhci_trb_virt_to_dma(input_seg, start_trb); end_dma = xhci_trb_virt_to_dma(input_seg, end_trb); - seg = trb_in_td(input_seg, start_trb, end_trb, input_dma); + seg = trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, false); if (seg != result_seg) { xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n", test_name, test_number); @@ -1917,6 +1918,8 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci, end_trb, end_dma); xhci_warn(xhci, "Expected seg %p, got seg %p\n", result_seg, seg); + trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, + true); return -1; } return 0; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 687d3660815..280dde93abe 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -40,6 +40,8 @@ static const char hcd_name[] = "xhci_hcd"; +static struct hc_driver __read_mostly xhci_pci_hc_driver; + /* called after powerup, by probe or system-pm "wakeup" */ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) { @@ -101,6 +103,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; + + if (pdev->vendor == PCI_VENDOR_ID_AMD) + xhci->quirks |= XHCI_TRUST_TX_LENGTH; + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_INTEL_HOST; @@ -151,6 +157,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; + /* See https://bugzilla.kernel.org/show_bug.cgi?id=79511 */ + if (pdev->vendor == PCI_VENDOR_ID_VIA && + pdev->device == 0x3432) + xhci->quirks |= XHCI_BROKEN_STREAMS; + if (xhci->quirks & XHCI_RESET_ON_RESUME) xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "QUIRK: Resetting on resume"); @@ -277,7 +288,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) * Systems with the TI redriver that loses port status change events * need to have the registers polled during D3, so avoid D3cold. */ - if (xhci_compliance_mode_recovery_timer_quirk_check()) + if (xhci->quirks & XHCI_COMP_MODE_QUIRK) pdev->no_d3cold = true; return xhci_suspend(xhci); @@ -315,68 +326,6 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) } #endif /* CONFIG_PM */ -static const struct hc_driver xhci_pci_hc_driver = { - .description = hcd_name, - .product_desc = "xHCI Host Controller", - .hcd_priv_size = sizeof(struct xhci_hcd *), - - /* - * generic hardware linkage - */ - .irq = xhci_irq, - .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, - - /* - * basic lifecycle operations - */ - .reset = xhci_pci_setup, - .start = xhci_run, -#ifdef CONFIG_PM - .pci_suspend = xhci_pci_suspend, - .pci_resume = xhci_pci_resume, -#endif - .stop = xhci_stop, - .shutdown = xhci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = xhci_urb_enqueue, - .urb_dequeue = xhci_urb_dequeue, - .alloc_dev = xhci_alloc_dev, - .free_dev = xhci_free_dev, - .alloc_streams = xhci_alloc_streams, - .free_streams = xhci_free_streams, - .add_endpoint = xhci_add_endpoint, - .drop_endpoint = xhci_drop_endpoint, - .endpoint_reset = xhci_endpoint_reset, - .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, - - /* - * scheduling support - */ - .get_frame_number = xhci_get_frame, - - /* Root hub support */ - .hub_control = xhci_hub_control, - .hub_status_data = xhci_hub_status_data, - .bus_suspend = xhci_bus_suspend, - .bus_resume = xhci_bus_resume, - /* - * call back when device connected and addressed - */ - .update_device = xhci_update_device, - .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm, - .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, - .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, - .find_raw_port_number = xhci_find_raw_port_number, -}; - /*-------------------------------------------------------------------------*/ /* PCI driver selection metadata; PCI hotplugging uses this */ @@ -406,12 +355,22 @@ static struct pci_driver xhci_pci_driver = { #endif }; -int __init xhci_register_pci(void) +static int __init xhci_pci_init(void) { + xhci_init_driver(&xhci_pci_hc_driver, xhci_pci_setup); +#ifdef CONFIG_PM + xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend; + xhci_pci_hc_driver.pci_resume = xhci_pci_resume; +#endif return pci_register_driver(&xhci_pci_driver); } +module_init(xhci_pci_init); -void xhci_unregister_pci(void) +static void __exit xhci_pci_exit(void) { pci_unregister_driver(&xhci_pci_driver); } +module_exit(xhci_pci_exit); + +MODULE_DESCRIPTION("xHCI PCI Host Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 1a0cf9f31e4..3d78b0cd674 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -23,6 +23,8 @@ #include "xhci-mvebu.h" #include "xhci-rcar.h" +static struct hc_driver __read_mostly xhci_plat_hc_driver; + static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { /* @@ -60,59 +62,6 @@ 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", - .hcd_priv_size = sizeof(struct xhci_hcd *), - - /* - * generic hardware linkage - */ - .irq = xhci_irq, - .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, - - /* - * basic lifecycle operations - */ - .reset = xhci_plat_setup, - .start = xhci_plat_start, - .stop = xhci_stop, - .shutdown = xhci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = xhci_urb_enqueue, - .urb_dequeue = xhci_urb_dequeue, - .alloc_dev = xhci_alloc_dev, - .free_dev = xhci_free_dev, - .alloc_streams = xhci_alloc_streams, - .free_streams = xhci_free_streams, - .add_endpoint = xhci_add_endpoint, - .drop_endpoint = xhci_drop_endpoint, - .endpoint_reset = xhci_endpoint_reset, - .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, - - /* - * scheduling support - */ - .get_frame_number = xhci_get_frame, - - /* Root hub support */ - .hub_control = xhci_hub_control, - .hub_status_data = xhci_hub_status_data, - .bus_suspend = xhci_bus_suspend, - .bus_resume = xhci_bus_resume, - - .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, - .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, -}; - static int xhci_plat_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -128,7 +77,7 @@ static int xhci_plat_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; - driver = &xhci_plat_xhci_driver; + driver = &xhci_plat_hc_driver; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -298,12 +247,19 @@ static struct platform_driver usb_xhci_driver = { }; MODULE_ALIAS("platform:xhci-hcd"); -int xhci_register_plat(void) +static int __init xhci_plat_init(void) { + xhci_init_driver(&xhci_plat_hc_driver, xhci_plat_setup); + xhci_plat_hc_driver.start = xhci_plat_start; return platform_driver_register(&usb_xhci_driver); } +module_init(xhci_plat_init); -void xhci_unregister_plat(void) +static void __exit xhci_plat_exit(void) { platform_driver_unregister(&usb_xhci_driver); } +module_exit(xhci_plat_exit); + +MODULE_DESCRIPTION("xHCI Platform Host Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 60fb52ae864..bc6fcbc16f6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -327,7 +327,6 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, * We don't want to restart any stream rings if there's a set dequeue * pointer command pending because the device can choose to start any * stream once the endpoint is on the HW schedule. - * FIXME - check all the stream rings for pending cancellations. */ if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) || (ep_state & EP_HALTED)) @@ -364,32 +363,6 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci, } } -/* - * Find the segment that trb is in. Start searching in start_seg. - * If we must move past a segment that has a link TRB with a toggle cycle state - * bit set, then we will toggle the value pointed at by cycle_state. - */ -static struct xhci_segment *find_trb_seg( - struct xhci_segment *start_seg, - union xhci_trb *trb, int *cycle_state) -{ - struct xhci_segment *cur_seg = start_seg; - struct xhci_generic_trb *generic_trb; - - while (cur_seg->trbs > trb || - &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) { - generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic; - if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE)) - *cycle_state ^= 0x1; - cur_seg = cur_seg->next; - if (cur_seg == start_seg) - /* Looped over the entire list. Oops! */ - return NULL; - } - return cur_seg; -} - - static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id) @@ -459,9 +432,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, 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_segment *new_seg; + union xhci_trb *new_deq; dma_addr_t addr; u64 hw_dequeue; + bool cycle_found = false; + bool td_last_trb_found = false; ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id, ep_index, stream_id); @@ -486,45 +462,45 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, 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; - } - } + new_seg = ep_ring->deq_seg; + new_deq = ep_ring->dequeue; + state->new_cycle_state = hw_dequeue & 0x1; + /* - * 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. + * We want to find the pointer, segment and cycle state of the new trb + * (the one after current TD's last_trb). We know the cycle state at + * hw_dequeue, so walk the ring until both hw_dequeue and last_trb are + * found. */ - 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; + do { + if (!cycle_found && xhci_trb_virt_to_dma(new_seg, new_deq) + == (dma_addr_t)(hw_dequeue & ~0xf)) { + cycle_found = true; + if (td_last_trb_found) + break; + } + if (new_deq == cur_td->last_trb) + td_last_trb_found = true; - state->new_deq_ptr = cur_td->last_trb; - 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); - if (!state->new_deq_seg) { - WARN_ON(1); - return; - } + if (cycle_found && + TRB_TYPE_LINK_LE32(new_deq->generic.field[3]) && + new_deq->generic.field[3] & cpu_to_le32(LINK_TOGGLE)) + state->new_cycle_state ^= 0x1; + + next_trb(xhci, ep_ring, &new_seg, &new_deq); - /* 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); + /* Search wrapped around, bail out */ + if (new_deq == ep->ring->dequeue) { + xhci_err(xhci, "Error: Failed finding new dequeue state\n"); + state->new_deq_seg = NULL; + state->new_deq_ptr = NULL; + return; + } + + } while (!cycle_found || !td_last_trb_found); + + state->new_deq_seg = new_seg; + state->new_deq_ptr = new_deq; /* Don't update the ring cycle state for the producer (us). */ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, @@ -595,40 +571,6 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } } -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_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, cmd, slot_id, ep_index, stream_id, - deq_state->new_deq_seg, - deq_state->new_deq_ptr, - (u32) deq_state->new_cycle_state); - /* Stop the TD queueing code from ringing the doorbell until - * this command completes. The HC won't set the dequeue pointer - * if the ring is running, and ringing the doorbell starts the - * ring running. - */ - ep->ep_state |= SET_DEQ_PENDING; -} - static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) { @@ -766,12 +708,8 @@ remove_finished_td: /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { - 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); + xhci_queue_new_dequeue_state(xhci, slot_id, ep_index, + ep->stopped_td->urb->stream_id, &deq_state); xhci_ring_cmd_db(xhci); } else { /* Otherwise ring the doorbell(s) to restart queued transfers */ @@ -1026,8 +964,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, 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; - return; + goto cleanup; } ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); @@ -1092,6 +1029,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, } } +cleanup: dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; dev->eps[ep_index].queued_deq_seg = NULL; dev->eps[ep_index].queued_deq_ptr = NULL; @@ -1722,10 +1660,12 @@ cleanup: * TRB in this TD, this function returns that TRB's segment. Otherwise it * returns 0. */ -struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, +struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, + struct xhci_segment *start_seg, union xhci_trb *start_trb, union xhci_trb *end_trb, - dma_addr_t suspect_dma) + dma_addr_t suspect_dma, + bool debug) { dma_addr_t start_dma; dma_addr_t end_seg_dma; @@ -1744,6 +1684,15 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, /* If the end TRB isn't in this segment, this is set to 0 */ end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb); + if (debug) + xhci_warn(xhci, + "Looking for event-dma %016llx trb-start %016llx trb-end %016llx seg-start %016llx seg-end %016llx\n", + (unsigned long long)suspect_dma, + (unsigned long long)start_dma, + (unsigned long long)end_trb_dma, + (unsigned long long)cur_seg->dma, + (unsigned long long)end_seg_dma); + if (end_trb_dma > 0) { /* The end TRB is in this segment, so suspect should be here */ if (start_dma <= end_trb_dma) { @@ -2476,8 +2425,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, td_num--; /* Is this a TRB in the currently executing TD? */ - event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, - td->last_trb, event_dma); + event_seg = trb_in_td(xhci, ep_ring->deq_seg, ep_ring->dequeue, + td->last_trb, event_dma, false); /* * Skip the Force Stopped Event. The event_trb(event_dma) of FSE @@ -2487,7 +2436,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, * last TRB of the previous TD. The command completion handle * will take care the rest. */ - if (!event_seg && trb_comp_code == COMP_STOP_INVAL) { + if (!event_seg && (trb_comp_code == COMP_STOP || + trb_comp_code == COMP_STOP_INVAL)) { ret = 0; goto cleanup; } @@ -2508,7 +2458,12 @@ static int handle_tx_event(struct xhci_hcd *xhci, /* HC is busted, give up! */ xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not " - "part of current TD\n"); + "part of current TD ep_index %d " + "comp_code %u\n", ep_index, + trb_comp_code); + trb_in_td(xhci, ep_ring->deq_seg, + ep_ring->dequeue, td->last_trb, + event_dma, true); return -ESHUTDOWN; } @@ -3948,14 +3903,11 @@ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, 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, 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) +/* 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); @@ -3964,28 +3916,59 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, struct xhci_command *cmd, u32 trb_sct = 0; u32 type = TRB_TYPE(TRB_SET_DEQ); struct xhci_virt_ep *ep; + struct xhci_command *cmd; + int ret; - addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); + 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); + + addr = xhci_trb_virt_to_dma(deq_state->new_deq_seg, + deq_state->new_deq_ptr); if (addr == 0) { xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n", - deq_seg, deq_ptr); - return 0; + deq_state->new_deq_seg, deq_state->new_deq_ptr); + return; } ep = &xhci->devs[slot_id]->eps[ep_index]; if ((ep->ep_state & SET_DEQ_PENDING)) { xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); xhci_warn(xhci, "A Set TR Deq Ptr command is pending.\n"); - return 0; + return; } - ep->queued_deq_seg = deq_seg; - ep->queued_deq_ptr = deq_ptr; + + /* This function gets called from contexts where it cannot sleep */ + cmd = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + if (!cmd) { + xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr: ENOMEM\n"); + return; + } + + ep->queued_deq_seg = deq_state->new_deq_seg; + ep->queued_deq_ptr = deq_state->new_deq_ptr; 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); + ret = queue_command(xhci, cmd, + lower_32_bits(addr) | trb_sct | deq_state->new_cycle_state, + upper_32_bits(addr), trb_stream_id, + trb_slot_id | trb_ep_index | type, false); + if (ret < 0) { + xhci_free_command(xhci, cmd); + return; + } + + /* Stop the TD queueing code from ringing the doorbell until + * this command completes. The HC won't set the dequeue pointer + * if the ring is running, and ringing the doorbell starts the + * ring running. + */ + ep->ep_state |= SET_DEQ_PENDING; } int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c index 7cf30c83dcf..367b630bdb3 100644 --- a/drivers/usb/host/xhci-trace.c +++ b/drivers/usb/host/xhci-trace.c @@ -13,3 +13,5 @@ #define CREATE_TRACE_POINTS #include "xhci-trace.h" + +EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_quirks); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index b6f21175b87..2a5d45b4cb1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -491,7 +491,7 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) * Systems: * Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820 */ -bool xhci_compliance_mode_recovery_timer_quirk_check(void) +static bool xhci_compliance_mode_recovery_timer_quirk_check(void) { const char *dmi_product_name, *dmi_sys_vendor; @@ -653,6 +653,7 @@ int xhci_run(struct usb_hcd *hcd) "Finished xhci_run for USB2 roothub"); return 0; } +EXPORT_SYMBOL_GPL(xhci_run); static void xhci_only_stop_hcd(struct usb_hcd *hcd) { @@ -871,6 +872,8 @@ int xhci_suspend(struct xhci_hcd *xhci) xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); del_timer_sync(&hcd->rh_timer); + clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + del_timer_sync(&xhci->shared_hcd->rh_timer); spin_lock_irq(&xhci->lock); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -927,6 +930,7 @@ int xhci_suspend(struct xhci_hcd *xhci) return rc; } +EXPORT_SYMBOL_GPL(xhci_suspend); /* * start xHC (not bus-specific) @@ -1075,9 +1079,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "%s: starting port polling.\n", __func__); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); usb_hcd_poll_rh_status(hcd); + set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + usb_hcd_poll_rh_status(xhci->shared_hcd); return retval; } +EXPORT_SYMBOL_GPL(xhci_resume); #endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -2880,18 +2887,16 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, ep_index, ep->stopped_stream, ep->stopped_td, &deq_state); + if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg) + return; + /* HW with the reset endpoint quirk will use the saved dequeue state to * issue a configure endpoint command later. */ if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) { - 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, + xhci_queue_new_dequeue_state(xhci, udev->slot_id, ep_index, ep->stopped_stream, &deq_state); } else { /* Better hope no one uses the input context between now and the @@ -3758,8 +3763,8 @@ disable_slot: /* * 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 should be protected by the usb_address0_mutex in hub_wq's hub_port_init, + * so we should only issue and wait on one address command at the same time. */ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, enum xhci_setup_dev setup) @@ -3968,13 +3973,21 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, int ret; spin_lock_irqsave(&xhci->lock, flags); - if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) { + + virt_dev = xhci->devs[udev->slot_id]; + + /* + * virt_dev might not exists yet if xHC resumed from hibernate (S4) and + * xHC was re-initialized. Exit latency will be set later after + * hub_port_finish_reset() is done and xhci->devs[] are re-allocated + */ + + if (!virt_dev || max_exit_latency == virt_dev->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) { @@ -4892,6 +4905,76 @@ error: kfree(xhci); return retval; } +EXPORT_SYMBOL_GPL(xhci_gen_setup); + +static const struct hc_driver xhci_hc_driver = { + .description = "xhci-hcd", + .product_desc = "xHCI Host Controller", + .hcd_priv_size = sizeof(struct xhci_hcd *), + + /* + * generic hardware linkage + */ + .irq = xhci_irq, + .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, + + /* + * basic lifecycle operations + */ + .reset = NULL, /* set in xhci_init_driver() */ + .start = xhci_run, + .stop = xhci_stop, + .shutdown = xhci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = xhci_urb_enqueue, + .urb_dequeue = xhci_urb_dequeue, + .alloc_dev = xhci_alloc_dev, + .free_dev = xhci_free_dev, + .alloc_streams = xhci_alloc_streams, + .free_streams = xhci_free_streams, + .add_endpoint = xhci_add_endpoint, + .drop_endpoint = xhci_drop_endpoint, + .endpoint_reset = xhci_endpoint_reset, + .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, + + /* + * scheduling support + */ + .get_frame_number = xhci_get_frame, + + /* + * root hub support + */ + .hub_control = xhci_hub_control, + .hub_status_data = xhci_hub_status_data, + .bus_suspend = xhci_bus_suspend, + .bus_resume = xhci_bus_resume, + + /* + * call back when device connected and addressed + */ + .update_device = xhci_update_device, + .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm, + .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, + .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, + .find_raw_port_number = xhci_find_raw_port_number, +}; + +void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *)) +{ + BUG_ON(!setup_fn); + *drv = xhci_hc_driver; + drv->reset = setup_fn; +} +EXPORT_SYMBOL_GPL(xhci_init_driver); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR(DRIVER_AUTHOR); @@ -4899,18 +4982,6 @@ MODULE_LICENSE("GPL"); static int __init xhci_hcd_init(void) { - int retval; - - retval = xhci_register_pci(); - if (retval < 0) { - pr_debug("Problem registering PCI driver.\n"); - return retval; - } - retval = xhci_register_plat(); - if (retval < 0) { - pr_debug("Problem registering platform driver.\n"); - goto unreg_pci; - } /* * Check the compiler generated sizes of structures that must be laid * out in specific ways for hardware access. @@ -4929,15 +5000,5 @@ static int __init xhci_hcd_init(void) /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); return 0; -unreg_pci: - xhci_unregister_pci(); - return retval; } module_init(xhci_hcd_init); - -static void __exit xhci_hcd_cleanup(void) -{ - xhci_unregister_pci(); - xhci_unregister_plat(); -} -module_exit(xhci_hcd_cleanup); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index dace5152e17..df76d642e71 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1731,25 +1731,6 @@ void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv); void xhci_free_command(struct xhci_hcd *xhci, struct xhci_command *command); -#ifdef CONFIG_PCI -/* xHCI PCI glue */ -int xhci_register_pci(void); -void xhci_unregister_pci(void); -#else -static inline int xhci_register_pci(void) { return 0; } -static inline void xhci_unregister_pci(void) {} -#endif - -#if IS_ENABLED(CONFIG_USB_XHCI_PLATFORM) -int xhci_register_plat(void); -void xhci_unregister_plat(void); -#else -static inline int xhci_register_plat(void) -{ return 0; } -static inline void xhci_unregister_plat(void) -{ } -#endif - /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr, @@ -1762,6 +1743,7 @@ int xhci_run(struct usb_hcd *hcd); void xhci_stop(struct usb_hcd *hcd); void xhci_shutdown(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); +void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *)); #ifdef CONFIG_PM int xhci_suspend(struct xhci_hcd *xhci); @@ -1804,9 +1786,9 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); /* xHCI ring, segment, TRB, and TD functions */ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); -struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, - union xhci_trb *start_trb, union xhci_trb *end_trb, - dma_addr_t suspect_dma); +struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, + struct xhci_segment *start_seg, union xhci_trb *start_trb, + union xhci_trb *end_trb, dma_addr_t suspect_dma, bool debug); 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, struct xhci_command *cmd, @@ -1839,7 +1821,6 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, 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); @@ -1887,7 +1868,4 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); -/* xHCI quirks */ -bool xhci_compliance_mode_recovery_timer_quirk_check(void); - #endif /* __LINUX_XHCI_HCD_H */ |