diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
commit | 597473720f4dc69749542bfcfed4a927a43d935e (patch) | |
tree | 711bf773910fb93d1dd9120c633adc807685e0d8 /drivers/usb | |
parent | f0dd687815f9546860fc3ac4379d55da045942c9 (diff) | |
parent | 593fdd4fb44ef2cbf4ec53ec2c6eb60eb079bb4c (diff) |
Merge branch 'next' into for-linus
Prepare input updates for 5.3 merge window.
Diffstat (limited to 'drivers/usb')
230 files changed, 3363 insertions, 1850 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 987fc5ba6321..e4b27413f528 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB device configuration # @@ -205,8 +206,4 @@ config USB_ULPI_BUS To compile this driver as a module, choose M here: the module will be called ulpi. -config USB_ROLE_SWITCH - tristate - select USB_COMMON - endif # USB_SUPPORT diff --git a/drivers/usb/README b/drivers/usb/README deleted file mode 100644 index 2144e7dbfa41..000000000000 --- a/drivers/usb/README +++ /dev/null @@ -1,54 +0,0 @@ -To understand all the Linux-USB framework, you'll use these resources: - - * This source code. This is necessarily an evolving work, and - includes kerneldoc that should help you get a current overview. - ("make pdfdocs", and then look at "usb.pdf" for host side and - "gadget.pdf" for peripheral side.) Also, Documentation/usb has - more information. - - * The USB 2.0 specification (from www.usb.org), with supplements - such as those for USB OTG and the various device classes. - The USB specification has a good overview chapter, and USB - peripherals conform to the widely known "Chapter 9". - - * Chip specifications for USB controllers. Examples include - host controllers (on PCs, servers, and more); peripheral - controllers (in devices with Linux firmware, like printers or - cell phones); and hard-wired peripherals like Ethernet adapters. - - * Specifications for other protocols implemented by USB peripheral - functions. Some are vendor-specific; others are vendor-neutral - but just standardized outside of the www.usb.org team. - -Here is a list of what each subdirectory here is, and what is contained in -them. - -core/ - This is for the core USB host code, including the - usbfs files and the hub class driver ("hub_wq"). - -host/ - This is for USB host controller drivers. This - includes UHCI, OHCI, EHCI, and others that might - be used with more specialized "embedded" systems. - -gadget/ - This is for USB peripheral controller drivers and - the various gadget drivers which talk to them. - - -Individual USB driver directories. A new driver should be added to the -first subdirectory in the list below that it fits into. - -image/ - This is for still image drivers, like scanners or - digital cameras. -../input/ - This is for any driver that uses the input subsystem, - like keyboard, mice, touchscreens, tablets, etc. -../media/ - This is for multimedia drivers, like video cameras, - radios, and any other drivers that talk to the v4l - subsystem. -../net/ - This is for network drivers. -serial/ - This is for USB to serial drivers. -storage/ - This is for USB mass-storage drivers. -class/ - This is for all USB device drivers that do not fit - into any of the above categories, and work for a range - of USB Class specified devices. -misc/ - This is for all USB device drivers that do not fit - into any of the above categories. diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index 0f922942a07a..989aaa3b080d 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB/ATM DSL configuration # diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index ee34e9046f7e..eb37ebfcb123 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_CHIPIDEA tristate "ChipIdea Highspeed Dual Role Controller" depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 09b37c0d075d..ceec8d5985d4 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -7,13 +7,12 @@ #include <linux/module.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/dma-mapping.h> #include <linux/usb/chipidea.h> #include <linux/usb/of.h> #include <linux/clk.h> +#include <linux/pinctrl/consumer.h> #include "ci.h" #include "ci_hdrc_imx.h" @@ -85,6 +84,9 @@ struct ci_hdrc_imx_data { bool supports_runtime_pm; bool override_phy_control; bool in_lpm; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_hsic_active; + struct regulator *hsic_pad_regulator; /* SoC before i.mx6 (except imx23/imx28) needs three clks */ bool need_three_clks; struct clk *clk_ipg; @@ -132,14 +134,24 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) data->dev = &misc_pdev->dev; - if (of_find_property(np, "disable-over-current", NULL)) + /* + * Check the various over current related properties. If over current + * detection is disabled we're not interested in the polarity. + */ + if (of_find_property(np, "disable-over-current", NULL)) { data->disable_oc = 1; + } else if (of_find_property(np, "over-current-active-high", NULL)) { + data->oc_pol_active_low = 0; + data->oc_pol_configured = 1; + } else if (of_find_property(np, "over-current-active-low", NULL)) { + data->oc_pol_active_low = 1; + data->oc_pol_configured = 1; + } else { + dev_warn(dev, "No over current polarity defined\n"); + } - if (of_find_property(np, "over-current-active-high", NULL)) - data->oc_polarity = 1; - - if (of_find_property(np, "external-vbus-divider", NULL)) - data->evdo = 1; + data->pwr_pol = of_property_read_bool(np, "power-active-high"); + data->evdo = of_property_read_bool(np, "external-vbus-divider"); if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) data->ulpi = 1; @@ -245,19 +257,49 @@ static void imx_disable_unprepare_clks(struct device *dev) } } +static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) +{ + struct device *dev = ci->dev->parent; + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + int ret = 0; + + switch (event) { + case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: + ret = pinctrl_select_state(data->pinctrl, + data->pinctrl_hsic_active); + if (ret) + dev_err(dev, "hsic_active select failed, err=%d\n", + ret); + break; + case CI_HDRC_IMX_HSIC_SUSPEND_EVENT: + ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data); + if (ret) + dev_err(dev, + "hsic_set_connect failed, err=%d\n", ret); + break; + default: + break; + } + + return ret; +} + static int ci_hdrc_imx_probe(struct platform_device *pdev) { struct ci_hdrc_imx_data *data; struct ci_hdrc_platform_data pdata = { .name = dev_name(&pdev->dev), .capoffset = DEF_CAPOFFSET, + .notify_event = ci_hdrc_imx_notify_event, }; int ret; const struct of_device_id *of_id; const struct ci_hdrc_imx_platform_flag *imx_platform_flag; struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct pinctrl_state *pinctrl_hsic_idle; - of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); + of_id = of_match_device(ci_hdrc_imx_dt_ids, dev); if (!of_id) return -ENODEV; @@ -268,19 +310,74 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, data); - data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); + data->usbmisc_data = usbmisc_get_init_data(dev); if (IS_ERR(data->usbmisc_data)) return PTR_ERR(data->usbmisc_data); - ret = imx_get_clks(&pdev->dev); + if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) + && data->usbmisc_data) { + pdata.flags |= CI_HDRC_IMX_IS_HSIC; + data->usbmisc_data->hsic = 1; + data->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(data->pinctrl)) { + dev_err(dev, "pinctrl get failed, err=%ld\n", + PTR_ERR(data->pinctrl)); + return PTR_ERR(data->pinctrl); + } + + pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); + if (IS_ERR(pinctrl_hsic_idle)) { + dev_err(dev, + "pinctrl_hsic_idle lookup failed, err=%ld\n", + PTR_ERR(pinctrl_hsic_idle)); + return PTR_ERR(pinctrl_hsic_idle); + } + + ret = pinctrl_select_state(data->pinctrl, pinctrl_hsic_idle); + if (ret) { + dev_err(dev, "hsic_idle select failed, err=%d\n", ret); + return ret; + } + + data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl, + "active"); + if (IS_ERR(data->pinctrl_hsic_active)) { + dev_err(dev, + "pinctrl_hsic_active lookup failed, err=%ld\n", + PTR_ERR(data->pinctrl_hsic_active)); + return PTR_ERR(data->pinctrl_hsic_active); + } + + data->hsic_pad_regulator = devm_regulator_get(dev, "hsic"); + if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { + /* no pad regualator is needed */ + data->hsic_pad_regulator = NULL; + } else if (IS_ERR(data->hsic_pad_regulator)) { + dev_err(dev, "Get HSIC pad regulator error: %ld\n", + PTR_ERR(data->hsic_pad_regulator)); + return PTR_ERR(data->hsic_pad_regulator); + } + + if (data->hsic_pad_regulator) { + ret = regulator_enable(data->hsic_pad_regulator); + if (ret) { + dev_err(dev, + "Failed to enable HSIC pad regulator\n"); + return ret; + } + } + } + ret = imx_get_clks(dev); if (ret) - return ret; + goto disable_hsic_regulator; - ret = imx_prepare_enable_clks(&pdev->dev); + ret = imx_prepare_enable_clks(dev); if (ret) - return ret; + goto disable_hsic_regulator; - data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0); + data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0); if (IS_ERR(data->phy)) { ret = PTR_ERR(data->phy); /* Return -EINVAL if no usbphy is available */ @@ -305,40 +402,43 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) ret = imx_usbmisc_init(data->usbmisc_data); if (ret) { - dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); + dev_err(dev, "usbmisc init failed, ret=%d\n", ret); goto err_clk; } - data->ci_pdev = ci_hdrc_add_device(&pdev->dev, + data->ci_pdev = ci_hdrc_add_device(dev, pdev->resource, pdev->num_resources, &pdata); if (IS_ERR(data->ci_pdev)) { ret = PTR_ERR(data->ci_pdev); if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "ci_hdrc_add_device failed, err=%d\n", ret); + dev_err(dev, "ci_hdrc_add_device failed, err=%d\n", + ret); goto err_clk; } ret = imx_usbmisc_init_post(data->usbmisc_data); if (ret) { - dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret); + dev_err(dev, "usbmisc post failed, ret=%d\n", ret); goto disable_device; } if (data->supports_runtime_pm) { - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); } - device_set_wakeup_capable(&pdev->dev, true); + device_set_wakeup_capable(dev, true); return 0; disable_device: ci_hdrc_remove_device(data->ci_pdev); err_clk: - imx_disable_unprepare_clks(&pdev->dev); + imx_disable_unprepare_clks(dev); +disable_hsic_regulator: + if (data->hsic_pad_regulator) + ret = regulator_disable(data->hsic_pad_regulator); return ret; } @@ -355,6 +455,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) if (data->override_phy_control) usb_phy_shutdown(data->phy); imx_disable_unprepare_clks(&pdev->dev); + if (data->hsic_pad_regulator) + regulator_disable(data->hsic_pad_regulator); return 0; } @@ -367,9 +469,16 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev) static int __maybe_unused imx_controller_suspend(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + int ret = 0; dev_dbg(dev, "at %s\n", __func__); + ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false); + if (ret) { + dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); + return ret; + } + imx_disable_unprepare_clks(dev); data->in_lpm = true; @@ -400,8 +509,16 @@ static int __maybe_unused imx_controller_resume(struct device *dev) goto clk_disable; } + ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true); + if (ret) { + dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); + goto hsic_set_clk_fail; + } + return 0; +hsic_set_clk_fail: + imx_usbmisc_set_wakeup(data->usbmisc_data, true); clk_disable: imx_disable_unprepare_clks(dev); return ret; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 204275f47573..c842e03f8767 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -11,13 +11,23 @@ struct imx_usbmisc_data { int index; unsigned int disable_oc:1; /* over current detect disabled */ - unsigned int oc_polarity:1; /* over current polarity if oc enabled */ + + /* true if over-current polarity is active low */ + unsigned int oc_pol_active_low:1; + + /* true if dt specifies polarity */ + unsigned int oc_pol_configured:1; + + unsigned int pwr_pol:1; /* power polarity */ unsigned int evdo:1; /* set external vbus divider option */ unsigned int ulpi:1; /* connected to an ULPI phy */ + unsigned int hsic:1; /* HSIC controlller */ }; -int imx_usbmisc_init(struct imx_usbmisc_data *); -int imx_usbmisc_init_post(struct imx_usbmisc_data *); -int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *, bool); +int imx_usbmisc_init(struct imx_usbmisc_data *data); +int imx_usbmisc_init_post(struct imx_usbmisc_data *data); +int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled); +int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data); +int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on); #endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */ diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 772851bee99b..12025358bb3c 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -130,6 +130,7 @@ static int tegra_udc_remove(struct platform_device *pdev) { struct tegra_udc *udc = platform_get_drvdata(pdev); + ci_hdrc_remove_device(udc->dev); usb_phy_set_suspend(udc->phy, 1); clk_disable_unprepare(udc->clk); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 7bfcbb23c2a4..27749ace2d93 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -954,25 +954,47 @@ static int ci_hdrc_probe(struct platform_device *pdev) } else if (ci->platdata->usb_phy) { ci->usb_phy = ci->platdata->usb_phy; } else { + /* Look for a generic PHY first */ ci->phy = devm_phy_get(dev->parent, "usb-phy"); - ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2); - /* if both generic PHY and USB PHY layers aren't enabled */ - if (PTR_ERR(ci->phy) == -ENOSYS && - PTR_ERR(ci->usb_phy) == -ENXIO) { - ret = -ENXIO; + if (PTR_ERR(ci->phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; goto ulpi_exit; + } else if (IS_ERR(ci->phy)) { + ci->phy = NULL; } - if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) { - ret = -EPROBE_DEFER; - goto ulpi_exit; + /* Look for a legacy USB PHY from device-tree next */ + if (!ci->phy) { + ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent, + "phys", 0); + + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } else if (IS_ERR(ci->usb_phy)) { + ci->usb_phy = NULL; + } } - if (IS_ERR(ci->phy)) - ci->phy = NULL; - else if (IS_ERR(ci->usb_phy)) - ci->usb_phy = NULL; + /* Look for any registered legacy USB PHY as last resort */ + if (!ci->phy && !ci->usb_phy) { + ci->usb_phy = devm_usb_get_phy(dev->parent, + USB_PHY_TYPE_USB2); + + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } else if (IS_ERR(ci->usb_phy)) { + ci->usb_phy = NULL; + } + } + + /* No USB PHY was found in the end */ + if (!ci->phy && !ci->usb_phy) { + ret = -ENXIO; + goto ulpi_exit; + } } ret = ci_usb_phy_init(ci); diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index d858a82c4f44..b45ceb91c735 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -170,6 +170,11 @@ static int host_start(struct ci_hdrc *ci) otg->host = &hcd->self; hcd->self.otg_port = 1; } + + if (ci->platdata->notify_event && + (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC)) + ci->platdata->notify_event + (ci, CI_HDRC_IMX_HSIC_ACTIVE_EVENT); } return ret; @@ -215,9 +220,85 @@ void ci_hdrc_host_destroy(struct ci_hdrc *ci) host_stop(ci); } +/* The below code is based on tegra ehci driver */ +static int ci_ehci_hub_control( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + u32 __iomem *status_reg; + u32 temp; + unsigned long flags; + int retval = 0; + struct device *dev = hcd->self.controller; + struct ci_hdrc *ci = dev_get_drvdata(dev); + + status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; + + spin_lock_irqsave(&ehci->lock, flags); + + if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { + temp = ehci_readl(ehci, status_reg); + if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) { + retval = -EPIPE; + goto done; + } + + temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E); + temp |= PORT_WKDISC_E | PORT_WKOC_E; + ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); + + /* + * If a transaction is in progress, there may be a delay in + * suspending the port. Poll until the port is suspended. + */ + if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, + PORT_SUSPEND, 5000)) + ehci_err(ehci, "timeout waiting for SUSPEND\n"); + + if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) { + if (ci->platdata->notify_event) + ci->platdata->notify_event(ci, + CI_HDRC_IMX_HSIC_SUSPEND_EVENT); + + temp = ehci_readl(ehci, status_reg); + temp &= ~(PORT_WKDISC_E | PORT_WKCONN_E); + ehci_writel(ehci, temp, status_reg); + } + + set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); + goto done; + } + + /* + * After resume has finished, it needs do some post resume + * operation for some SoCs. + */ + else if (typeReq == ClearPortFeature && + wValue == USB_PORT_FEAT_C_SUSPEND) { + /* Make sure the resume has finished, it should be finished */ + if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 25000)) + ehci_err(ehci, "timeout waiting for resume\n"); + } + + spin_unlock_irqrestore(&ehci->lock, flags); + + /* Handle the hub control events here */ + return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); +done: + spin_unlock_irqrestore(&ehci->lock, flags); + return retval; +} static int ci_ehci_bus_suspend(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct device *dev = hcd->self.controller; + struct ci_hdrc *ci = dev_get_drvdata(dev); int port; u32 tmp; @@ -249,6 +330,16 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd) * It needs a short delay between set RS bit and PHCD. */ usleep_range(150, 200); + /* + * Need to clear WKCN and WKOC for imx HSIC, + * otherwise, there will be wakeup event. + */ + if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) { + tmp = ehci_readl(ehci, reg); + tmp &= ~(PORT_WKDISC_E | PORT_WKCONN_E); + ehci_writel(ehci, tmp, reg); + } + break; } } @@ -281,4 +372,5 @@ void ci_hdrc_host_driver_init(void) ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides); orig_bus_suspend = ci_ehci_hc_driver.bus_suspend; ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend; + ci_ehci_hc_driver.hub_control = ci_ehci_hub_control; } diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index def80ff547e4..d8b67e150b12 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -63,11 +63,24 @@ #define MX6_BM_NON_BURST_SETTING BIT(1) #define MX6_BM_OVER_CUR_DIS BIT(7) #define MX6_BM_OVER_CUR_POLARITY BIT(8) +#define MX6_BM_PWR_POLARITY BIT(9) #define MX6_BM_WAKEUP_ENABLE BIT(10) +#define MX6_BM_UTMI_ON_CLOCK BIT(13) #define MX6_BM_ID_WAKEUP BIT(16) #define MX6_BM_VBUS_WAKEUP BIT(17) #define MX6SX_BM_DPDM_WAKEUP_EN BIT(29) #define MX6_BM_WAKEUP_INTR BIT(31) + +#define MX6_USB_HSIC_CTRL_OFFSET 0x10 +/* Send resume signal without 480Mhz PHY clock */ +#define MX6SX_BM_HSIC_AUTO_RESUME BIT(23) +/* set before portsc.suspendM = 1 */ +#define MX6_BM_HSIC_DEV_CONN BIT(21) +/* HSIC enable */ +#define MX6_BM_HSIC_EN BIT(12) +/* Force HSIC module 480M clock on, even when in Host is in suspend mode */ +#define MX6_BM_HSIC_CLK_ON BIT(11) + #define MX6_USB_OTG1_PHY_CTRL 0x18 /* For imx6dql, it is host-only controller, for later imx6, it is otg's */ #define MX6_USB_OTG2_PHY_CTRL 0x1c @@ -94,6 +107,10 @@ struct usbmisc_ops { int (*post)(struct imx_usbmisc_data *data); /* It's called when we need to enable/disable usb wakeup */ int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled); + /* It's called before setting portsc.suspendM */ + int (*hsic_set_connect)(struct imx_usbmisc_data *data); + /* It's called during suspend/resume */ + int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled); }; struct imx_usbmisc { @@ -120,6 +137,14 @@ static int usbmisc_imx25_init(struct imx_usbmisc_data *data) val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT); val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT); + + /* + * If the polarity is not configured assume active high for + * historical reasons. + */ + if (data->oc_pol_configured && data->oc_pol_active_low) + val &= ~MX25_OTG_OCPOL_BIT; + writel(val, usbmisc->base); break; case 1: @@ -129,6 +154,13 @@ static int usbmisc_imx25_init(struct imx_usbmisc_data *data) val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT); + /* + * If the polarity is not configured assume active high for + * historical reasons. + */ + if (data->oc_pol_configured && data->oc_pol_active_low) + val &= ~MX25_H1_OCPOL_BIT; + writel(val, usbmisc->base); break; @@ -340,12 +372,21 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) reg = readl(usbmisc->base + data->index * 4); if (data->disable_oc) { reg |= MX6_BM_OVER_CUR_DIS; - } else if (data->oc_polarity == 1) { - /* High active */ - reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); } else { - reg &= ~(MX6_BM_OVER_CUR_DIS); + reg &= ~MX6_BM_OVER_CUR_DIS; + + /* + * If the polarity is not configured keep it as setup by the + * bootloader. + */ + if (data->oc_pol_configured && data->oc_pol_active_low) + reg |= MX6_BM_OVER_CUR_POLARITY; + else if (data->oc_pol_configured) + reg &= ~MX6_BM_OVER_CUR_POLARITY; } + /* If the polarity is not set keep it as setup by the bootlader */ + if (data->pwr_pol == 1) + reg |= MX6_BM_PWR_POLARITY; writel(reg, usbmisc->base + data->index * 4); /* SoC non-burst setting */ @@ -353,6 +394,18 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base + data->index * 4); + /* For HSIC controller */ + if (data->hsic) { + reg = readl(usbmisc->base + data->index * 4); + writel(reg | MX6_BM_UTMI_ON_CLOCK, + usbmisc->base + data->index * 4); + reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON; + writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + } + spin_unlock_irqrestore(&usbmisc->lock, flags); usbmisc_imx6q_set_wakeup(data, false); @@ -360,6 +413,79 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) return 0; } +static int usbmisc_imx6_hsic_get_reg_offset(struct imx_usbmisc_data *data) +{ + int offset, ret = 0; + + if (data->index == 2 || data->index == 3) { + offset = (data->index - 2) * 4; + } else if (data->index == 0) { + /* + * For SoCs like i.MX7D and later, each USB controller has + * its own non-core register region. For SoCs before i.MX7D, + * the first two USB controllers are non-HSIC controllers. + */ + offset = 0; + } else { + dev_err(data->dev, "index is error for usbmisc\n"); + ret = -EINVAL; + } + + return ret ? ret : offset; +} + +static int usbmisc_imx6_hsic_set_connect(struct imx_usbmisc_data *data) +{ + unsigned long flags; + u32 val; + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + int offset; + + spin_lock_irqsave(&usbmisc->lock, flags); + offset = usbmisc_imx6_hsic_get_reg_offset(data); + if (offset < 0) { + spin_unlock_irqrestore(&usbmisc->lock, flags); + return offset; + } + + val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); + if (!(val & MX6_BM_HSIC_DEV_CONN)) + writel(val | MX6_BM_HSIC_DEV_CONN, + usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); + + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + +static int usbmisc_imx6_hsic_set_clk(struct imx_usbmisc_data *data, bool on) +{ + unsigned long flags; + u32 val; + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + int offset; + + spin_lock_irqsave(&usbmisc->lock, flags); + offset = usbmisc_imx6_hsic_get_reg_offset(data); + if (offset < 0) { + spin_unlock_irqrestore(&usbmisc->lock, flags); + return offset; + } + + val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); + val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON; + if (on) + val |= MX6_BM_HSIC_CLK_ON; + else + val &= ~MX6_BM_HSIC_CLK_ON; + + writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + + static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data) { void __iomem *reg = NULL; @@ -385,6 +511,13 @@ static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data) spin_unlock_irqrestore(&usbmisc->lock, flags); } + /* For HSIC controller */ + if (data->hsic) { + val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET); + val |= MX6SX_BM_HSIC_AUTO_RESUME; + writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET); + } + return 0; } @@ -444,16 +577,28 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data) reg = readl(usbmisc->base); if (data->disable_oc) { reg |= MX6_BM_OVER_CUR_DIS; - } else if (data->oc_polarity == 1) { - /* High active */ - reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); + } else { + reg &= ~MX6_BM_OVER_CUR_DIS; + + /* + * If the polarity is not configured keep it as setup by the + * bootloader. + */ + if (data->oc_pol_configured && data->oc_pol_active_low) + reg |= MX6_BM_OVER_CUR_POLARITY; + else if (data->oc_pol_configured) + reg &= ~MX6_BM_OVER_CUR_POLARITY; } + /* If the polarity is not set keep it as setup by the bootlader */ + if (data->pwr_pol == 1) + reg |= MX6_BM_PWR_POLARITY; writel(reg, usbmisc->base); reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK; writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID, usbmisc->base + MX7D_USBNC_USB_CTRL2); + spin_unlock_irqrestore(&usbmisc->lock, flags); usbmisc_imx7d_set_wakeup(data, false); @@ -481,6 +626,8 @@ static const struct usbmisc_ops imx53_usbmisc_ops = { static const struct usbmisc_ops imx6q_usbmisc_ops = { .set_wakeup = usbmisc_imx6q_set_wakeup, .init = usbmisc_imx6q_init, + .hsic_set_connect = usbmisc_imx6_hsic_set_connect, + .hsic_set_clk = usbmisc_imx6_hsic_set_clk, }; static const struct usbmisc_ops vf610_usbmisc_ops = { @@ -490,6 +637,8 @@ static const struct usbmisc_ops vf610_usbmisc_ops = { static const struct usbmisc_ops imx6sx_usbmisc_ops = { .set_wakeup = usbmisc_imx6q_set_wakeup, .init = usbmisc_imx6sx_init, + .hsic_set_connect = usbmisc_imx6_hsic_set_connect, + .hsic_set_clk = usbmisc_imx6_hsic_set_clk, }; static const struct usbmisc_ops imx7d_usbmisc_ops = { @@ -546,6 +695,33 @@ int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled) } EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup); +int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data) +{ + struct imx_usbmisc *usbmisc; + + if (!data) + return 0; + + usbmisc = dev_get_drvdata(data->dev); + if (!usbmisc->ops->hsic_set_connect || !data->hsic) + return 0; + return usbmisc->ops->hsic_set_connect(data); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect); + +int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on) +{ + struct imx_usbmisc *usbmisc; + + if (!data) + return 0; + + usbmisc = dev_get_drvdata(data->dev); + if (!usbmisc->ops->hsic_set_clk || !data->hsic) + return 0; + return usbmisc->ops->hsic_set_clk(data, on); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk); static const struct of_device_id usbmisc_imx_dt_ids[] = { { .compatible = "fsl,imx25-usbmisc", diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 971385fe9abc..52f3a531a82f 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Class driver configuration # diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 1b68fed464cb..ec666eb4b7b4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -558,10 +558,8 @@ static void acm_softint(struct work_struct *work) clear_bit(EVENT_RX_STALL, &acm->flags); } - if (test_bit(EVENT_TTY_WAKEUP, &acm->flags)) { + if (test_and_clear_bit(EVENT_TTY_WAKEUP, &acm->flags)) tty_port_tty_wakeup(&acm->port); - clear_bit(EVENT_TTY_WAKEUP, &acm->flags); - } } /* @@ -581,6 +579,13 @@ static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) if (retval) goto error_init_termios; + /* + * Suppress initial echoing for some devices which might send data + * immediately after acm driver has been installed. + */ + if (acm->quirks & DISABLE_ECHO) + tty->termios.c_lflag &= ~ECHO; + tty->driver_data = acm; return 0; @@ -1657,6 +1662,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x0e8d, 0x2000), /* MediaTek Inc Preloader */ + .driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */ + }, { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, @@ -1855,6 +1863,13 @@ static const struct usb_device_id acm_ids[] = { .driver_info = IGNORE_DEVICE, }, + { USB_DEVICE(0x1bc7, 0x0021), /* Telit 3G ACM only composition */ + .driver_info = SEND_ZERO_PACKET, + }, + { USB_DEVICE(0x1bc7, 0x0023), /* Telit 3G ACM + ECM composition */ + .driver_info = SEND_ZERO_PACKET, + }, + /* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) }, diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index ca06b20d7af9..515aad0847ee 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -140,3 +140,4 @@ struct acm { #define QUIRK_CONTROL_LINE_STATE BIT(6) #define CLEAR_HALT_CONDITIONS BIT(7) #define SEND_ZERO_PACKET BIT(8) +#define DISABLE_ECHO BIT(9) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index bec581fb7c63..9e9caff905d5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -1099,7 +1099,7 @@ static int wdm_post_reset(struct usb_interface *intf) rv = recover_from_urb_loss(desc); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); - return 0; + return rv; } static struct usb_driver wdm_driver = { diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile index fb4d5ef4165c..0a7c45e85481 100644 --- a/drivers/usb/common/Makefile +++ b/drivers/usb/common/Makefile @@ -9,4 +9,3 @@ usb-common-$(CONFIG_USB_LED_TRIG) += led.o obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o obj-$(CONFIG_USB_ULPI_BUS) += ulpi.o -obj-$(CONFIG_USB_ROLE_SWITCH) += roles.o diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 48277bbc15e4..73c8e6591746 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -145,6 +145,8 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) do { controller = of_find_node_with_property(controller, "phys"); + if (!of_device_is_available(controller)) + continue; index = 0; do { if (arg0 == -1) { diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 4d75d9a80001..bdb6bd0b63a6 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Core configuration # @@ -90,3 +91,15 @@ config USB_LEDS_TRIGGER_USBPORT This driver allows LEDs to be controlled by USB events. Enabling this trigger allows specifying list of USB ports that should turn on LED when some USB device gets connected. + +config USB_AUTOSUSPEND_DELAY + int "Default autosuspend delay" + depends on USB + default 2 + help + The default autosuspend delay in seconds. Can be overridden + with the usbcore.autosuspend command line or module parameter. + + The default value Linux has always had is 2 seconds. Change + this value if you want a different delay and cannot modify + the command line or module parameter. diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7b5cb28ffb35..20ff036b4c22 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -552,7 +552,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, unsigned char *buffer2; int size2; struct usb_descriptor_header *header; - int len, retval; + int retval; u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; unsigned iad_num = 0; @@ -707,8 +707,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, nalts[i] = j = USB_MAXALTSETTING; } - len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; - config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); + intfc = kzalloc(struct_size(intfc, altsetting, j), GFP_KERNEL); + config->intf_cache[i] = intfc; if (!intfc) return -ENOMEM; kref_init(&intfc->ref); @@ -800,13 +800,11 @@ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = 0; + int result = -ENOMEM; unsigned int cfgno, length; unsigned char *bigbuffer; struct usb_config_descriptor *desc; - cfgno = 0; - result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -832,8 +830,7 @@ int usb_get_configuration(struct usb_device *dev) if (!desc) goto err2; - result = 0; - for (; cfgno < ncfg; cfgno++) { + for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, @@ -889,7 +886,6 @@ int usb_get_configuration(struct usb_device *dev) goto err; } } - result = 0; err: kfree(desc); diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 3de3c750b5f6..44f28a114c2b 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -598,7 +598,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, return -EINVAL; if (nbytes <= 0) return 0; - if (!access_ok(VERIFY_WRITE, buf, nbytes)) + if (!access_ok(buf, nbytes)) return -EFAULT; mutex_lock(&usb_bus_idr_lock); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index a75bc0b8a50f..fa783531ee88 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -604,7 +604,7 @@ static void async_completed(struct urb *urb) snoop(&urb->dev->dev, "urb complete\n"); snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, as->status, COMPLETE, NULL, 0); - if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN) + if (usb_urb_dir_in(urb)) snoop_urb_data(urb, urb->actual_length); if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && @@ -1094,7 +1094,7 @@ static int proc_control(struct usb_dev_state *ps, void __user *arg) ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, ctrl.wIndex, ctrl.wLength); if (ctrl.bRequestType & 0x80) { - if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, + if (ctrl.wLength && !access_ok(ctrl.data, ctrl.wLength)) { ret = -EINVAL; goto done; @@ -1183,7 +1183,7 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) } tmo = bulk.timeout; if (bulk.ep & 0x80) { - if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { + if (len1 && !access_ok(bulk.data, len1)) { ret = -EINVAL; goto done; } @@ -1564,12 +1564,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb } for (totlen = u = 0; u < number_of_packets; u++) { /* - * arbitrary limit need for USB 3.0 - * bMaxBurst (0~15 allowed, 1~16 packets) - * bmAttributes (bit 1:0, mult 0~2, 1~3 packets) - * sizemax: 1024 * 16 * 3 = 49152 + * arbitrary limit need for USB 3.1 Gen2 + * sizemax: 96 DPs at SSP, 96 * 1024 = 98304 */ - if (isopkt[u].length > 49152) { + if (isopkt[u].length > 98304) { ret = -EINVAL; goto error; } @@ -1584,8 +1582,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb } if (uurb->buffer_length > 0 && - !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, - uurb->buffer, uurb->buffer_length)) { + !access_ok(uurb->buffer, uurb->buffer_length)) { ret = -EFAULT; goto error; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 53564386ed57..ebcadaad89d1 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -473,11 +473,6 @@ static int usb_unbind_interface(struct device *dev) pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - /* Undo any residual pm_autopm_get_interface_* calls */ - for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r) - usb_autopm_put_interface_no_suspend(intf); - atomic_set(&intf->pm_usage_cnt, 0); - if (!error) usb_autosuspend_device(udev); @@ -1633,7 +1628,6 @@ void usb_autopm_put_interface(struct usb_interface *intf) int status; usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); status = pm_runtime_put_sync(&intf->dev); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), @@ -1662,7 +1656,6 @@ void usb_autopm_put_interface_async(struct usb_interface *intf) int status; usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); status = pm_runtime_put(&intf->dev); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), @@ -1684,7 +1677,6 @@ void usb_autopm_put_interface_no_suspend(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); pm_runtime_put_noidle(&intf->dev); } EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend); @@ -1715,8 +1707,6 @@ int usb_autopm_get_interface(struct usb_interface *intf) status = pm_runtime_get_sync(&intf->dev); if (status < 0) pm_runtime_put_sync(&intf->dev); - else - atomic_inc(&intf->pm_usage_cnt); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), status); @@ -1750,8 +1740,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf) status = pm_runtime_get(&intf->dev); if (status < 0 && status != -EINPROGRESS) pm_runtime_put_noidle(&intf->dev); - else - atomic_inc(&intf->pm_usage_cnt); dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), status); @@ -1775,7 +1763,6 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); usb_mark_last_busy(udev); - atomic_inc(&intf->pm_usage_cnt); pm_runtime_get_noresume(&intf->dev); } EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume); @@ -1896,14 +1883,11 @@ int usb_runtime_idle(struct device *dev) return -EBUSY; } -int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; - if (enable && !udev->usb2_hw_lpm_allowed) - return 0; - if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) @@ -1913,6 +1897,24 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) return ret; } +int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_capable || + !udev->usb2_hw_lpm_allowed || + udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 1); +} + +int usb_disable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 0); +} + #endif /* CONFIG_PM */ struct bus_type usb_bus_type = { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 356b05c82dbc..1ac9c1e5f773 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -118,6 +118,31 @@ int usb_choose_configuration(struct usb_device *udev) continue; } + /* + * Select first configuration as default for audio so that + * devices that don't comply with UAC3 protocol are supported. + * But, still iterate through other configurations and + * select UAC3 compliant config if present. + */ + if (desc && is_audio(desc)) { + /* Always prefer the first found UAC3 config */ + if (is_uac3_config(desc)) { + best = c; + break; + } + + /* If there is no UAC3 config, prefer the first config */ + else if (i == 0) + best = c; + + /* Unconditional continue, because the rest of the code + * in the loop is irrelevant for audio devices, and + * because it can reassign best, which for audio devices + * we don't want. + */ + continue; + } + /* When the first config's first interface is one of Microsoft's * pet nonstandard Ethernet-over-USB protocols, ignore it unless * this kernel has enabled the necessary host side driver. @@ -132,22 +157,6 @@ int usb_choose_configuration(struct usb_device *udev) #endif } - /* - * Select first configuration as default for audio so that - * devices that don't comply with UAC3 protocol are supported. - * But, still iterate through other configurations and - * select UAC3 compliant config if present. - */ - if (i == 0 && num_configs > 1 && desc && is_audio(desc)) { - best = c; - continue; - } - - if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) { - best = c; - break; - } - /* From the remaining configs, choose the first one whose * first interface is for a non-vendor-specific class. * Reason: Linux is more likely to have a class driver diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 487025d31d44..975d7c1288e3 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -373,13 +373,19 @@ static const u8 ss_rh_config_descriptor[] = { * -1 is authorized for all devices except wireless (old behaviour) * 0 is unauthorized for all devices * 1 is authorized for all devices + * 2 is authorized for internal devices */ -static int authorized_default = -1; +#define USB_AUTHORIZE_WIRED -1 +#define USB_AUTHORIZE_NONE 0 +#define USB_AUTHORIZE_ALL 1 +#define USB_AUTHORIZE_INTERNAL 2 + +static int authorized_default = USB_AUTHORIZE_WIRED; module_param(authorized_default, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(authorized_default, "Default USB device authorization: 0 is not authorized, 1 is " - "authorized, -1 is authorized except for wireless USB (default, " - "old behaviour"); + "authorized, 2 is authorized for internal devices, -1 is " + "authorized except for wireless USB (default, old behaviour)"); /*-------------------------------------------------------------------------*/ /** @@ -884,7 +890,7 @@ static ssize_t authorized_default_show(struct device *dev, struct usb_hcd *hcd; hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd)); + return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy); } static ssize_t authorized_default_store(struct device *dev, @@ -900,11 +906,8 @@ static ssize_t authorized_default_store(struct device *dev, hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - if (val) - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - + hcd->dev_policy = val <= USB_DEVICE_AUTHORIZE_INTERNAL ? + val : USB_DEVICE_AUTHORIZE_ALL; result = size; } else { result = -EINVAL; @@ -1074,8 +1077,6 @@ static int register_root_hub(struct usb_hcd *hcd) usb_dev->devnum = devnum; usb_dev->bus->devnum_next = devnum + 1; - memset (&usb_dev->bus->devmap.devicemap, 0, - sizeof usb_dev->bus->devmap.devicemap); set_bit (devnum, usb_dev->bus->devmap.devicemap); usb_set_device_state(usb_dev, USB_STATE_ADDRESS); @@ -2738,6 +2739,14 @@ int usb_add_hcd(struct usb_hcd *hcd, if (retval) return retval; + retval = usb_phy_roothub_set_mode(hcd->phy_roothub, + PHY_MODE_USB_HOST_SS); + if (retval) + retval = usb_phy_roothub_set_mode(hcd->phy_roothub, + PHY_MODE_USB_HOST); + if (retval) + goto err_usb_phy_roothub_power_on; + retval = usb_phy_roothub_power_on(hcd->phy_roothub); if (retval) goto err_usb_phy_roothub_power_on; @@ -2745,18 +2754,26 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); - /* Keep old behaviour if authorized_default is not in [0, 1]. */ - if (authorized_default < 0 || authorized_default > 1) { - if (hcd->wireless) - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - } else { - if (authorized_default) - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + switch (authorized_default) { + case USB_AUTHORIZE_NONE: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_NONE; + break; + + case USB_AUTHORIZE_ALL: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_ALL; + break; + + case USB_AUTHORIZE_INTERNAL: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_INTERNAL; + break; + + case USB_AUTHORIZE_WIRED: + default: + hcd->dev_policy = hcd->wireless ? + USB_DEVICE_AUTHORIZE_NONE : USB_DEVICE_AUTHORIZE_ALL; + break; } + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* per default all interfaces are authorized */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f76b2e0aba9d..8d4631c81b9f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -108,6 +108,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); static void hub_release(struct kref *kref); static int usb_reset_and_verify_device(struct usb_device *udev); static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); +static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, + u16 portstatus); static inline char *portspeed(struct usb_hub *hub, int portstatus) { @@ -607,6 +609,36 @@ static int hub_port_status(struct usb_hub *hub, int port1, status, change, NULL); } +static void hub_resubmit_irq_urb(struct usb_hub *hub) +{ + unsigned long flags; + int status; + + spin_lock_irqsave(&hub->irq_urb_lock, flags); + + if (hub->quiescing) { + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); + return; + } + + status = usb_submit_urb(hub->urb, GFP_ATOMIC); + if (status && status != -ENODEV && status != -EPERM && + status != -ESHUTDOWN) { + dev_err(hub->intfdev, "resubmit --> %d\n", status); + mod_timer(&hub->irq_urb_retry, jiffies + HZ); + } + + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); +} + +static void hub_retry_irq_urb(struct timer_list *t) +{ + struct usb_hub *hub = from_timer(hub, t, irq_urb_retry); + + hub_resubmit_irq_urb(hub); +} + + static void kick_hub_wq(struct usb_hub *hub) { struct usb_interface *intf; @@ -709,12 +741,7 @@ static void hub_irq(struct urb *urb) kick_hub_wq(hub); resubmit: - if (hub->quiescing) - return; - - status = usb_submit_urb(hub->urb, GFP_ATOMIC); - if (status != 0 && status != -ENODEV && status != -EPERM) - dev_err(hub->intfdev, "resubmit --> %d\n", status); + hub_resubmit_irq_urb(hub); } /* USB 2.0 spec Section 11.24.2.3 */ @@ -1112,6 +1139,21 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) USB_PORT_FEAT_ENABLE); } + /* Make sure a warm-reset request is handled by port_event */ + if (type == HUB_RESUME && + hub_port_warm_reset_required(hub, port1, portstatus)) + set_bit(port1, hub->event_bits); + + /* + * Add debounce if USB3 link is in polling/link training state. + * Link will automatically transition to Enabled state after + * link training completes. + */ + if (hub_is_superspeed(hdev) && + ((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_POLLING)) + need_debounce_delay = true; + /* Clear status-change flags; we'll debounce later */ if (portchange & USB_PORT_STAT_C_CONNECTION) { need_debounce_delay = true; @@ -1254,10 +1296,13 @@ enum hub_quiescing_type { static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) { struct usb_device *hdev = hub->hdev; + unsigned long flags; int i; /* hub_wq and related activity won't re-trigger */ + spin_lock_irqsave(&hub->irq_urb_lock, flags); hub->quiescing = 1; + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); if (type != HUB_SUSPEND) { /* Disconnect all the children */ @@ -1268,6 +1313,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) } /* Stop hub_wq and related activity */ + del_timer_sync(&hub->irq_urb_retry); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); @@ -1800,6 +1846,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); + spin_lock_init(&hub->irq_urb_lock); + timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); usb_get_intf(intf); usb_get_dev(hdev); @@ -3210,8 +3258,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) } /* disable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); if (usb_disable_ltm(udev)) { dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); @@ -3249,8 +3296,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_enable_ltm(udev); err_ltm: /* Try to enable USB2 hardware LPM again */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); if (udev->do_remote_wakeup) (void) usb_disable_remote_wakeup(udev); @@ -3533,8 +3579,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) hub_port_logical_disconnect(hub, port1); } else { /* Try to enable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); /* Try to enable USB3 LTM */ usb_enable_ltm(udev); @@ -4425,7 +4470,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { udev->usb2_hw_lpm_allowed = 1; - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); } } @@ -5639,8 +5684,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) /* Disable USB2 hardware LPM. * It will be re-enabled by the enumeration process. */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); /* Disable LPM while we reset the device and reinstall the alt settings. * Device-initiated LPM, and system exit latency settings are cleared @@ -5743,7 +5787,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: /* Now that the alt settings are re-installed, enable LTM and LPM. */ - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); usb_release_bos_descriptor(udev); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 4accfb63f7dc..a9e24e4b8df1 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,6 +69,8 @@ struct usb_hub { struct delayed_work leds; struct delayed_work init_work; struct work_struct events; + spinlock_t irq_urb_lock; + struct timer_list irq_urb_retry; struct usb_port **ports; }; diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index dc7f7fd71684..c12ac56606c3 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -119,11 +119,6 @@ static const struct attribute_group ports_group = { .attrs = ports_attrs, }; -static const struct attribute_group *ports_groups[] = { - &ports_group, - NULL -}; - /*************************************** * Adding & removing ports ***************************************/ @@ -307,6 +302,7 @@ static int usbport_trig_notify(struct notifier_block *nb, unsigned long action, static int usbport_trig_activate(struct led_classdev *led_cdev) { struct usbport_trig_data *usbport_data; + int err; usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL); if (!usbport_data) @@ -315,6 +311,9 @@ static int usbport_trig_activate(struct led_classdev *led_cdev) /* List of ports */ INIT_LIST_HEAD(&usbport_data->ports); + err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group); + if (err) + goto err_free; usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports); usbport_trig_update_count(usbport_data); @@ -322,8 +321,11 @@ static int usbport_trig_activate(struct led_classdev *led_cdev) usbport_data->nb.notifier_call = usbport_trig_notify; led_set_trigger_data(led_cdev, usbport_data); usb_register_notify(&usbport_data->nb); - return 0; + +err_free: + kfree(usbport_data); + return err; } static void usbport_trig_deactivate(struct led_classdev *led_cdev) @@ -335,6 +337,8 @@ static void usbport_trig_deactivate(struct led_classdev *led_cdev) usbport_trig_remove_port(usbport_data, port); } + sysfs_remove_group(&led_cdev->dev->kobj, &ports_group); + usb_unregister_notify(&usbport_data->nb); kfree(usbport_data); @@ -344,7 +348,6 @@ static struct led_trigger usbport_led_trigger = { .name = "usbport", .activate = usbport_trig_activate, .deactivate = usbport_trig_deactivate, - .groups = ports_groups, }; static int __init usbport_trig_init(void) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index bfa5eda0cc26..e844bb7b5676 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -820,9 +820,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; - if (size <= 0 || !buf || !index) + if (size <= 0 || !buf) return -EINVAL; buf[0] = 0; + if (index <= 0 || index >= 256) + return -EINVAL; tbuf = kmalloc(256, GFP_NOIO); if (!tbuf) return -ENOMEM; @@ -1243,8 +1245,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev->actconfig->interface[i] = NULL; } - if (dev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(dev, 0); + usb_disable_usb2_hardware_lpm(dev); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); @@ -2007,6 +2008,13 @@ free_interfaces: for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; + if (intf->dev.of_node && + !of_device_is_available(intf->dev.of_node)) { + dev_info(&dev->dev, "skipping disabled interface %d\n", + intf->cur_altsetting->desc.bInterfaceNumber); + continue; + } + dev_dbg(&dev->dev, "adding %s (config #%d, interface %d)\n", dev_name(&intf->dev), configuration, diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 38b2c776c4b4..7580493b867a 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -123,6 +123,34 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) } EXPORT_SYMBOL_GPL(usb_phy_roothub_exit); +int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, + enum phy_mode mode) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_set_mode(roothub_entry->phy, mode); + if (err) + goto err_out; + } + + return 0; + +err_out: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_power_off(roothub_entry->phy); + + return err; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode); + int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) { struct usb_phy_roothub *roothub_entry; diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h index 88a3c037e9df..dad564e2d2d4 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h @@ -16,6 +16,8 @@ struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev); int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub); int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); +int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, + enum phy_mode mode); int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 514c5214ddb2..8bc35d53408b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -394,7 +394,8 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET }, /* Corsair K70 RGB */ - { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_DELAY_CTRL_MSG }, /* Corsair Strafe */ { USB_DEVICE(0x1b1c, 0x1b15), .driver_info = USB_QUIRK_DELAY_INIT | diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index ea18284dfa9a..7e88fdfe3cf5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -528,7 +528,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, if (!ret) { udev->usb2_hw_lpm_allowed = value; - ret = usb_set_usb2_hardware_lpm(udev, value); + if (value) + ret = usb_enable_usb2_hardware_lpm(udev); + else + ret = usb_disable_usb2_hardware_lpm(udev); } usb_unlock_device(udev); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index f51750bcd152..0eab79f82ce4 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -70,9 +70,8 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; - urb = kmalloc(sizeof(struct urb) + - iso_packets * sizeof(struct usb_iso_packet_descriptor), - mem_flags); + urb = kmalloc(struct_size(urb, iso_frame_desc, iso_packets), + mem_flags); if (!urb) return NULL; usb_init_urb(urb); diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index e221861b3187..9043d7242d67 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -139,86 +139,123 @@ static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent, return acpi_find_child_device(parent, raw, false); } -static struct acpi_device *usb_acpi_find_companion(struct device *dev) +static struct acpi_device * +usb_acpi_get_companion_for_port(struct usb_port *port_dev) { struct usb_device *udev; struct acpi_device *adev; acpi_handle *parent_handle; + int port1; + + /* Get the struct usb_device point of port's hub */ + udev = to_usb_device(port_dev->dev.parent->parent); /* - * In the ACPI DSDT table, only usb root hub and usb ports are - * acpi device nodes. The hierarchy like following. - * Device (EHC1) - * Device (HUBN) - * Device (PR01) - * Device (PR11) - * Device (PR12) - * Device (PR13) - * ... - * So all binding process is divided into two parts. binding - * root hub and usb ports. + * The root hub ports' parent is the root hub. The non-root-hub + * ports' parent is the parent hub port which the hub is + * connected to. */ - if (is_usb_device(dev)) { - udev = to_usb_device(dev); - if (udev->parent) + if (!udev->parent) { + adev = ACPI_COMPANION(&udev->dev); + port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus), + port_dev->portnum); + } else { + parent_handle = usb_get_hub_port_acpi_handle(udev->parent, + udev->portnum); + if (!parent_handle) return NULL; - /* root hub is only child (_ADR=0) under its parent, the HC */ - adev = ACPI_COMPANION(dev->parent); - return acpi_find_child_device(adev, 0, false); - } else if (is_usb_port(dev)) { - struct usb_port *port_dev = to_usb_port(dev); - int port1 = port_dev->portnum; - struct acpi_pld_info *pld; - acpi_handle *handle; - acpi_status status; - - /* Get the struct usb_device point of port's hub */ - udev = to_usb_device(dev->parent->parent); - - /* - * The root hub ports' parent is the root hub. The non-root-hub - * ports' parent is the parent hub port which the hub is - * connected to. - */ - if (!udev->parent) { - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - int raw; - - raw = usb_hcd_find_raw_port_number(hcd, port1); - - adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev), - raw); - - if (!adev) - return NULL; - } else { - parent_handle = - usb_get_hub_port_acpi_handle(udev->parent, - udev->portnum); - if (!parent_handle) - return NULL; - - acpi_bus_get_device(parent_handle, &adev); - - adev = usb_acpi_find_port(adev, port1); - - if (!adev) - return NULL; - } - handle = adev->handle; - status = acpi_get_physical_device_location(handle, &pld); - if (ACPI_FAILURE(status) || !pld) - return adev; + acpi_bus_get_device(parent_handle, &adev); + port1 = port_dev->portnum; + } + return usb_acpi_find_port(adev, port1); +} + +static struct acpi_device * +usb_acpi_find_companion_for_port(struct usb_port *port_dev) +{ + struct acpi_device *adev; + struct acpi_pld_info *pld; + acpi_handle *handle; + acpi_status status; + + adev = usb_acpi_get_companion_for_port(port_dev); + if (!adev) + return NULL; + + handle = adev->handle; + status = acpi_get_physical_device_location(handle, &pld); + if (!ACPI_FAILURE(status) && pld) { port_dev->location = USB_ACPI_LOCATION_VALID | pld->group_token << 8 | pld->group_position; port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); ACPI_FREE(pld); + } - return adev; + return adev; +} + +static struct acpi_device * +usb_acpi_find_companion_for_device(struct usb_device *udev) +{ + struct acpi_device *adev; + struct usb_port *port_dev; + struct usb_hub *hub; + + if (!udev->parent) { + /* root hub is only child (_ADR=0) under its parent, the HC */ + adev = ACPI_COMPANION(udev->dev.parent); + return acpi_find_child_device(adev, 0, false); } + hub = usb_hub_to_struct_hub(udev->parent); + if (!hub) + return NULL; + + /* + * This is an embedded USB device connected to a port and such + * devices share port's ACPI companion. + */ + port_dev = hub->ports[udev->portnum - 1]; + return usb_acpi_get_companion_for_port(port_dev); +} + +static struct acpi_device *usb_acpi_find_companion(struct device *dev) +{ + /* + * The USB hierarchy like following: + * + * Device (EHC1) + * Device (HUBN) + * Device (PR01) + * Device (PR11) + * Device (PR12) + * Device (FN12) + * Device (FN13) + * Device (PR13) + * ... + * where HUBN is root hub, and PRNN are USB ports and devices + * connected to them, and FNNN are individualk functions for + * connected composite USB devices. PRNN and FNNN may contain + * _CRS and other methods describing sideband resources for + * the connected device. + * + * On the kernel side both root hub and embedded USB devices are + * represented as instances of usb_device structure, and ports + * are represented as usb_port structures, so the whole process + * is split into 2 parts: finding companions for devices and + * finding companions for ports. + * + * Note that we do not handle individual functions of composite + * devices yet, for that we would need to assign companions to + * devices corresponding to USB interfaces. + */ + if (is_usb_device(dev)) + return usb_acpi_find_companion_for_device(to_usb_device(dev)); + else if (is_usb_port(dev)) + return usb_acpi_find_companion_for_port(to_usb_port(dev)); + return NULL; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4ebfbd737905..7fcb9f782931 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -46,8 +46,7 @@ #include <linux/mm.h> #include <linux/dma-mapping.h> -#include "usb.h" - +#include "hub.h" const char *usbcore_name = "usbcore"; @@ -65,8 +64,8 @@ int usb_disabled(void) EXPORT_SYMBOL_GPL(usb_disabled); #ifdef CONFIG_PM -static int usb_autosuspend_delay = 2; /* Default delay value, - * in seconds */ +/* Default delay value, in seconds */ +static int usb_autosuspend_delay = CONFIG_USB_AUTOSUSPEND_DELAY; module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); @@ -536,6 +535,27 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) return hcd->wireless; } +static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd) +{ + struct usb_hub *hub; + + if (!dev->parent) + return true; /* Root hub always ok [and always wired] */ + + switch (hcd->dev_policy) { + case USB_DEVICE_AUTHORIZE_NONE: + default: + return false; + + case USB_DEVICE_AUTHORIZE_ALL: + return true; + + case USB_DEVICE_AUTHORIZE_INTERNAL: + hub = usb_hub_to_struct_hub(dev->parent); + return hub->ports[dev->portnum - 1]->connect_type == + USB_PORT_CONNECT_TYPE_HARD_WIRED; + } +} /** * usb_alloc_dev - usb device constructor (usbcore-internal) @@ -663,12 +683,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->connect_time = jiffies; dev->active_duration = -jiffies; #endif - if (root_hub) /* Root hub always ok [and always wired] */ - dev->authorized = 1; - else { - dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd); + + dev->authorized = usb_dev_authorized(dev, usb_hcd); + if (!root_hub) dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; - } + return dev; } EXPORT_SYMBOL_GPL(usb_alloc_dev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 546a2219454b..d95a5358f73d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -92,7 +92,8 @@ extern int usb_remote_wakeup(struct usb_device *dev); extern int usb_runtime_suspend(struct device *dev); extern int usb_runtime_resume(struct device *dev); extern int usb_runtime_idle(struct device *dev); -extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); +extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev); +extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev); #else @@ -112,7 +113,12 @@ static inline int usb_autoresume_device(struct usb_device *udev) return 0; } -static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + return 0; +} + +static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev) { return 0; } diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index b6a495e98fd8..68d095ae2865 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_DWC2 tristate "DesignWare USB2 DRD Core Support" depends on HAS_DMA diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 2d6d2c8244de..6812a8a3a98b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -261,8 +261,8 @@ static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); - dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); - dwc2_set_bit(hsotg, DCFG, DCTL_RMTWKUPSIG); + dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); + dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG); } } @@ -768,22 +768,13 @@ static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) return desc_size; } -/* - * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. - * @hs_ep: The endpoint - * @dma_buff: DMA address to use - * @len: Length of the transfer - * - * This function will iterate over descriptor chain and fill its entries - * with corresponding information based on transfer data. - */ -static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, +static void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep, + struct dwc2_dma_desc **desc, dma_addr_t dma_buff, - unsigned int len) + unsigned int len, + bool true_last) { - struct dwc2_hsotg *hsotg = hs_ep->parent; int dir_in = hs_ep->dir_in; - struct dwc2_dma_desc *desc = hs_ep->desc_list; u32 mps = hs_ep->ep.maxpacket; u32 maxsize = 0; u32 offset = 0; @@ -798,42 +789,80 @@ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, hs_ep->desc_count = 1; for (i = 0; i < hs_ep->desc_count; ++i) { - desc->status = 0; - desc->status |= (DEV_DMA_BUFF_STS_HBUSY + (*desc)->status = 0; + (*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); if (len > maxsize) { if (!hs_ep->index && !dir_in) - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); - desc->status |= (maxsize << - DEV_DMA_NBYTES_SHIFT & mask); - desc->buf = dma_buff + offset; + (*desc)->status |= + maxsize << DEV_DMA_NBYTES_SHIFT & mask; + (*desc)->buf = dma_buff + offset; len -= maxsize; offset += maxsize; } else { - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + if (true_last) + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); if (dir_in) - desc->status |= (len % mps) ? DEV_DMA_SHORT : - ((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0); - if (len > maxsize) - dev_err(hsotg->dev, "wrong len %d\n", len); + (*desc)->status |= (len % mps) ? DEV_DMA_SHORT : + ((hs_ep->send_zlp && true_last) ? + DEV_DMA_SHORT : 0); - desc->status |= + (*desc)->status |= len << DEV_DMA_NBYTES_SHIFT & mask; - desc->buf = dma_buff + offset; + (*desc)->buf = dma_buff + offset; } - desc->status &= ~DEV_DMA_BUFF_STS_MASK; - desc->status |= (DEV_DMA_BUFF_STS_HREADY + (*desc)->status &= ~DEV_DMA_BUFF_STS_MASK; + (*desc)->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); - desc++; + (*desc)++; } } /* + * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. + * @hs_ep: The endpoint + * @ureq: Request to transfer + * @offset: offset in bytes + * @len: Length of the transfer + * + * This function will iterate over descriptor chain and fill its entries + * with corresponding information based on transfer data. + */ +static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, + struct usb_request *ureq, + unsigned int offset, + unsigned int len) +{ + struct dwc2_dma_desc *desc = hs_ep->desc_list; + struct scatterlist *sg; + int i; + u8 desc_count = 0; + + /* non-DMA sg buffer */ + if (!ureq->num_sgs) { + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, + ureq->dma + offset, len, true); + return; + } + + /* DMA sg buffer */ + for_each_sg(ureq->sg, sg, ureq->num_sgs, i) { + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, + sg_dma_address(sg) + sg->offset, sg_dma_len(sg), + sg_is_last(sg)); + desc_count += hs_ep->desc_count; + } + + hs_ep->desc_count = desc_count; +} + +/* * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. * @hs_ep: The isochronous endpoint. * @dma_buff: usb requests dma buffer. @@ -944,7 +973,13 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) hs_ep->next_desc = 0; list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { - ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); if (ret) break; @@ -1100,7 +1135,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, offset = ureq->actual; /* Fill DDMA chain entries */ - dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset, + dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq, offset, length); /* write descriptor chain address to control register */ @@ -1399,7 +1434,13 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, */ if (using_desc_dma(hs) && hs_ep->isochronous) { if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { - dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); } return 0; @@ -1987,13 +2028,12 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", index); if (using_desc_dma(hsotg)) { - /* Not specific buffer needed for ep0 ZLP */ - dma_addr_t dma = hs_ep->desc_list_dma; - if (!index) dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); - dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); + /* Not specific buffer needed for ep0 ZLP */ + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &hs_ep->desc_list, + hs_ep->desc_list_dma, 0, true); } else { dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | DXEPTSIZ_XFERSIZE(0), @@ -3165,8 +3205,6 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); } -static int dwc2_hsotg_ep_disable(struct usb_ep *ep); - /** * dwc2_hsotg_disconnect - disconnect service * @hsotg: The device state. @@ -3188,9 +3226,11 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) /* all endpoints should be shutdown */ for (ep = 0; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) - dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); + kill_all_requests(hsotg, hsotg->eps_in[ep], + -ESHUTDOWN); if (hsotg->eps_out[ep]) - dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); + kill_all_requests(hsotg, hsotg->eps_out[ep], + -ESHUTDOWN); } call_gadget(hsotg, disconnect); @@ -3234,6 +3274,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) GINTSTS_PTXFEMP | \ GINTSTS_RXFLVL) +static int dwc2_hsotg_ep_disable(struct usb_ep *ep); /** * dwc2_hsotg_core_init - issue softreset to the core * @hsotg: The device state @@ -4004,6 +4045,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, ret = -ENOMEM; goto error1; } + epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT); hsotg->fifo_map |= 1 << fifo_index; epctrl |= DXEPCTL_TXFNUM(fifo_index); hs_ep->fifo_index = fifo_index; @@ -4069,10 +4111,8 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) struct dwc2_hsotg *hsotg = hs_ep->parent; int dir_in = hs_ep->dir_in; int index = hs_ep->index; - unsigned long flags; u32 epctrl_reg; u32 ctrl; - int locked; dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); @@ -4088,10 +4128,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); - locked = spin_is_locked(&hsotg->lock); - if (!locked) - spin_lock_irqsave(&hsotg->lock, flags); - ctrl = dwc2_readl(hsotg, epctrl_reg); if (ctrl & DXEPCTL_EPENA) @@ -4114,12 +4150,22 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) hs_ep->fifo_index = 0; hs_ep->fifo_size = 0; - if (!locked) - spin_unlock_irqrestore(&hsotg->lock, flags); - return 0; } +static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) +{ + struct dwc2_hsotg_ep *hs_ep = our_ep(ep); + struct dwc2_hsotg *hsotg = hs_ep->parent; + unsigned long flags; + int ret; + + spin_lock_irqsave(&hsotg->lock, flags); + ret = dwc2_hsotg_ep_disable(ep); + spin_unlock_irqrestore(&hsotg->lock, flags); + return ret; +} + /** * on_list - check request is on the given endpoint * @ep: The endpoint to check. @@ -4267,7 +4313,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) static const struct usb_ep_ops dwc2_hsotg_ep_ops = { .enable = dwc2_hsotg_ep_enable, - .disable = dwc2_hsotg_ep_disable, + .disable = dwc2_hsotg_ep_disable_lock, .alloc_request = dwc2_hsotg_ep_alloc_request, .free_request = dwc2_hsotg_ep_free_request, .queue = dwc2_hsotg_ep_queue_lock, @@ -4380,6 +4426,7 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); + gadget->sg_supported = using_desc_dma(hsotg); dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0; @@ -4407,9 +4454,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) /* all endpoints should be shutdown */ for (ep = 1; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) - dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); + dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); if (hsotg->eps_out[ep]) - dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); + dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); } spin_lock_irqsave(&hsotg->lock, flags); @@ -4857,9 +4904,9 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) for (ep = 0; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) - dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); + dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); if (hsotg->eps_out[ep]) - dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); + dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); } } @@ -5026,6 +5073,7 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; + val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC; dwc2_writel(hsotg, val, GLPMCFG); dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index dd82fa516f3f..3f087962f498 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3981,10 +3981,8 @@ static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags) { struct dwc2_hcd_urb *urb; - u32 size = sizeof(*urb) + iso_desc_count * - sizeof(struct dwc2_hcd_iso_packet_desc); - urb = kzalloc(size, mem_flags); + urb = kzalloc(struct_size(urb, iso_descs, iso_desc_count), mem_flags); if (urb) urb->packet_count = iso_desc_count; return urb; diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 3f9bccc95add..c089ffa1f0a8 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -366,7 +366,7 @@ struct dwc2_qh { u32 desc_list_sz; u32 *n_bytes; struct timer_list unreserve_timer; - struct timer_list wait_timer; + struct hrtimer wait_timer; struct dwc2_tt *dwc_tt; int ttport; unsigned tt_buffer_dirty:1; diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 40839591d2ec..ea3aa640c15c 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -59,7 +59,7 @@ #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5)) /* If we get a NAK, wait this long before retrying */ -#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1)) +#define DWC2_RETRY_WAIT_DELAY 1*1E6L /** * dwc2_periodic_channel_available() - Checks that a channel is available for a @@ -1464,10 +1464,12 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg, * qh back to the "inactive" list, then queues transactions. * * @t: Pointer to wait_timer in a qh. + * + * Return: HRTIMER_NORESTART to not automatically restart this timer. */ -static void dwc2_wait_timer_fn(struct timer_list *t) +static enum hrtimer_restart dwc2_wait_timer_fn(struct hrtimer *t) { - struct dwc2_qh *qh = from_timer(qh, t, wait_timer); + struct dwc2_qh *qh = container_of(t, struct dwc2_qh, wait_timer); struct dwc2_hsotg *hsotg = qh->hsotg; unsigned long flags; @@ -1491,6 +1493,7 @@ static void dwc2_wait_timer_fn(struct timer_list *t) } spin_unlock_irqrestore(&hsotg->lock, flags); + return HRTIMER_NORESTART; } /** @@ -1521,7 +1524,8 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, /* Initialize QH */ qh->hsotg = hsotg; timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0); - timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0); + hrtimer_init(&qh->wait_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + qh->wait_timer.function = &dwc2_wait_timer_fn; qh->ep_type = ep_type; qh->ep_is_in = ep_is_in; @@ -1690,7 +1694,7 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) * won't do anything anyway, but we want it to finish before we free * memory. */ - del_timer_sync(&qh->wait_timer); + hrtimer_cancel(&qh->wait_timer); dwc2_host_put_tt_info(hsotg, qh->dwc_tt); @@ -1716,6 +1720,7 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { int status; u32 intr_mask; + ktime_t delay; if (dbg_qh(qh)) dev_vdbg(hsotg->dev, "%s()\n", __func__); @@ -1734,8 +1739,8 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) list_add_tail(&qh->qh_list_entry, &hsotg->non_periodic_sched_waiting); qh->wait_timer_cancel = false; - mod_timer(&qh->wait_timer, - jiffies + DWC2_RETRY_WAIT_DELAY + 1); + delay = ktime_set(0, DWC2_RETRY_WAIT_DELAY); + hrtimer_start(&qh->wait_timer, delay, HRTIMER_MODE_REL); } else { list_add_tail(&qh->qh_list_entry, &hsotg->non_periodic_sched_inactive); diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 2b1ea441b7d4..98af924a9a5c 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -333,6 +333,8 @@ #define GLPMCFG_SNDLPM BIT(24) #define GLPMCFG_RETRY_CNT_MASK (0x7 << 21) #define GLPMCFG_RETRY_CNT_SHIFT 21 +#define GLPMCFG_LPM_ACCEPT_CTRL_CONTROL BIT(21) +#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22) #define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17) #define GLPMCFG_LPM_CHNL_INDX_SHIFT 17 #define GLPMCFG_L1RESUMEOK BIT(16) diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 7c1b6938f212..24ff5f21cb25 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -71,6 +71,13 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) p->power_down = false; } +static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg) +{ + struct dwc2_core_params *p = &hsotg->params; + + p->power_down = 0; +} + static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) { struct dwc2_core_params *p = &hsotg->params; @@ -111,6 +118,7 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 << GAHBCFG_HBSTLEN_SHIFT; + p->power_down = DWC2_POWER_DOWN_PARAM_NONE; } static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) @@ -151,7 +159,8 @@ const struct of_device_id dwc2_of_match_table[] = { { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params }, { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params }, { .compatible = "snps,dwc2" }, - { .compatible = "samsung,s3c6400-hsotg" }, + { .compatible = "samsung,s3c6400-hsotg", + .data = dwc2_set_s3c6400_params }, { .compatible = "amlogic,meson8-usb", .data = dwc2_set_amlogic_params }, { .compatible = "amlogic,meson8b-usb", diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 1a0404fda596..2b1494460d0c 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) && HAS_DMA @@ -86,11 +88,11 @@ config USB_DWC3_HAPS platform, please say 'Y' or 'M' here. config USB_DWC3_KEYSTONE - tristate "Texas Instruments Keystone2 Platforms" - depends on ARCH_KEYSTONE || COMPILE_TEST + tristate "Texas Instruments Keystone2/AM654 Platforms" + depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST default USB_DWC3 help - Support of USB2/3 functionality in TI Keystone2 platforms. + Support of USB2/3 functionality in TI Keystone2 and AM654 platforms. Say 'Y' or 'M' here if you have one such device config USB_DWC3_OF_SIMPLE diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 2f2048aa5fde..a1b126f90261 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -80,11 +80,12 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc) mode = USB_DR_MODE_PERIPHERAL; /* - * dwc_usb31 does not support OTG mode. If the controller - * supports DRD but the dr_mode is not specified or set to OTG, - * then set the mode to peripheral. + * DWC_usb31 and DWC_usb3 v3.30a and higher do not support OTG + * mode. If the controller supports DRD but the dr_mode is not + * specified or set to OTG, then set the mode to peripheral. */ - if (mode == USB_DR_MODE_OTG && dwc3_is_usb31(dwc)) + if (mode == USB_DR_MODE_OTG && + dwc->revision >= DWC3_REVISION_330A) mode = USB_DR_MODE_PERIPHERAL; } @@ -661,6 +662,8 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_enblslpm_quirk) reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + else + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; if (dwc->dis_u2_freeclk_exists_quirk) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; @@ -702,6 +705,7 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) /* Detected DWC_usb31 IP */ dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER); dwc->revision |= DWC3_REVISION_IS_DWC31; + dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE); } else { return false; } @@ -1244,8 +1248,12 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,is-utmi-l1-suspend"); device_property_read_u8(dev, "snps,hird-threshold", &hird_threshold); + dwc->dis_start_transfer_quirk = device_property_read_bool(dev, + "snps,dis-start-transfer-quirk"); dwc->usb3_lpm_capable = device_property_read_bool(dev, "snps,usb3_lpm_capable"); + dwc->usb2_lpm_disable = device_property_read_bool(dev, + "snps,usb2-lpm-disable"); device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd", &rx_thr_num_pkt_prd); device_property_read_u8(dev, "snps,rx-max-burst-prd", @@ -1482,7 +1490,8 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_core_init(dwc); if (ret) { - dev_err(dev, "failed to initialize core\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to initialize core: %d\n", ret); goto err4; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5bfb62533e0f..1528d395b156 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -37,6 +37,7 @@ #define DWC3_EP0_SETUP_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 +#define DWC3_ISOC_MAX_RETRIES 5 #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_BUFFERS_SIZE 4096 @@ -174,13 +175,19 @@ #define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */ #define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff +/* Global Debug LSP MUX Select */ +#define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */ +#define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff) +#define DWC3_GDBGLSPMUX_DEVSELECT(n) (((n) & 0xf) << 4) +#define DWC3_GDBGLSPMUX_EPSELECT(n) ((n) & 0xf) + /* Global Debug Queue/FIFO Space Available Register */ #define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f) #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) #define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff) -#define DWC3_TXFIFOQ 0 -#define DWC3_RXFIFOQ 1 +#define DWC3_TXFIFO 0 +#define DWC3_RXFIFO 1 #define DWC3_TXREQQ 2 #define DWC3_RXREQQ 3 #define DWC3_RXINFOQ 4 @@ -253,6 +260,9 @@ #define DWC3_GSTS_DEVICE_IP BIT(6) #define DWC3_GSTS_CSR_TIMEOUT BIT(5) #define DWC3_GSTS_BUS_ERR_ADDR_VLD BIT(4) +#define DWC3_GSTS_CURMOD(n) ((n) & 0x3) +#define DWC3_GSTS_CURMOD_DEVICE 0 +#define DWC3_GSTS_CURMOD_HOST 1 /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) @@ -321,6 +331,7 @@ #define DWC3_GHWPARAMS1_EN_PWROPT_HIB 2 #define DWC3_GHWPARAMS1_PWROPT(n) ((n) << 24) #define DWC3_GHWPARAMS1_PWROPT_MASK DWC3_GHWPARAMS1_PWROPT(3) +#define DWC3_GHWPARAMS1_ENDBC BIT(31) /* Global HWPARAMS3 Register */ #define DWC3_GHWPARAMS3_SSPHY_IFC(n) ((n) & 3) @@ -636,9 +647,9 @@ struct dwc3_event_buffer { /** * struct dwc3_ep - device side endpoint representation * @endpoint: usb endpoint + * @cancelled_list: list of cancelled requests for this endpoint * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint - * @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete * @lock: spinlock for endpoint request queue traversal * @regs: pointer to first endpoint register * @trb_pool: array of transaction buffers @@ -656,14 +667,17 @@ struct dwc3_event_buffer { * @name: a human readable name e.g. ep1out-bulk * @direction: true for TX, false for RX * @stream_capable: true when streams are enabled + * @combo_num: the test combination BIT[15:14] of the frame number to test + * isochronous START TRANSFER command failure workaround + * @start_cmd_status: the status of testing START TRANSFER command with + * combo_num = 'b00 */ struct dwc3_ep { struct usb_ep endpoint; + struct list_head cancelled_list; struct list_head pending_list; struct list_head started_list; - wait_queue_head_t wait_end_transfer; - spinlock_t lock; void __iomem *regs; @@ -678,7 +692,6 @@ struct dwc3_ep { #define DWC3_EP_WEDGE BIT(2) #define DWC3_EP_TRANSFER_STARTED BIT(3) #define DWC3_EP_PENDING_REQUEST BIT(5) -#define DWC3_EP_END_TRANSFER_PENDING BIT(7) /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN BIT(31) @@ -705,6 +718,10 @@ struct dwc3_ep { unsigned direction:1; unsigned stream_capable:1; + + /* For isochronous START TRANSFER workaround only */ + u8 combo_num; + int start_cmd_status; }; enum dwc3_phy { @@ -766,6 +783,7 @@ enum dwc3_link_state { #define DWC3_TRB_CTRL_ISP_IMI BIT(10) #define DWC3_TRB_CTRL_IOC BIT(11) #define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14) +#define DWC3_TRB_CTRL_GET_SID_SOFN(n) (((n) & (0xffff << 14)) >> 14) #define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4)) #define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1) @@ -844,14 +862,15 @@ struct dwc3_hwparams { * @num_pending_sgs: counter to pending sgs * @num_queued_sgs: counter to the number of sgs which already got queued * @remaining: amount of data remaining + * @status: internal dwc3 request status tracking * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb * @trb_dma: DMA address of @trb - * @unaligned: true for OUT endpoints with length not divisible by maxp + * @num_trbs: number of TRBs used by this request + * @needs_extra_trb: true when request needs one extra TRB (either due to ZLP + * or unaligned OUT) * @direction: IN or OUT direction flag * @mapped: true when request has been dma-mapped - * @started: request is started - * @zero: wants a ZLP */ struct dwc3_request { struct usb_request request; @@ -863,15 +882,23 @@ struct dwc3_request { unsigned num_pending_sgs; unsigned int num_queued_sgs; unsigned remaining; + + unsigned int status; +#define DWC3_REQUEST_STATUS_QUEUED 0 +#define DWC3_REQUEST_STATUS_STARTED 1 +#define DWC3_REQUEST_STATUS_CANCELLED 2 +#define DWC3_REQUEST_STATUS_COMPLETED 3 +#define DWC3_REQUEST_STATUS_UNKNOWN -1 + u8 epnum; struct dwc3_trb *trb; dma_addr_t trb_dma; - unsigned unaligned:1; + unsigned num_trbs; + + unsigned needs_extra_trb:1; unsigned direction:1; unsigned mapped:1; - unsigned started:1; - unsigned zero:1; }; /* @@ -918,6 +945,7 @@ struct dwc3_scratchpad_array { * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents + * @version_type: VERSIONTYPE register contents, a sub release of a revision * @dr_mode: requested mode of operation * @current_dr_role: current role of operation when in dual-role mode * @desired_dr_role: desired role of operation when in dual-role mode @@ -945,6 +973,7 @@ struct dwc3_scratchpad_array { * @hwparams: copy of hwparams registers * @root: debugfs root folder pointer * @regset: debugfs pointer to regdump file + * @dbg_lsp_select: current debug lsp mux register selection * @test_mode: true when we're entering a USB test mode * @test_mode_nr: test feature selector * @lpm_nyet_threshold: LPM NYET response threshold @@ -970,7 +999,10 @@ struct dwc3_scratchpad_array { * @pullups_connected: true when Run/Stop bit is set * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @three_stage_setup: set if we perform a three phase setup + * @dis_start_transfer_quirk: set if start_transfer failure SW workaround is + * not needed for DWC_usb31 version 1.70a-ea06 and below * @usb3_lpm_capable: set if hadrware supports Link Power Management + * @usb2_lpm_disable: set to disable usb2 lpm * @disable_scramble_quirk: set if we enable the disable scramble quirk * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk @@ -1095,6 +1127,7 @@ struct dwc3 { #define DWC3_REVISION_290A 0x5533290a #define DWC3_REVISION_300A 0x5533300a #define DWC3_REVISION_310A 0x5533310a +#define DWC3_REVISION_330A 0x5533330a /* * NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really @@ -1103,6 +1136,17 @@ struct dwc3 { #define DWC3_REVISION_IS_DWC31 0x80000000 #define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31) #define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) +#define DWC3_USB31_REVISION_160A (0x3136302a | DWC3_REVISION_IS_DWC31) +#define DWC3_USB31_REVISION_170A (0x3137302a | DWC3_REVISION_IS_DWC31) + + u32 version_type; + +#define DWC31_VERSIONTYPE_EA01 0x65613031 +#define DWC31_VERSIONTYPE_EA02 0x65613032 +#define DWC31_VERSIONTYPE_EA03 0x65613033 +#define DWC31_VERSIONTYPE_EA04 0x65613034 +#define DWC31_VERSIONTYPE_EA05 0x65613035 +#define DWC31_VERSIONTYPE_EA06 0x65613036 enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; @@ -1121,6 +1165,8 @@ struct dwc3 { struct dentry *root; struct debugfs_regset32 *regset; + u32 dbg_lsp_select; + u8 test_mode; u8 test_mode_nr; u8 lpm_nyet_threshold; @@ -1145,7 +1191,9 @@ struct dwc3 { unsigned pullups_connected:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; + unsigned dis_start_transfer_quirk:1; unsigned usb3_lpm_capable:1; + unsigned usb2_lpm_disable:1; unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index c66d216dcc30..6759a7efd8d5 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -117,6 +117,35 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state) } /** + * dwc3_gadget_hs_link_string - returns highspeed and below link name + * @link_state: link state code + */ +static inline const char * +dwc3_gadget_hs_link_string(enum dwc3_link_state link_state) +{ + switch (link_state) { + case DWC3_LINK_STATE_U0: + return "On"; + case DWC3_LINK_STATE_U2: + return "Sleep"; + case DWC3_LINK_STATE_U3: + return "Suspend"; + case DWC3_LINK_STATE_SS_DIS: + return "Disconnected"; + case DWC3_LINK_STATE_RX_DET: + return "Early Suspend"; + case DWC3_LINK_STATE_RECOV: + return "Recovery"; + case DWC3_LINK_STATE_RESET: + return "Reset"; + case DWC3_LINK_STATE_RESUME: + return "Resume"; + default: + return "UNKNOWN link state\n"; + } +} + +/** * dwc3_trb_type_string - returns TRB type as a string * @type: the type of the TRB */ @@ -164,65 +193,69 @@ static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) * dwc3_gadget_event_string - returns event name * @event: the event code */ -static inline const char * -dwc3_gadget_event_string(char *str, const struct dwc3_event_devt *event) +static inline const char *dwc3_gadget_event_string(char *str, size_t size, + const struct dwc3_event_devt *event) { enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK; switch (event->type) { case DWC3_DEVICE_EVENT_DISCONNECT: - sprintf(str, "Disconnect: [%s]", + snprintf(str, size, "Disconnect: [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_RESET: - sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "Reset [%s]", + dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CONNECT_DONE: - sprintf(str, "Connection Done [%s]", + snprintf(str, size, "Connection Done [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: - sprintf(str, "Link Change [%s]", + snprintf(str, size, "Link Change [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_WAKEUP: - sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "WakeUp [%s]", + dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_EOPF: - sprintf(str, "End-Of-Frame [%s]", + snprintf(str, size, "End-Of-Frame [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_SOF: - sprintf(str, "Start-Of-Frame [%s]", + snprintf(str, size, "Start-Of-Frame [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - sprintf(str, "Erratic Error [%s]", + snprintf(str, size, "Erratic Error [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CMD_CMPL: - sprintf(str, "Command Complete [%s]", + snprintf(str, size, "Command Complete [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_OVERFLOW: - sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "Overflow [%s]", + dwc3_gadget_link_string(state)); break; default: - sprintf(str, "UNKNOWN"); + snprintf(str, size, "UNKNOWN"); } return str; } -static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str) +static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str, + size_t size) { switch (t & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: - sprintf(str, "Get Interface Status(Intf = %d, Length = %d)", - i, l); + snprintf(str, size, "Get Interface Status(Intf = %d, Length = %d)", + i, l); break; case USB_RECIP_ENDPOINT: - sprintf(str, "Get Endpoint Status(ep%d%s)", + snprintf(str, size, "Get Endpoint Status(ep%d%s)", i & ~USB_DIR_IN, i & USB_DIR_IN ? "in" : "out"); break; @@ -230,11 +263,11 @@ static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str) } static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, - __u16 i, char *str) + __u16 i, char *str, size_t size) { switch (t & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - sprintf(str, "%s Device Feature(%s%s)", + snprintf(str, size, "%s Device Feature(%s%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", ({char *s; switch (v) { @@ -282,13 +315,13 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, } s; }) : ""); break; case USB_RECIP_INTERFACE: - sprintf(str, "%s Interface Feature(%s)", + snprintf(str, size, "%s Interface Feature(%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", v == USB_INTRF_FUNC_SUSPEND ? "Function Suspend" : "UNKNOWN"); break; case USB_RECIP_ENDPOINT: - sprintf(str, "%s Endpoint Feature(%s ep%d%s)", + snprintf(str, size, "%s Endpoint Feature(%s ep%d%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", v == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN", i & ~USB_DIR_IN, @@ -297,15 +330,15 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, } } -static inline void dwc3_decode_set_address(__u16 v, char *str) +static inline void dwc3_decode_set_address(__u16 v, char *str, size_t size) { - sprintf(str, "Set Address(Addr = %02x)", v); + snprintf(str, size, "Set Address(Addr = %02x)", v); } static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v, - __u16 i, __u16 l, char *str) + __u16 i, __u16 l, char *str, size_t size) { - sprintf(str, "%s %s Descriptor(Index = %d, Length = %d)", + snprintf(str, size, "%s %s Descriptor(Index = %d, Length = %d)", b == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set", ({ char *s; switch (v >> 8) { @@ -364,87 +397,92 @@ static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v, } -static inline void dwc3_decode_get_configuration(__u16 l, char *str) +static inline void dwc3_decode_get_configuration(__u16 l, char *str, + size_t size) { - sprintf(str, "Get Configuration(Length = %d)", l); + snprintf(str, size, "Get Configuration(Length = %d)", l); } -static inline void dwc3_decode_set_configuration(__u8 v, char *str) +static inline void dwc3_decode_set_configuration(__u8 v, char *str, size_t size) { - sprintf(str, "Set Configuration(Config = %d)", v); + snprintf(str, size, "Set Configuration(Config = %d)", v); } -static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str) +static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str, + size_t size) { - sprintf(str, "Get Interface(Intf = %d, Length = %d)", i, l); + snprintf(str, size, "Get Interface(Intf = %d, Length = %d)", i, l); } -static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str) +static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str, size_t size) { - sprintf(str, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v); + snprintf(str, size, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v); } -static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str) +static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str, + size_t size) { - sprintf(str, "Synch Frame(Endpoint = %d, Length = %d)", i, l); + snprintf(str, size, "Synch Frame(Endpoint = %d, Length = %d)", i, l); } -static inline void dwc3_decode_set_sel(__u16 l, char *str) +static inline void dwc3_decode_set_sel(__u16 l, char *str, size_t size) { - sprintf(str, "Set SEL(Length = %d)", l); + snprintf(str, size, "Set SEL(Length = %d)", l); } -static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str) +static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str, size_t size) { - sprintf(str, "Set Isochronous Delay(Delay = %d ns)", v); + snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", v); } /** * dwc3_decode_ctrl - returns a string represetion of ctrl request */ -static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, - __u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength) +static inline const char *dwc3_decode_ctrl(char *str, size_t size, + __u8 bRequestType, __u8 bRequest, __u16 wValue, __u16 wIndex, + __u16 wLength) { switch (bRequest) { case USB_REQ_GET_STATUS: - dwc3_decode_get_status(bRequestType, wIndex, wLength, str); + dwc3_decode_get_status(bRequestType, wIndex, wLength, str, + size); break; case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: dwc3_decode_set_clear_feature(bRequestType, bRequest, wValue, - wIndex, str); + wIndex, str, size); break; case USB_REQ_SET_ADDRESS: - dwc3_decode_set_address(wValue, str); + dwc3_decode_set_address(wValue, str, size); break; case USB_REQ_GET_DESCRIPTOR: case USB_REQ_SET_DESCRIPTOR: dwc3_decode_get_set_descriptor(bRequestType, bRequest, wValue, - wIndex, wLength, str); + wIndex, wLength, str, size); break; case USB_REQ_GET_CONFIGURATION: - dwc3_decode_get_configuration(wLength, str); + dwc3_decode_get_configuration(wLength, str, size); break; case USB_REQ_SET_CONFIGURATION: - dwc3_decode_set_configuration(wValue, str); + dwc3_decode_set_configuration(wValue, str, size); break; case USB_REQ_GET_INTERFACE: - dwc3_decode_get_intf(wIndex, wLength, str); + dwc3_decode_get_intf(wIndex, wLength, str, size); break; case USB_REQ_SET_INTERFACE: - dwc3_decode_set_intf(wValue, wIndex, str); + dwc3_decode_set_intf(wValue, wIndex, str, size); break; case USB_REQ_SYNCH_FRAME: - dwc3_decode_synch_frame(wIndex, wLength, str); + dwc3_decode_synch_frame(wIndex, wLength, str, size); break; case USB_REQ_SET_SEL: - dwc3_decode_set_sel(wLength, str); + dwc3_decode_set_sel(wLength, str, size); break; case USB_REQ_SET_ISOCH_DELAY: - dwc3_decode_set_isoch_delay(wValue, str); + dwc3_decode_set_isoch_delay(wValue, str, size); break; default: - sprintf(str, "%02x %02x %02x %02x %02x %02x %02x %02x", + snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x", bRequestType, bRequest, cpu_to_le16(wValue) & 0xff, cpu_to_le16(wValue) >> 8, @@ -461,16 +499,15 @@ static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, * dwc3_ep_event_string - returns event name * @event: then event code */ -static inline const char * -dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, - u32 ep0state) +static inline const char *dwc3_ep_event_string(char *str, size_t size, + const struct dwc3_event_depevt *event, u32 ep0state) { u8 epnum = event->endpoint_number; size_t len; int status; int ret; - ret = sprintf(str, "ep%d%s: ", epnum >> 1, + ret = snprintf(str, size, "ep%d%s: ", epnum >> 1, (epnum & 1) ? "in" : "out"); if (ret < 0) return "UNKNOWN"; @@ -480,7 +517,7 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: len = strlen(str); - sprintf(str + len, "Transfer Complete (%c%c%c)", + snprintf(str + len, size - len, "Transfer Complete (%c%c%c)", status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', status & DEPEVT_STATUS_LST ? 'L' : 'l'); @@ -488,12 +525,13 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, len = strlen(str); if (epnum <= 1) - sprintf(str + len, " [%s]", dwc3_ep0_state_string(ep0state)); + snprintf(str + len, size - len, " [%s]", + dwc3_ep0_state_string(ep0state)); break; case DWC3_DEPEVT_XFERINPROGRESS: len = strlen(str); - sprintf(str + len, "Transfer In Progress [%d] (%c%c%c)", + snprintf(str + len, size - len, "Transfer In Progress [%d] (%c%c%c)", event->parameters, status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', @@ -502,47 +540,51 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, case DWC3_DEPEVT_XFERNOTREADY: len = strlen(str); - sprintf(str + len, "Transfer Not Ready [%d]%s", + snprintf(str + len, size - len, "Transfer Not Ready [%d]%s", event->parameters, status & DEPEVT_STATUS_TRANSFER_ACTIVE ? " (Active)" : " (Not Active)"); + len = strlen(str); + /* Control Endpoints */ if (epnum <= 1) { int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status); switch (phase) { case DEPEVT_STATUS_CONTROL_DATA: - strcat(str, " [Data Phase]"); + snprintf(str + ret, size - ret, + " [Data Phase]"); break; case DEPEVT_STATUS_CONTROL_STATUS: - strcat(str, " [Status Phase]"); + snprintf(str + ret, size - ret, + " [Status Phase]"); } } break; case DWC3_DEPEVT_RXTXFIFOEVT: - strcat(str, "FIFO"); + snprintf(str + ret, size - ret, "FIFO"); break; case DWC3_DEPEVT_STREAMEVT: status = event->status; switch (status) { case DEPEVT_STREAMEVT_FOUND: - sprintf(str + ret, " Stream %d Found", + snprintf(str + ret, size - ret, " Stream %d Found", event->parameters); break; case DEPEVT_STREAMEVT_NOTFOUND: default: - strcat(str, " Stream Not Found"); + snprintf(str + ret, size - ret, " Stream Not Found"); break; } break; case DWC3_DEPEVT_EPCMDCMPLT: - strcat(str, "Endpoint Command Complete"); + snprintf(str + ret, size - ret, "Endpoint Command Complete"); break; default: - sprintf(str, "UNKNOWN"); + snprintf(str, size, "UNKNOWN"); } return str; @@ -582,14 +624,15 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) } } -static inline const char *dwc3_decode_event(char *str, u32 event, u32 ep0state) +static inline const char *dwc3_decode_event(char *str, size_t size, u32 event, + u32 ep0state) { const union dwc3_event evt = (union dwc3_event) event; if (evt.type.is_devspec) - return dwc3_gadget_event_string(str, &evt.devt); + return dwc3_gadget_event_string(str, size, &evt.devt); else - return dwc3_ep_event_string(str, &evt.depevt, ep0state); + return dwc3_ep_event_string(str, size, &evt.depevt, ep0state); } static inline const char *dwc3_ep_cmd_status_string(int status) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index df8e73ec3342..1c792710348f 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -25,6 +25,8 @@ #include "io.h" #include "debug.h" +#define DWC3_LSP_MUX_UNSELECTED 0xfffff + #define dump_register(nm) \ { \ .name = __stringify(nm), \ @@ -82,10 +84,6 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GDBGFIFOSPACE), dump_register(GDBGLTSSM), dump_register(GDBGBMU), - dump_register(GDBGLSPMUX), - dump_register(GDBGLSP), - dump_register(GDBGEPINFO0), - dump_register(GDBGEPINFO1), dump_register(GPRTBIMAP_HS0), dump_register(GPRTBIMAP_HS1), dump_register(GPRTBIMAP_FS0), @@ -279,6 +277,114 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(OSTS), }; +static void dwc3_host_lsp(struct seq_file *s) +{ + struct dwc3 *dwc = s->private; + bool dbc_enabled; + u32 sel; + u32 reg; + u32 val; + + dbc_enabled = !!(dwc->hwparams.hwparams1 & DWC3_GHWPARAMS1_ENDBC); + + sel = dwc->dbg_lsp_select; + if (sel == DWC3_LSP_MUX_UNSELECTED) { + seq_puts(s, "Write LSP selection to print for host\n"); + return; + } + + reg = DWC3_GDBGLSPMUX_HOSTSELECT(sel); + + dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); + val = dwc3_readl(dwc->regs, DWC3_GDBGLSP); + seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", sel, val); + + if (dbc_enabled && sel < 256) { + reg |= DWC3_GDBGLSPMUX_ENDBC; + dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); + val = dwc3_readl(dwc->regs, DWC3_GDBGLSP); + seq_printf(s, "GDBGLSP_DBC[%d] = 0x%08x\n", sel, val); + } +} + +static void dwc3_gadget_lsp(struct seq_file *s) +{ + struct dwc3 *dwc = s->private; + int i; + u32 reg; + + for (i = 0; i < 16; i++) { + reg = DWC3_GDBGLSPMUX_DEVSELECT(i); + dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); + reg = dwc3_readl(dwc->regs, DWC3_GDBGLSP); + seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", i, reg); + } +} + +static int dwc3_lsp_show(struct seq_file *s, void *unused) +{ + struct dwc3 *dwc = s->private; + unsigned int current_mode; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&dwc->lock, flags); + reg = dwc3_readl(dwc->regs, DWC3_GSTS); + current_mode = DWC3_GSTS_CURMOD(reg); + + switch (current_mode) { + case DWC3_GSTS_CURMOD_HOST: + dwc3_host_lsp(s); + break; + case DWC3_GSTS_CURMOD_DEVICE: + dwc3_gadget_lsp(s); + break; + default: + seq_puts(s, "Mode is unknown, no LSP register printed\n"); + break; + } + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_lsp_open(struct inode *inode, struct file *file) +{ + return single_open(file, dwc3_lsp_show, inode->i_private); +} + +static ssize_t dwc3_lsp_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct dwc3 *dwc = s->private; + unsigned long flags; + char buf[32] = { 0 }; + u32 sel; + int ret; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = kstrtouint(buf, 0, &sel); + if (ret) + return ret; + + spin_lock_irqsave(&dwc->lock, flags); + dwc->dbg_lsp_select = sel; + spin_unlock_irqrestore(&dwc->lock, flags); + + return count; +} + +static const struct file_operations dwc3_lsp_fops = { + .open = dwc3_lsp_open, + .write = dwc3_lsp_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int dwc3_mode_show(struct seq_file *s, void *unused) { struct dwc3 *dwc = s->private; @@ -433,13 +539,24 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) unsigned long flags; enum dwc3_link_state state; u32 reg; + u8 speed; spin_lock_irqsave(&dwc->lock, flags); + reg = dwc3_readl(dwc->regs, DWC3_GSTS); + if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { + seq_puts(s, "Not available\n"); + spin_unlock_irqrestore(&dwc->lock, flags); + return 0; + } + reg = dwc3_readl(dwc->regs, DWC3_DSTS); state = DWC3_DSTS_USBLNKST(reg); - spin_unlock_irqrestore(&dwc->lock, flags); + speed = reg & DWC3_DSTS_CONNECTSPD; - seq_printf(s, "%s\n", dwc3_gadget_link_string(state)); + seq_printf(s, "%s\n", (speed >= DWC3_DSTS_SUPERSPEED) ? + dwc3_gadget_link_string(state) : + dwc3_gadget_hs_link_string(state)); + spin_unlock_irqrestore(&dwc->lock, flags); return 0; } @@ -457,6 +574,8 @@ static ssize_t dwc3_link_state_write(struct file *file, unsigned long flags; enum dwc3_link_state state = 0; char buf[32]; + u32 reg; + u8 speed; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; @@ -477,6 +596,21 @@ static ssize_t dwc3_link_state_write(struct file *file, return -EINVAL; spin_lock_irqsave(&dwc->lock, flags); + reg = dwc3_readl(dwc->regs, DWC3_GSTS); + if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + speed = reg & DWC3_DSTS_CONNECTSPD; + + if (speed < DWC3_DSTS_SUPERSPEED && + state != DWC3_LINK_STATE_RECOV) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + dwc3_gadget_set_link_state(dwc, state); spin_unlock_irqrestore(&dwc->lock, flags); @@ -496,7 +630,7 @@ struct dwc3_ep_file_map { const struct file_operations *const fops; }; -static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused) +static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused) { struct dwc3_ep *dep = s->private; struct dwc3 *dwc = dep->dwc; @@ -504,14 +638,18 @@ static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused) u32 val; spin_lock_irqsave(&dwc->lock, flags); - val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ); + val = dwc3_core_fifo_space(dep, DWC3_TXFIFO); + + /* Convert to bytes */ + val *= DWC3_MDWIDTH(dwc->hwparams.hwparams0); + val >>= 3; seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); return 0; } -static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused) +static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused) { struct dwc3_ep *dep = s->private; struct dwc3 *dwc = dep->dwc; @@ -519,7 +657,11 @@ static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused) u32 val; spin_lock_irqsave(&dwc->lock, flags); - val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ); + val = dwc3_core_fifo_space(dep, DWC3_RXFIFO); + + /* Convert to bytes */ + val *= DWC3_MDWIDTH(dwc->hwparams.hwparams0); + val >>= 3; seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); @@ -675,8 +817,32 @@ out: return 0; } -DEFINE_SHOW_ATTRIBUTE(dwc3_tx_fifo_queue); -DEFINE_SHOW_ATTRIBUTE(dwc3_rx_fifo_queue); +static int dwc3_ep_info_register_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u64 ep_info; + u32 lower_32_bits; + u32 upper_32_bits; + u32 reg; + + spin_lock_irqsave(&dwc->lock, flags); + reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number); + dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); + + lower_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO0); + upper_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO1); + + ep_info = ((u64)upper_32_bits << 32) | lower_32_bits; + seq_printf(s, "0x%016llx\n", ep_info); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(dwc3_tx_fifo_size); +DEFINE_SHOW_ATTRIBUTE(dwc3_rx_fifo_size); DEFINE_SHOW_ATTRIBUTE(dwc3_tx_request_queue); DEFINE_SHOW_ATTRIBUTE(dwc3_rx_request_queue); DEFINE_SHOW_ATTRIBUTE(dwc3_rx_info_queue); @@ -684,10 +850,11 @@ DEFINE_SHOW_ATTRIBUTE(dwc3_descriptor_fetch_queue); DEFINE_SHOW_ATTRIBUTE(dwc3_event_queue); DEFINE_SHOW_ATTRIBUTE(dwc3_transfer_type); DEFINE_SHOW_ATTRIBUTE(dwc3_trb_ring); +DEFINE_SHOW_ATTRIBUTE(dwc3_ep_info_register); static const struct dwc3_ep_file_map dwc3_ep_file_map[] = { - { "tx_fifo_queue", &dwc3_tx_fifo_queue_fops, }, - { "rx_fifo_queue", &dwc3_rx_fifo_queue_fops, }, + { "tx_fifo_size", &dwc3_tx_fifo_size_fops, }, + { "rx_fifo_size", &dwc3_rx_fifo_size_fops, }, { "tx_request_queue", &dwc3_tx_request_queue_fops, }, { "rx_request_queue", &dwc3_rx_request_queue_fops, }, { "rx_info_queue", &dwc3_rx_info_queue_fops, }, @@ -695,6 +862,7 @@ static const struct dwc3_ep_file_map dwc3_ep_file_map[] = { { "event_queue", &dwc3_event_queue_fops, }, { "transfer_type", &dwc3_transfer_type_fops, }, { "trb_ring", &dwc3_trb_ring_fops, }, + { "GDBGEPINFO", &dwc3_ep_info_register_fops, }, }; static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep, @@ -742,6 +910,8 @@ void dwc3_debugfs_init(struct dwc3 *dwc) if (!dwc->regset) return; + dwc->dbg_lsp_select = DWC3_LSP_MUX_UNSELECTED; + dwc->regset->regs = dwc3_regs; dwc->regset->nregs = ARRAY_SIZE(dwc3_regs); dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START; @@ -751,6 +921,9 @@ void dwc3_debugfs_init(struct dwc3 *dwc) debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset); + debugfs_create_file("lsp_dump", S_IRUGO | S_IWUSR, root, dwc, + &dwc3_lsp_fops); + if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) { debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, dwc, &dwc3_mode_fops); diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 218371f985ca..726100d1ac0d 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -10,6 +10,7 @@ #include <linux/extcon.h> #include <linux/of_graph.h> #include <linux/platform_device.h> +#include <linux/property.h> #include "debug.h" #include "core.h" @@ -445,9 +446,24 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) struct device *dev = dwc->dev; struct device_node *np_phy, *np_conn; struct extcon_dev *edev; + const char *name; - if (of_property_read_bool(dev->of_node, "extcon")) - return extcon_get_edev_by_phandle(dwc->dev, 0); + if (device_property_read_bool(dev, "extcon")) + return extcon_get_edev_by_phandle(dev, 0); + + /* + * Device tree platforms should get extcon via phandle. + * On ACPI platforms, we get the name from a device property. + * This device property is for kernel internal use only and + * is expected to be set by the glue code. + */ + if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) { + edev = extcon_get_extcon_dev(name); + if (!edev) + return ERR_PTR(-EPROBE_DEFER); + + return edev; + } np_phy = of_parse_phandle(dev->of_node, "phys", 0); np_conn = of_graph_get_remote_node(np_phy, -1, -1); diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index cb7fcd7c0ad8..c1e9ea621f41 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -78,7 +78,7 @@ static int dwc3_exynos_probe(struct platform_device *pdev) for (i = 0; i < exynos->num_clks; i++) { ret = clk_prepare_enable(exynos->clks[i]); if (ret) { - while (--i > 0) + while (i-- > 0) clk_disable_unprepare(exynos->clks[i]); return ret; } @@ -223,7 +223,7 @@ static int dwc3_exynos_resume(struct device *dev) for (i = 0; i < exynos->num_clks; i++) { ret = clk_prepare_enable(exynos->clks[i]); if (ret) { - while (--i > 0) + while (i-- > 0) clk_disable_unprepare(exynos->clks[i]); return ret; } diff --git a/drivers/usb/dwc3/dwc3-haps.c b/drivers/usb/dwc3/dwc3-haps.c index c9cc33881bef..3cecbf169452 100644 --- a/drivers/usb/dwc3/dwc3-haps.c +++ b/drivers/usb/dwc3/dwc3-haps.c @@ -15,10 +15,6 @@ #include <linux/platform_device.h> #include <linux/property.h> -#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd -#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce -#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf - /** * struct dwc3_haps - Driver private structure * @dwc3: child dwc3 platform_device @@ -110,6 +106,15 @@ static const struct pci_device_id dwc3_haps_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), + /* + * i.MX6QP and i.MX7D platform use a PCIe controller with the + * same VID and PID as this USB controller. The system may + * incorrectly match this driver to that PCIe controller. To + * workaround this, specifically use class type USB to prevent + * incorrect driver matching. + */ + .class = (PCI_CLASS_SERIAL_USB << 8), + .class_mask = 0xffff00, }, { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 193a9a88222a..cbee5fb9b9fb 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -106,6 +106,10 @@ static int kdwc3_probe(struct platform_device *pdev) goto err_irq; } + /* IRQ processing not required currently for AM65 */ + if (of_device_is_compatible(node, "ti,am654-dwc3")) + goto skip_irq; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "missing irq\n"); @@ -123,6 +127,7 @@ static int kdwc3_probe(struct platform_device *pdev) kdwc3_enable_irqs(kdwc); +skip_irq: error = of_platform_populate(node, NULL, NULL, dev); if (error) { dev_err(&pdev->dev, "failed to create dwc3 core\n"); @@ -152,8 +157,11 @@ static int kdwc3_remove_core(struct device *dev, void *c) static int kdwc3_remove(struct platform_device *pdev) { struct dwc3_keystone *kdwc = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + if (!of_device_is_compatible(node, "ti,am654-dwc3")) + kdwc3_disable_irqs(kdwc); - kdwc3_disable_irqs(kdwc); device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); pm_runtime_put_sync(kdwc->dev); pm_runtime_disable(kdwc->dev); @@ -165,6 +173,7 @@ static int kdwc3_remove(struct platform_device *pdev) static const struct of_device_id kdwc3_of_match[] = { { .compatible = "ti,keystone-dwc3", }, + { .compatible = "ti,am654-dwc3" }, {}, }; MODULE_DEVICE_TABLE(of, kdwc3_of_match); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 842795856bf4..8cced3609e24 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -29,6 +29,7 @@ #define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa #define PCI_DEVICE_ID_INTEL_KBP 0xa2b0 +#define PCI_DEVICE_ID_INTEL_CMLH 0x02ee #define PCI_DEVICE_ID_INTEL_GLK 0x31aa #define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e @@ -170,20 +171,20 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc) * put the gpio descriptors again here because the phy driver * might want to grab them, too. */ - gpio = devm_gpiod_get_optional(&pdev->dev, "cs", - GPIOD_OUT_LOW); + gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW); if (IS_ERR(gpio)) return PTR_ERR(gpio); gpiod_set_value_cansleep(gpio, 1); + gpiod_put(gpio); - gpio = devm_gpiod_get_optional(&pdev->dev, "reset", - GPIOD_OUT_LOW); + gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(gpio)) return PTR_ERR(gpio); if (gpio) { gpiod_set_value_cansleep(gpio, 1); + gpiod_put(gpio); usleep_range(10000, 11000); } } @@ -305,6 +306,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD), (kernel_ulong_t) &dwc3_pci_mrfld_properties, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH), + (kernel_ulong_t) &dwc3_pci_intel_properties, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP), (kernel_ulong_t) &dwc3_pci_intel_properties, }, diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index a6d0203e40b6..184df4daa590 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -595,6 +595,7 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { static const struct of_device_id dwc3_qcom_of_match[] = { { .compatible = "qcom,dwc3" }, { .compatible = "qcom,msm8996-dwc3" }, + { .compatible = "qcom,msm8998-dwc3" }, { .compatible = "qcom,sdm845-dwc3" }, { } }; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9f92ee03dde7..e293400cc6e9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -27,7 +27,7 @@ #include "gadget.h" #include "io.h" -#define DWC3_ALIGN_FRAME(d) (((d)->frame_number + (d)->interval) \ +#define DWC3_ALIGN_FRAME(d, n) (((d)->frame_number + ((d)->interval * (n))) \ & ~((d)->interval - 1)) /** @@ -174,9 +174,9 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, { struct dwc3 *dwc = dep->dwc; - req->started = false; list_del(&req->list); req->remaining = 0; + req->needs_extra_trb = false; if (req->request.status == -EINPROGRESS) req->request.status = status; @@ -208,6 +208,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, struct dwc3 *dwc = dep->dwc; dwc3_gadget_del_and_unmap_request(dep, req, status); + req->status = DWC3_REQUEST_STATUS_COMPLETED; spin_unlock(&dwc->lock); usb_gadget_giveback_request(&dep->endpoint, &req->request); @@ -383,19 +384,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status); - if (ret == 0) { - switch (DWC3_DEPCMD_CMD(cmd)) { - case DWC3_DEPCMD_STARTTRANSFER: - dep->flags |= DWC3_EP_TRANSFER_STARTED; - dwc3_gadget_ep_get_transfer_index(dep); - break; - case DWC3_DEPCMD_ENDTRANSFER: - dep->flags &= ~DWC3_EP_TRANSFER_STARTED; - break; - default: - /* nothing */ - break; - } + if (ret == 0 && DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { + dep->flags |= DWC3_EP_TRANSFER_STARTED; + dwc3_gadget_ep_get_transfer_index(dep); } if (saved_config) { @@ -641,14 +632,11 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; - dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg |= DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); - init_waitqueue_head(&dep->wait_end_transfer); - if (usb_endpoint_xfer_control(desc)) goto out; @@ -672,7 +660,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) * Issue StartTransfer here with no-op TRB so we can always rely on No * Response Update Transfer command. */ - if (usb_endpoint_xfer_bulk(desc) || + if ((usb_endpoint_xfer_bulk(desc) && !dep->stream_capable) || usb_endpoint_xfer_int(desc)) { struct dwc3_gadget_ep_cmd_params params; struct dwc3_trb *trb; @@ -699,12 +687,13 @@ out: return 0; } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force); +static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, + bool interrupt); static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, false); /* - giveback all requests to gadget driver */ while (!list_empty(&dep->started_list)) { @@ -749,7 +738,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->stream_capable = false; dep->type = 0; - dep->flags &= DWC3_EP_END_TRANSFER_PENDING; + dep->flags = 0; /* Clear out the ep descriptors for non-ep0 */ if (dep->number > 1) { @@ -848,6 +837,7 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep, req->direction = dep->direction; req->epnum = dep->number; req->dep = dep; + req->status = DWC3_REQUEST_STATUS_UNKNOWN; trace_dwc3_alloc_request(req); @@ -919,8 +909,6 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, struct usb_gadget *gadget = &dwc->gadget; enum usb_device_speed speed = gadget->speed; - dwc3_ep_inc_enq(dep); - trb->size = DWC3_TRB_SIZE_LENGTH(length); trb->bpl = lower_32_bits(dma); trb->bph = upper_32_bits(dma); @@ -990,16 +978,20 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, usb_endpoint_type(dep->endpoint.desc)); } - /* always enable Continue on Short Packet */ + /* + * Enable Continue on Short Packet + * when endpoint is not a stream capable + */ if (usb_endpoint_dir_out(dep->endpoint.desc)) { - trb->ctrl |= DWC3_TRB_CTRL_CSP; + if (!dep->stream_capable) + trb->ctrl |= DWC3_TRB_CTRL_CSP; if (short_not_ok) trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; } if ((!no_interrupt && !chain) || - (dwc3_calc_trbs_left(dep) == 0)) + (dwc3_calc_trbs_left(dep) == 1)) trb->ctrl |= DWC3_TRB_CTRL_IOC; if (chain) @@ -1010,6 +1002,8 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, trb->ctrl |= DWC3_TRB_CTRL_HWO; + dwc3_ep_inc_enq(dep); + trace_dwc3_prepare_trb(dep, trb); } @@ -1046,6 +1040,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, req->trb_dma = dwc3_trb_dma_offset(dep, trb); } + req->num_trbs++; + __dwc3_prepare_one_trb(dep, trb, dma, length, chain, node, stream_id, short_not_ok, no_interrupt); } @@ -1073,13 +1069,14 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, struct dwc3 *dwc = dep->dwc; struct dwc3_trb *trb; - req->unaligned = true; + req->needs_extra_trb = true; /* prepare normal TRB */ dwc3_prepare_one_trb(dep, req, true, i); /* Now prepare one extra TRB to align transfer size */ trb = &dep->trb_pool[dep->trb_enqueue]; + req->num_trbs++; __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem, false, 1, req->request.stream_id, @@ -1113,17 +1110,18 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); unsigned int rem = length % maxp; - if (rem && usb_endpoint_dir_out(dep->endpoint.desc)) { + if ((!length || rem) && usb_endpoint_dir_out(dep->endpoint.desc)) { struct dwc3 *dwc = dep->dwc; struct dwc3_trb *trb; - req->unaligned = true; + req->needs_extra_trb = true; /* prepare normal TRB */ dwc3_prepare_one_trb(dep, req, true, 0); /* Now prepare one extra TRB to align transfer size */ trb = &dep->trb_pool[dep->trb_enqueue]; + req->num_trbs++; __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem, false, 1, req->request.stream_id, req->request.short_not_ok, @@ -1133,13 +1131,14 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, struct dwc3 *dwc = dep->dwc; struct dwc3_trb *trb; - req->zero = true; + req->needs_extra_trb = true; /* prepare normal TRB */ dwc3_prepare_one_trb(dep, req, true, 0); /* Now prepare one extra TRB to handle ZLP */ trb = &dep->trb_pool[dep->trb_enqueue]; + req->num_trbs++; __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0, false, 1, req->request.stream_id, req->request.short_not_ok, @@ -1232,6 +1231,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) params.param1 = lower_32_bits(req->trb_dma); cmd = DWC3_DEPCMD_STARTTRANSFER; + if (dep->stream_capable) + cmd |= DWC3_DEPCMD_PARAM(req->request.stream_id); + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) cmd |= DWC3_DEPCMD_PARAM(dep->frame_number); } else { @@ -1263,17 +1265,151 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc) return DWC3_DSTS_SOFFN(reg); } -static void __dwc3_gadget_start_isoc(struct dwc3_ep *dep) +/** + * dwc3_gadget_start_isoc_quirk - workaround invalid frame number + * @dep: isoc endpoint + * + * This function tests for the correct combination of BIT[15:14] from the 16-bit + * microframe number reported by the XferNotReady event for the future frame + * number to start the isoc transfer. + * + * In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed + * isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the + * XferNotReady event are invalid. The driver uses this number to schedule the + * isochronous transfer and passes it to the START TRANSFER command. Because + * this number is invalid, the command may fail. If BIT[15:14] matches the + * internal 16-bit microframe, the START TRANSFER command will pass and the + * transfer will start at the scheduled time, if it is off by 1, the command + * will still pass, but the transfer will start 2 seconds in the future. For all + * other conditions, the START TRANSFER command will fail with bus-expiry. + * + * In order to workaround this issue, we can test for the correct combination of + * BIT[15:14] by sending START TRANSFER commands with different values of + * BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart + * (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. + * As the result, within the 4 possible combinations for BIT[15:14], there will + * be 2 successful and 2 failure START COMMAND status. One of the 2 successful + * command status will result in a 2-second delay start. The smaller BIT[15:14] + * value is the correct combination. + * + * Since there are only 4 outcomes and the results are ordered, we can simply + * test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to + * deduce the smaller successful combination. + * + * Let test0 = test status for combination 'b00 and test1 = test status for 'b01 + * of BIT[15:14]. The correct combination is as follow: + * + * if test0 fails and test1 passes, BIT[15:14] is 'b01 + * if test0 fails and test1 fails, BIT[15:14] is 'b10 + * if test0 passes and test1 fails, BIT[15:14] is 'b11 + * if test0 passes and test1 passes, BIT[15:14] is 'b00 + * + * Synopsys STAR 9001202023: Wrong microframe number for isochronous IN + * endpoints. + */ +static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) { + int cmd_status = 0; + bool test0; + bool test1; + + while (dep->combo_num < 2) { + struct dwc3_gadget_ep_cmd_params params; + u32 test_frame_number; + u32 cmd; + + /* + * Check if we can start isoc transfer on the next interval or + * 4 uframes in the future with BIT[15:14] as dep->combo_num + */ + test_frame_number = dep->frame_number & 0x3fff; + test_frame_number |= dep->combo_num << 14; + test_frame_number += max_t(u32, 4, dep->interval); + + params.param0 = upper_32_bits(dep->dwc->bounce_addr); + params.param1 = lower_32_bits(dep->dwc->bounce_addr); + + cmd = DWC3_DEPCMD_STARTTRANSFER; + cmd |= DWC3_DEPCMD_PARAM(test_frame_number); + cmd_status = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); + + /* Redo if some other failure beside bus-expiry is received */ + if (cmd_status && cmd_status != -EAGAIN) { + dep->start_cmd_status = 0; + dep->combo_num = 0; + return 0; + } + + /* Store the first test status */ + if (dep->combo_num == 0) + dep->start_cmd_status = cmd_status; + + dep->combo_num++; + + /* + * End the transfer if the START_TRANSFER command is successful + * to wait for the next XferNotReady to test the command again + */ + if (cmd_status == 0) { + dwc3_stop_active_transfer(dep, true, true); + return 0; + } + } + + /* test0 and test1 are both completed at this point */ + test0 = (dep->start_cmd_status == 0); + test1 = (cmd_status == 0); + + if (!test0 && test1) + dep->combo_num = 1; + else if (!test0 && !test1) + dep->combo_num = 2; + else if (test0 && !test1) + dep->combo_num = 3; + else if (test0 && test1) + dep->combo_num = 0; + + dep->frame_number &= 0x3fff; + dep->frame_number |= dep->combo_num << 14; + dep->frame_number += max_t(u32, 4, dep->interval); + + /* Reinitialize test variables */ + dep->start_cmd_status = 0; + dep->combo_num = 0; + + return __dwc3_gadget_kick_transfer(dep); +} + +static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) +{ + struct dwc3 *dwc = dep->dwc; + int ret; + int i; + if (list_empty(&dep->pending_list)) { - dev_info(dep->dwc->dev, "%s: ran out of requests\n", - dep->name); dep->flags |= DWC3_EP_PENDING_REQUEST; - return; + return -EAGAIN; + } + + if (!dwc->dis_start_transfer_quirk && dwc3_is_usb31(dwc) && + (dwc->revision <= DWC3_USB31_REVISION_160A || + (dwc->revision == DWC3_USB31_REVISION_170A && + dwc->version_type >= DWC31_VERSIONTYPE_EA01 && + dwc->version_type <= DWC31_VERSIONTYPE_EA06))) { + + if (dwc->gadget.speed <= USB_SPEED_HIGH && dep->direction) + return dwc3_gadget_start_isoc_quirk(dep); } - dep->frame_number = DWC3_ALIGN_FRAME(dep); - __dwc3_gadget_kick_transfer(dep); + for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) { + dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1); + + ret = __dwc3_gadget_kick_transfer(dep); + if (ret != -EAGAIN) + break; + } + + return ret; } static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) @@ -1290,6 +1426,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) &req->request, req->dep->name)) return -EINVAL; + if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED, + "%s: request %pK already in flight\n", + dep->name, &req->request)) + return -EINVAL; + pm_runtime_get(dwc->dev); req->request.actual = 0; @@ -1298,6 +1439,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) trace_dwc3_ep_queue(req); list_add_tail(&req->list, &dep->pending_list); + req->status = DWC3_REQUEST_STATUS_QUEUED; /* * NOTICE: Isochronous endpoints should NEVER be prestarted. We must @@ -1314,8 +1456,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if ((dep->flags & DWC3_EP_PENDING_REQUEST)) { if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) { - __dwc3_gadget_start_isoc(dep); - return 0; + return __dwc3_gadget_start_isoc(dep); } } } @@ -1341,6 +1482,42 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, return ret; } +static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *req) +{ + int i; + + /* + * If request was already started, this means we had to + * stop the transfer. With that we also need to ignore + * all TRBs used by the request, however TRBs can only + * be modified after completion of END_TRANSFER + * command. So what we do here is that we wait for + * END_TRANSFER completion and only after that, we jump + * over TRBs by clearing HWO and incrementing dequeue + * pointer. + */ + for (i = 0; i < req->num_trbs; i++) { + struct dwc3_trb *trb; + + trb = req->trb + i; + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + dwc3_ep_inc_deq(dep); + } + + req->num_trbs = 0; +} + +static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep) +{ + struct dwc3_request *req; + struct dwc3_request *tmp; + + list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) { + dwc3_gadget_ep_skip_trbs(dep, req); + dwc3_gadget_giveback(dep, req, -ECONNRESET); + } +} + static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request) { @@ -1369,70 +1546,16 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, } if (r == req) { /* wait until it is processed */ - dwc3_stop_active_transfer(dep, true); - - /* - * If request was already started, this means we had to - * stop the transfer. With that we also need to ignore - * all TRBs used by the request, however TRBs can only - * be modified after completion of END_TRANSFER - * command. So what we do here is that we wait for - * END_TRANSFER completion and only after that, we jump - * over TRBs by clearing HWO and incrementing dequeue - * pointer. - * - * Note that we have 2 possible types of transfers here: - * - * i) Linear buffer request - * ii) SG-list based request - * - * SG-list based requests will have r->num_pending_sgs - * set to a valid number (> 0). Linear requests, - * normally use a single TRB. - * - * For each of these two cases, if r->unaligned flag is - * set, one extra TRB has been used to align transfer - * size to wMaxPacketSize. - * - * All of these cases need to be taken into - * consideration so we don't mess up our TRB ring - * pointers. - */ - wait_event_lock_irq(dep->wait_end_transfer, - !(dep->flags & DWC3_EP_END_TRANSFER_PENDING), - dwc->lock); + dwc3_stop_active_transfer(dep, true, true); if (!r->trb) goto out0; - if (r->num_pending_sgs) { - struct dwc3_trb *trb; - int i = 0; - - for (i = 0; i < r->num_pending_sgs; i++) { - trb = r->trb + i; - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - } - - if (r->unaligned || r->zero) { - trb = r->trb + r->num_pending_sgs + 1; - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - } - } else { - struct dwc3_trb *trb = r->trb; - - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - - if (r->unaligned || r->zero) { - trb = r->trb + 1; - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - } - } - goto out1; + dwc3_gadget_move_cancelled_request(req); + if (dep->flags & DWC3_EP_TRANSFER_STARTED) + goto out0; + else + goto out1; } dev_err(dwc->dev, "request %pK was not queued to %s\n", request, ep->name); @@ -1441,8 +1564,6 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, } out1: - /* giveback the request */ - dwc3_gadget_giveback(dep, req, -ECONNRESET); out0: @@ -1867,6 +1988,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; + dwc->link_state = DWC3_LINK_STATE_SS_DIS; dwc3_ep0_out_start(dwc); dwc3_gadget_enable_irq(dwc); @@ -1934,8 +2056,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; - int epnum; - u32 tmo_eps = 0; spin_lock_irqsave(&dwc->lock, flags); @@ -1944,36 +2064,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g) __dwc3_gadget_stop(dwc); - for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { - struct dwc3_ep *dep = dwc->eps[epnum]; - int ret; - - if (!dep) - continue; - - if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) - continue; - - ret = wait_event_interruptible_lock_irq_timeout(dep->wait_end_transfer, - !(dep->flags & DWC3_EP_END_TRANSFER_PENDING), - dwc->lock, msecs_to_jiffies(5)); - - if (ret <= 0) { - /* Timed out or interrupted! There's nothing much - * we can do so we just log here and print which - * endpoints timed out at the end. - */ - tmo_eps |= 1 << epnum; - dep->flags &= DWC3_EP_END_TRANSFER_PENDING; - } - } - - if (tmo_eps) { - dev_err(dwc->dev, - "end transfer timed out on endpoints 0x%x [bitmap]\n", - tmo_eps); - } - out: dwc->gadget_driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); @@ -2148,6 +2238,8 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) dep->direction = direction; dep->regs = dwc->regs + DWC3_DEP_BASE(epnum); dwc->eps[epnum] = dep; + dep->combo_num = 0; + dep->start_cmd_status = 0; snprintf(dep->name, sizeof(dep->name), "ep%u%s", num, direction ? "in" : "out"); @@ -2176,6 +2268,7 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) INIT_LIST_HEAD(&dep->pending_list); INIT_LIST_HEAD(&dep->started_list); + INIT_LIST_HEAD(&dep->cancelled_list); return 0; } @@ -2235,6 +2328,7 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, dwc3_ep_inc_deq(dep); trace_dwc3_complete_trb(dep, trb); + req->num_trbs--; /* * If we're in the middle of series of chained TRBs and we @@ -2250,11 +2344,25 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, trb->ctrl &= ~DWC3_TRB_CTRL_HWO; /* + * For isochronous transfers, the first TRB in a service interval must + * have the Isoc-First type. Track and report its interval frame number. + */ + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + (trb->ctrl & DWC3_TRBCTL_ISOCHRONOUS_FIRST)) { + unsigned int frame_number; + + frame_number = DWC3_TRB_CTRL_GET_SID_SOFN(trb->ctrl); + frame_number &= ~(dep->interval - 1); + req->request.frame_number = frame_number; + } + + /* * If we're dealing with unaligned size OUT transfer, we will be left * with one TRB pending in the ring. We need to manually clear HWO bit * from that TRB. */ - if ((req->zero || req->unaligned) && !(trb->ctrl & DWC3_TRB_CTRL_CHN)) { + + if (req->needs_extra_trb && !(trb->ctrl & DWC3_TRB_CTRL_CHN)) { trb->ctrl &= ~DWC3_TRB_CTRL_HWO; return 1; } @@ -2331,11 +2439,10 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status); - if (req->unaligned || req->zero) { + if (req->needs_extra_trb) { ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status); - req->unaligned = false; - req->zero = false; + req->needs_extra_trb = false; } req->request.actual = req->request.length - req->remaining; @@ -2396,7 +2503,7 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); if (stop) { - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, true); dep->flags = DWC3_EP_ENABLED; } @@ -2430,7 +2537,7 @@ static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { dwc3_gadget_endpoint_frame_from_event(dep, event); - __dwc3_gadget_start_isoc(dep); + (void) __dwc3_gadget_start_isoc(dep); } static void dwc3_endpoint_interrupt(struct dwc3 *dwc, @@ -2443,7 +2550,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep = dwc->eps[epnum]; if (!(dep->flags & DWC3_EP_ENABLED)) { - if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* Handle only EPCMDCMPLT when EP disabled */ @@ -2467,8 +2574,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, cmd = DEPEVT_PARAMETER_CMD(event->parameters); if (cmd == DWC3_DEPCMD_ENDTRANSFER) { - dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; - wake_up(&dep->wait_end_transfer); + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; + dwc3_gadget_ep_cleanup_cancelled_requests(dep); } break; case DWC3_DEPEVT_STREAMEVT: @@ -2517,15 +2624,15 @@ static void dwc3_reset_gadget(struct dwc3 *dwc) } } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force) +static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, + bool interrupt) { struct dwc3 *dwc = dep->dwc; struct dwc3_gadget_ep_cmd_params params; u32 cmd; int ret; - if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) || - !dep->resource_index) + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* @@ -2561,17 +2668,15 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force) cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; - cmd |= DWC3_DEPCMD_CMDIOC; + cmd |= interrupt ? DWC3_DEPCMD_CMDIOC : 0; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; - if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) { - dep->flags |= DWC3_EP_END_TRANSFER_PENDING; + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) udelay(100); - } } static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) @@ -3235,6 +3340,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err4; } + dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed); + return 0; err4: @@ -3277,6 +3384,8 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) dwc3_disconnect_gadget(dwc); __dwc3_gadget_stop(dwc); + synchronize_irq(dwc->irq_gadget); + return 0; } diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 2aacd1afd9ff..3ed738e86ea7 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -75,10 +75,25 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) { struct dwc3_ep *dep = req->dep; - req->started = true; + req->status = DWC3_REQUEST_STATUS_STARTED; list_move_tail(&req->list, &dep->started_list); } +/** + * dwc3_gadget_move_cancelled_request - move @req to the cancelled_list + * @req: the request to be moved + * + * Caller should take care of locking. This function will move @req from its + * current list to the endpoint's cancelled_list. + */ +static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req) +{ + struct dwc3_ep *dep = req->dep; + + req->status = DWC3_REQUEST_STATUS_CANCELLED; + list_move_tail(&req->list, &dep->cancelled_list); +} + void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 1a3878a3be78..f55947294f7c 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -46,7 +46,7 @@ out: int dwc3_host_init(struct dwc3 *dwc) { - struct property_entry props[3]; + struct property_entry props[4]; struct platform_device *xhci; int ret, irq; struct resource *res; @@ -93,6 +93,9 @@ int dwc3_host_init(struct dwc3 *dwc) if (dwc->usb3_lpm_capable) props[prop_idx++].name = "usb3-lpm-capable"; + if (dwc->usb2_lpm_disable) + props[prop_idx++].name = "usb2-lpm-disable"; + /** * WORKAROUND: dwc3 revisions <=3.00a have a limitation * where Port Disable command doesn't work. diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index f22714cce070..818a63da1a44 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -59,8 +59,8 @@ DECLARE_EVENT_CLASS(dwc3_log_event, __entry->ep0state = dwc->ep0state; ), TP_printk("event (%08x): %s", __entry->event, - dwc3_decode_event(__get_str(str), __entry->event, - __entry->ep0state)) + dwc3_decode_event(__get_str(str), DWC3_MSG_MAX, + __entry->event, __entry->ep0state)) ); DEFINE_EVENT(dwc3_log_event, dwc3_event, @@ -86,7 +86,8 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", dwc3_decode_ctrl(__get_str(str), __entry->bRequestType, + TP_printk("%s", dwc3_decode_ctrl(__get_str(str), DWC3_MSG_MAX, + __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) ) @@ -199,7 +200,7 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd, __entry->param2 = params->param2; __entry->cmd_status = cmd_status; ), - TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x --> status: %s", + TP_printk("%s: cmd '%s' [%x] params %08x %08x %08x --> status: %s", __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd), __entry->cmd, __entry->param0, __entry->param1, __entry->param2, @@ -251,9 +252,11 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, s = "2x "; break; case 3: + default: s = "3x "; break; } + break; default: s = ""; } s; }), @@ -303,7 +306,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ep, __entry->trb_enqueue = dep->trb_enqueue; __entry->trb_dequeue = dep->trb_dequeue; ), - TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c:%c", + TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c", __get_str(name), __entry->maxpacket, __entry->maxpacket_limit, __entry->max_streams, __entry->maxburst, __entry->trb_enqueue, @@ -313,7 +316,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ep, __entry->flags & DWC3_EP_WEDGE ? 'W' : 'w', __entry->flags & DWC3_EP_TRANSFER_STARTED ? 'B' : 'b', __entry->flags & DWC3_EP_PENDING_REQUEST ? 'P' : 'p', - __entry->flags & DWC3_EP_END_TRANSFER_PENDING ? 'E' : 'e', __entry->direction ? '<' : '>' ) ); diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index d633c2abe5a4..ea0d531c63e2 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -631,28 +631,28 @@ static int ehci_reset_port(int port) if (!(portsc & PORT_RESET)) break; } - if (portsc & PORT_RESET) { - /* force reset to complete */ - loop = 100 * 1000; - writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), - &ehci_regs->port_status[port - 1]); - do { - udelay(1); - portsc = readl(&ehci_regs->port_status[port-1]); - } while ((portsc & PORT_RESET) && (--loop > 0)); - } + if (portsc & PORT_RESET) { + /* force reset to complete */ + loop = 100 * 1000; + writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), + &ehci_regs->port_status[port - 1]); + do { + udelay(1); + portsc = readl(&ehci_regs->port_status[port-1]); + } while ((portsc & PORT_RESET) && (--loop > 0)); + } - /* Device went away? */ - if (!(portsc & PORT_CONNECT)) - return -ENOTCONN; + /* Device went away? */ + if (!(portsc & PORT_CONNECT)) + return -ENOTCONN; - /* bomb out completely if something weird happened */ - if ((portsc & PORT_CSC)) - return -EINVAL; + /* bomb out completely if something weird happened */ + if ((portsc & PORT_CSC)) + return -EINVAL; - /* If we've finished resetting, then break out of the loop */ - if (!(portsc & PORT_RESET) && (portsc & PORT_PE)) - return 0; + /* If we've finished resetting, then break out of the loop */ + if (!(portsc & PORT_RESET) && (portsc & PORT_PE)) + return 0; return -EBUSY; } diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index d2652dccc699..c9cfb100ecdc 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -94,7 +94,7 @@ static void * __init xdbc_get_page(dma_addr_t *dma_addr) { void *virt; - virt = memblock_alloc_nopanic(PAGE_SIZE, PAGE_SIZE); + virt = memblock_alloc(PAGE_SIZE, PAGE_SIZE); if (!virt) return NULL; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 31cce7805eb2..ec189d7855a0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 71b15c65b90f..1eb4fa2e623f 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -67,9 +67,6 @@ struct usb_ep *usb_ep_autoconfig_ss( ) { struct usb_ep *ep; - u8 type; - - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; if (gadget->ops->match_ep) { ep = gadget->ops->match_ep(gadget, desc, ep_comp); @@ -109,16 +106,6 @@ found_ep: desc->bEndpointAddress |= gadget->out_epnum; } - /* report (variable) full speed bulk maxpacket */ - if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) { - int size = ep->maxpacket_limit; - - /* min() doesn't work on bitfields with gcc-3.5 */ - if (size > 64) - size = 64; - desc->wMaxPacketSize = cpu_to_le16(size); - } - ep->address = desc->bEndpointAddress; ep->desc = NULL; ep->comp_desc = NULL; @@ -152,9 +139,10 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); * * On success, this returns an claimed usb_ep, and modifies the endpoint * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed. To prevent - * the endpoint from being returned by a later autoconfig call, claims it - * by assigning ep->claimed to true. + * is initialized as if the endpoint were used at full speed. Because of + * that the users must consider adjusting the autoconfigured descriptor. + * To prevent the endpoint from being returned by a later autoconfig call, + * claims it by assigning ep->claimed to true. * * On failure, this returns a null endpoint descriptor. */ @@ -163,7 +151,26 @@ struct usb_ep *usb_ep_autoconfig( struct usb_endpoint_descriptor *desc ) { - return usb_ep_autoconfig_ss(gadget, desc, NULL); + struct usb_ep *ep; + u8 type; + + ep = usb_ep_autoconfig_ss(gadget, desc, NULL); + if (!ep) + return NULL; + + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + /* report (variable) full speed bulk maxpacket */ + if (type == USB_ENDPOINT_XFER_BULK) { + int size = ep->maxpacket_limit; + + /* min() doesn't work on bitfields with gcc-3.5 */ + if (size > 64) + size = 64; + desc->wMaxPacketSize = cpu_to_le16(size); + } + + return ep; } EXPORT_SYMBOL_GPL(usb_ep_autoconfig); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 31e8bf3578c8..20413c276c61 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -18,11 +18,15 @@ #include <linux/pagemap.h> #include <linux/export.h> #include <linux/hid.h> +#include <linux/mm.h> #include <linux/module.h> +#include <linux/scatterlist.h> #include <linux/sched/signal.h> #include <linux/uio.h> +#include <linux/vmalloc.h> #include <asm/unaligned.h> +#include <linux/usb/ccid.h> #include <linux/usb/composite.h> #include <linux/usb/functionfs.h> @@ -218,6 +222,8 @@ struct ffs_io_data { struct usb_ep *ep; struct usb_request *req; + struct sg_table sgt; + bool use_sg; struct ffs_data *ffs; }; @@ -749,6 +755,65 @@ static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) return ret; } +/* + * allocate a virtually contiguous buffer and create a scatterlist describing it + * @sg_table - pointer to a place to be filled with sg_table contents + * @size - required buffer size + */ +static void *ffs_build_sg_list(struct sg_table *sgt, size_t sz) +{ + struct page **pages; + void *vaddr, *ptr; + unsigned int n_pages; + int i; + + vaddr = vmalloc(sz); + if (!vaddr) + return NULL; + + n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT; + pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL); + if (!pages) { + vfree(vaddr); + + return NULL; + } + for (i = 0, ptr = vaddr; i < n_pages; ++i, ptr += PAGE_SIZE) + pages[i] = vmalloc_to_page(ptr); + + if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL)) { + kvfree(pages); + vfree(vaddr); + + return NULL; + } + kvfree(pages); + + return vaddr; +} + +static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data, + size_t data_len) +{ + if (io_data->use_sg) + return ffs_build_sg_list(&io_data->sgt, data_len); + + return kmalloc(data_len, GFP_KERNEL); +} + +static inline void ffs_free_buffer(struct ffs_io_data *io_data) +{ + if (!io_data->buf) + return; + + if (io_data->use_sg) { + sg_free_table(&io_data->sgt); + vfree(io_data->buf); + } else { + kfree(io_data->buf); + } +} + static void ffs_user_copy_worker(struct work_struct *work) { struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, @@ -776,7 +841,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read) kfree(io_data->to_free); - kfree(io_data->buf); + ffs_free_buffer(io_data); kfree(io_data); } @@ -932,6 +997,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * earlier */ gadget = epfile->ffs->gadget; + io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ @@ -948,7 +1014,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); spin_unlock_irq(&epfile->ffs->eps_lock); - data = kmalloc(data_len, GFP_KERNEL); + data = ffs_alloc_buffer(io_data, data_len); if (unlikely(!data)) { ret = -ENOMEM; goto error_mutex; @@ -988,8 +1054,16 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) bool interrupted = false; req = ep->req; - req->buf = data; - req->length = data_len; + if (io_data->use_sg) { + req->buf = NULL; + req->sg = io_data->sgt.sgl; + req->num_sgs = io_data->sgt.nents; + } else { + req->buf = data; + } + req->length = data_len; + + io_data->buf = data; req->context = &done; req->complete = ffs_epfile_io_complete; @@ -1008,6 +1082,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * condition with req->complete callback. */ usb_ep_dequeue(ep->ep, req); + wait_for_completion(&done); interrupted = ep->status < 0; } @@ -1022,8 +1097,14 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) { ret = -ENOMEM; } else { - req->buf = data; - req->length = data_len; + if (io_data->use_sg) { + req->buf = NULL; + req->sg = io_data->sgt.sgl; + req->num_sgs = io_data->sgt.nents; + } else { + req->buf = data; + } + req->length = data_len; io_data->buf = data; io_data->ep = ep->ep; @@ -1052,7 +1133,7 @@ error_lock: error_mutex: mutex_unlock(&epfile->mutex); error: - kfree(data); + ffs_free_buffer(io_data); return ret; } @@ -1926,7 +2007,7 @@ typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity, static int __must_check ffs_do_single_desc(char *data, unsigned len, ffs_entity_callback entity, - void *priv) + void *priv, int *current_class) { struct usb_descriptor_header *_ds = (void *)data; u8 length; @@ -1984,6 +2065,7 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, __entity(INTERFACE, ds->bInterfaceNumber); if (ds->iInterface) __entity(STRING, ds->iInterface); + *current_class = ds->bInterfaceClass; } break; @@ -1997,11 +2079,22 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, } break; - case HID_DT_HID: - pr_vdebug("hid descriptor\n"); - if (length != sizeof(struct hid_descriptor)) - goto inv_length; - break; + case USB_TYPE_CLASS | 0x01: + if (*current_class == USB_INTERFACE_CLASS_HID) { + pr_vdebug("hid descriptor\n"); + if (length != sizeof(struct hid_descriptor)) + goto inv_length; + break; + } else if (*current_class == USB_INTERFACE_CLASS_CCID) { + pr_vdebug("ccid descriptor\n"); + if (length != sizeof(struct ccid_descriptor)) + goto inv_length; + break; + } else { + pr_vdebug("unknown descriptor: %d for class %d\n", + _ds->bDescriptorType, *current_class); + return -EINVAL; + } case USB_DT_OTG: if (length != sizeof(struct usb_otg_descriptor)) @@ -2058,6 +2151,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, { const unsigned _len = len; unsigned long num = 0; + int current_class = -1; ENTER(); @@ -2078,7 +2172,8 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, if (!data) return _len - len; - ret = ffs_do_single_desc(data, len, entity, priv); + ret = ffs_do_single_desc(data, len, entity, priv, + ¤t_class); if (unlikely(ret < 0)) { pr_debug("%s returns %d\n", __func__, ret); return ret; @@ -2749,12 +2844,18 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, struct usb_request *req; struct usb_ep *ep; u8 bEndpointAddress; + u16 wMaxPacketSize; /* * We back up bEndpointAddress because autoconfig overwrites * it with physical endpoint address. */ bEndpointAddress = ds->bEndpointAddress; + /* + * We back up wMaxPacketSize because autoconfig treats + * endpoint descriptors as if they were full speed. + */ + wMaxPacketSize = ds->wMaxPacketSize; pr_vdebug("autoconfig\n"); ep = usb_ep_autoconfig(func->gadget, ds); if (unlikely(!ep)) @@ -2775,6 +2876,11 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, */ if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) ds->bEndpointAddress = bEndpointAddress; + /* + * Restore wMaxPacketSize which was potentially + * overwritten by autoconfig. + */ + ds->wMaxPacketSize = wMaxPacketSize; } ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 54e859dcb25c..f3816a5c861e 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -252,7 +252,7 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, if (!count) return 0; - if (!access_ok(VERIFY_WRITE, buffer, count)) + if (!access_ok(buffer, count)) return -EFAULT; spin_lock_irqsave(&hidg->read_spinlock, flags); @@ -339,7 +339,7 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, unsigned long flags; ssize_t status = -ENOMEM; - if (!access_ok(VERIFY_READ, buffer, count)) + if (!access_ok(buffer, count)) return -EFAULT; spin_lock_irqsave(&hidg->write_spinlock, flags); @@ -391,20 +391,20 @@ try_again: req->complete = f_hidg_req_complete; req->context = hidg; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); + status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC); if (status < 0) { ERROR(hidg->func.config->cdev, "usb_ep_queue error on int endpoint %zd\n", status); - goto release_write_pending_unlocked; + goto release_write_pending; } else { status = count; } - spin_unlock_irqrestore(&hidg->write_spinlock, flags); return status; release_write_pending: spin_lock_irqsave(&hidg->write_spinlock, flags); -release_write_pending_unlocked: hidg->write_pending = 0; spin_unlock_irqrestore(&hidg->write_spinlock, flags); diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 9cdef108fb1b..ed68a4860b7d 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -838,7 +838,7 @@ static struct usb_function *source_sink_alloc_func( ss = kzalloc(sizeof(*ss), GFP_KERNEL); if (!ss) - return NULL; + return ERR_PTR(-ENOMEM); ss_opts = container_of(fi, struct f_ss_opts, func_inst); diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 106988a6661a..7f01f78b1d23 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1256,11 +1256,6 @@ static int usbg_check_false(struct se_portal_group *se_tpg) return 0; } -static char *usbg_get_fabric_name(void) -{ - return "usb_gadget"; -} - static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg) { struct usbg_tpg *tpg = container_of(se_tpg, @@ -1297,14 +1292,6 @@ static u32 usbg_sess_get_index(struct se_session *se_sess) return 0; } -/* - * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be - */ -static int usbg_write_pending_status(struct se_cmd *se_cmd) -{ - return 0; -} - static void usbg_set_default_node_attrs(struct se_node_acl *nacl) { } @@ -1718,8 +1705,7 @@ static int usbg_check_stop_free(struct se_cmd *se_cmd) static const struct target_core_fabric_ops usbg_ops = { .module = THIS_MODULE, - .name = "usb_gadget", - .get_fabric_name = usbg_get_fabric_name, + .fabric_name = "usb_gadget", .tpg_get_wwn = usbg_get_fabric_wwn, .tpg_get_tag = usbg_get_tag, .tpg_check_demo_mode = usbg_check_true, @@ -1731,7 +1717,6 @@ static const struct target_core_fabric_ops usbg_ops = { .sess_get_index = usbg_sess_get_index, .sess_get_initiator_sid = NULL, .write_pending = usbg_send_write_request, - .write_pending_status = usbg_write_pending_status, .set_default_node_attributes = usbg_set_default_node_attrs, .get_cmd_state = usbg_get_cmd_state, .queue_data_in = usbg_send_read_response, diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 2746a926a8d9..00d346965f7a 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -459,10 +459,10 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } else if (intf == uac1->as_in_intf) { uac1->as_in_alt = alt; - if (alt) - ret = u_audio_start_playback(&uac1->g_audio); - else - u_audio_stop_playback(&uac1->g_audio); + if (alt) + ret = u_audio_start_playback(&uac1->g_audio); + else + u_audio_stop_playback(&uac1->g_audio); } else { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return -EINVAL; @@ -568,6 +568,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; as_out_interface_alt_0_desc.bInterfaceNumber = status; as_out_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc.baInterfaceNr[0] = status; uac1->as_out_intf = status; uac1->as_out_alt = 0; @@ -576,6 +577,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; as_in_interface_alt_0_desc.bInterfaceNumber = status; as_in_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc.baInterfaceNr[1] = status; uac1->as_in_intf = status; uac1->as_in_alt = 0; diff --git a/drivers/usb/gadget/function/u_ecm.h b/drivers/usb/gadget/function/u_ecm.h index 050aa672ee7f..098ece573a5e 100644 --- a/drivers/usb/gadget/function/u_ecm.h +++ b/drivers/usb/gadget/function/u_ecm.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_ECM_H diff --git a/drivers/usb/gadget/function/u_eem.h b/drivers/usb/gadget/function/u_eem.h index de3828d3e8f0..921386a375cf 100644 --- a/drivers/usb/gadget/function/u_eem.h +++ b/drivers/usb/gadget/function/u_eem.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_EEM_H diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 0f026d445e31..737bd77a575d 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -879,7 +879,7 @@ int gether_register_netdev(struct net_device *net) sa.sa_family = net->type; memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN); rtnl_lock(); - status = dev_set_mac_address(net, &sa); + status = dev_set_mac_address(net, &sa, NULL); rtnl_unlock(); if (status) pr_warn("cannot set self ethernet address: %d\n", status); diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index cd33cee4d78b..d8b92485b727 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_ETHER_CONFIGFS_H diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index c3aba4dfa958..f9b0cf67360d 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_FFS_H diff --git a/drivers/usb/gadget/function/u_gether.h b/drivers/usb/gadget/function/u_gether.h index 5b7e2eb90336..ce4f07626f96 100644 --- a/drivers/usb/gadget/function/u_gether.h +++ b/drivers/usb/gadget/function/u_gether.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_GETHER_H diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 2f5ca4bfa7ff..1594bfa312eb 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_HID_H diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h index 5599aa5fc977..29bf006c0a13 100644 --- a/drivers/usb/gadget/function/u_midi.h +++ b/drivers/usb/gadget/function/u_midi.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_MIDI_H diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index 67324f983343..d483e45c0f77 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_NCM_H diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h index 6088ff744194..78797764f478 100644 --- a/drivers/usb/gadget/function/u_printer.h +++ b/drivers/usb/gadget/function/u_printer.h @@ -7,7 +7,7 @@ * Copyright (c) 2015 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_PRINTER_H diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index d65fb4ebac3c..1e148b76f339 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_RNDIS_H diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 29436f75bbe0..65f634ec7fc2 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/interrupt.h> #include <linux/device.h> #include <linux/delay.h> #include <linux/tty.h> @@ -26,6 +25,7 @@ #include <linux/module.h> #include <linux/console.h> #include <linux/kthread.h> +#include <linux/workqueue.h> #include <linux/kfifo.h> #include "u_serial.h" @@ -110,7 +110,7 @@ struct gs_port { int read_allocated; struct list_head read_queue; unsigned n_read; - struct tasklet_struct push; + struct delayed_work push; struct list_head write_pool; int write_started; @@ -352,9 +352,10 @@ __acquires(&port->port_lock) * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) * can be buffered before the TTY layer's buffers (currently 64 KB). */ -static void gs_rx_push(unsigned long _port) +static void gs_rx_push(struct work_struct *work) { - struct gs_port *port = (void *)_port; + struct delayed_work *w = to_delayed_work(work); + struct gs_port *port = container_of(w, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; @@ -429,21 +430,13 @@ static void gs_rx_push(unsigned long _port) /* We want our data queue to become empty ASAP, keeping data * in the tty and ldisc (not here). If we couldn't push any - * this time around, there may be trouble unless there's an - * implicit tty_unthrottle() call on its way... + * this time around, RX may be starved, so wait until next jiffy. * - * REVISIT we should probably add a timer to keep the tasklet - * from starving ... but it's not clear that case ever happens. + * We may leave non-empty queue only when there is a tty, and + * either it is throttled or there is no more room in flip buffer. */ - if (!list_empty(queue) && tty) { - if (!tty_throttled(tty)) { - if (do_push) - tasklet_schedule(&port->push); - else - pr_warn("ttyGS%d: RX not scheduled?\n", - port->port_num); - } - } + if (!list_empty(queue) && !tty_throttled(tty)) + schedule_delayed_work(&port->push, 1); /* If we're still connected, refill the USB RX queue. */ if (!disconnect && port->port_usb) @@ -459,7 +452,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) /* Queue all received data until the tty layer is ready for it. */ spin_lock(&port->port_lock); list_add_tail(&req->list, &port->read_queue); - tasklet_schedule(&port->push); + schedule_delayed_work(&port->push, 0); spin_unlock(&port->port_lock); } @@ -854,8 +847,8 @@ static void gs_unthrottle(struct tty_struct *tty) * rts/cts, or other handshaking with the host, but if the * read queue backs up enough we'll be NAKing OUT packets. */ - tasklet_schedule(&port->push); pr_vdebug("ttyGS%d: unthrottle\n", port->port_num); + schedule_delayed_work(&port->push, 0); } spin_unlock_irqrestore(&port->port_lock, flags); } @@ -1159,7 +1152,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) init_waitqueue_head(&port->drain_wait); init_waitqueue_head(&port->close_wait); - tasklet_init(&port->push, gs_rx_push, (unsigned long) port); + INIT_DELAYED_WORK(&port->push, gs_rx_push); INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queue); @@ -1186,7 +1179,7 @@ static int gs_closed(struct gs_port *port) static void gserial_free_port(struct gs_port *port) { - tasklet_kill(&port->push); + cancel_delayed_work_sync(&port->push); /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 8362ee572e1e..82048791eb6e 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_UAC2_H diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 5242d489e20a..16da49a2fcf2 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -7,7 +7,7 @@ * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_UVC_H diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 099d650082e5..1473d25ff17a 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -56,6 +56,8 @@ extern unsigned int uvc_gadget_trace_param; dev_dbg(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) #define uvcg_info(f, fmt, args...) \ dev_info(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) +#define uvcg_warn(f, fmt, args...) \ + dev_warn(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) #define uvcg_err(f, fmt, args...) \ dev_err(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index bc1e2af566c3..00fb58e50a15 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #include <linux/sort.h> @@ -1570,10 +1570,6 @@ uvcg_uncompressed_##cname##_store(struct config_item *item, \ if (ret) \ goto end; \ \ - if (num > 255) { \ - ret = -EINVAL; \ - goto end; \ - } \ u->desc.aname = num; \ ret = len; \ end: \ @@ -1767,10 +1763,6 @@ uvcg_mjpeg_##cname##_store(struct config_item *item, \ if (ret) \ goto end; \ \ - if (num > 255) { \ - ret = -EINVAL; \ - goto end; \ - } \ u->desc.aname = num; \ ret = len; \ end: \ diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h index 8549c0b27b9d..341391dbc81f 100644 --- a/drivers/usb/gadget/function/uvc_configfs.h +++ b/drivers/usb/gadget/function/uvc_configfs.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef UVC_CONFIGFS_H #define UVC_CONFIGFS_H diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index f2497cb96abb..61e2c94cc0b0 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -102,7 +102,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&queue->irqlock, flags); } -static struct vb2_ops uvc_queue_qops = { +static const struct vb2_ops uvc_queue_qops = { .queue_setup = uvc_queue_setup, .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, diff --git a/drivers/usb/gadget/function/uvc_v4l2.h b/drivers/usb/gadget/function/uvc_v4l2.h index a75e9c397446..452d71059b3f 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.h +++ b/drivers/usb/gadget/function/uvc_v4l2.h @@ -7,7 +7,7 @@ * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __UVC_V4L2_H__ diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index 278dc52c7604..dff12103f696 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h @@ -7,7 +7,7 @@ * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __UVC_VIDEO_H__ #define __UVC_VIDEO_H__ diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 784bf86dad4f..d7c9e4fca895 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 37ca0e669bd8..249277d0e53f 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -1218,27 +1218,27 @@ ep0_poll (struct file *fd, poll_table *wait) if (dev->state <= STATE_DEV_OPENED) return DEFAULT_POLLMASK; - poll_wait(fd, &dev->wait, wait); - - spin_lock_irq (&dev->lock); - - /* report fd mode change before acting on it */ - if (dev->setup_abort) { - dev->setup_abort = 0; - mask = EPOLLHUP; - goto out; - } - - if (dev->state == STATE_DEV_SETUP) { - if (dev->setup_in || dev->setup_can_stall) - mask = EPOLLOUT; - } else { - if (dev->ev_next != 0) - mask = EPOLLIN; - } + poll_wait(fd, &dev->wait, wait); + + spin_lock_irq(&dev->lock); + + /* report fd mode change before acting on it */ + if (dev->setup_abort) { + dev->setup_abort = 0; + mask = EPOLLHUP; + goto out; + } + + if (dev->state == STATE_DEV_SETUP) { + if (dev->setup_in || dev->setup_can_stall) + mask = EPOLLOUT; + } else { + if (dev->ev_next != 0) + mask = EPOLLIN; + } out: - spin_unlock_irq(&dev->lock); - return mask; + spin_unlock_irq(&dev->lock); + return mask; } static long dev_ioctl (struct file *fd, unsigned code, unsigned long value) diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index dbaa46eee853..6aea1ecb3999 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -5,7 +5,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #include "u_f.h" diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 09f90447fed5..eaa13fd3dc7f 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_F_H__ diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h index 8acd21779ac8..5d7d35c8cc31 100644 --- a/drivers/usb/gadget/u_os_desc.h +++ b/drivers/usb/gadget/u_os_desc.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_OS_DESC_H__ diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 0a16cbd4e528..ef0259a950ba 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index f0233912bace..6b1b16b17d7d 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -438,7 +438,7 @@ static int ast_vhub_udc_stop(struct usb_gadget *gadget) return 0; } -static struct usb_gadget_ops ast_vhub_udc_ops = { +static const struct usb_gadget_ops ast_vhub_udc_ops = { .get_frame = ast_vhub_udc_get_frame, .wakeup = ast_vhub_udc_wakeup, .pullup = ast_vhub_udc_pullup, diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 4a28e3fbeb0b..83340f4fdc6e 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -120,7 +120,7 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep) /* No current DMA ongoing */ req->active = false; - /* Grab lenght out of HW */ + /* Grab length out of HW */ len = VHUB_EP_DMA_TX_SIZE(stat); /* If not using DMA, copy data out if needed */ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 35ba0e55a2e9..7c040f56100e 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -295,7 +295,7 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, dsize = AST_VHUB_HUB_DESC_SIZE; memcpy(ep->buf, &ast_vhub_hub_desc, dsize); BUILD_BUG_ON(dsize > sizeof(ast_vhub_hub_desc)); - BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); + BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; default: return std_req_stall; diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 11247322d587..660712e0bf98 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -88,7 +88,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf, size_t len, remaining, actual = 0; char tmpbuf[38]; - if (!access_ok(VERIFY_WRITE, buf, nbytes)) + if (!access_ok(buf, nbytes)) return -EFAULT; inode_lock(file_inode(file)); diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig index c74ac25dddcd..3e88c7670b2e 100644 --- a/drivers/usb/gadget/udc/bdc/Kconfig +++ b/drivers/usb/gadget/udc/bdc/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_BDC_UDC tristate "Broadcom USB3.0 device controller IP driver(BDC)" depends on USB_GADGET && HAS_DMA diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c index 6305bf2c8b59..44c2a5eef785 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_cmd.c +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c @@ -311,8 +311,8 @@ int bdc_ep_clear_stall(struct bdc *bdc, int epnum) /* if the endpoint it not stallled */ if (!(ep->flags & BDC_EP_STALL)) { ret = bdc_ep_set_stall(bdc, epnum); - if (ret) - return ret; + if (ret) + return ret; } } /* Preserve the seq number for ep0 only */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 01b44e159623..ccbd1d34eb2a 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -172,8 +172,9 @@ static int scratchpad_setup(struct bdc *bdc) /* Refer to BDC spec, Table 4 for description of SPB */ sp_buff_size = 1 << (sp_buff_size + 5); dev_dbg(bdc->dev, "Allocating %d bytes for scratchpad\n", sp_buff_size); - bdc->scratchpad.buff = dma_zalloc_coherent(bdc->dev, sp_buff_size, - &bdc->scratchpad.sp_dma, GFP_KERNEL); + bdc->scratchpad.buff = dma_alloc_coherent(bdc->dev, sp_buff_size, + &bdc->scratchpad.sp_dma, + GFP_KERNEL); if (!bdc->scratchpad.buff) goto fail; @@ -202,11 +203,9 @@ static int setup_srr(struct bdc *bdc, int interrupter) bdc_writel(bdc->regs, BDC_SRRINT(0), BDC_SRR_RWS | BDC_SRR_RST); bdc->srr.dqp_index = 0; /* allocate the status report descriptors */ - bdc->srr.sr_bds = dma_zalloc_coherent( - bdc->dev, - NUM_SR_ENTRIES * sizeof(struct bdc_bd), - &bdc->srr.dma_addr, - GFP_KERNEL); + bdc->srr.sr_bds = dma_alloc_coherent(bdc->dev, + NUM_SR_ENTRIES * sizeof(struct bdc_bd), + &bdc->srr.dma_addr, GFP_KERNEL); if (!bdc->srr.sr_bds) return -ENOMEM; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 87d6b12779f2..7cf34beb50df 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -281,10 +281,10 @@ EXPORT_SYMBOL_GPL(usb_ep_queue); * @ep:the endpoint associated with the request * @req:the request being canceled * - * If the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. This is guaranteed to happen before the call to - * usb_ep_dequeue() returns. + * If the request is still active on the endpoint, it is dequeued and + * eventually its completion routine is called (with status -ECONNRESET); + * else a negative error code is returned. This routine is asynchronous, + * that is, it may return before the completion routine runs. * * Note that some hardware can't clear out write fifos (to unlink the request * at the head of the queue) except as part of disconnecting from usb. Such diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index baf72f95f0f1..213b52508621 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -979,8 +979,18 @@ static int dummy_udc_start(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - if (driver->max_speed == USB_SPEED_UNKNOWN) + switch (g->speed) { + /* All the speeds we support */ + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: + dev_err(dummy_dev(dum_hcd), "Unsupported driver max speed %d\n", + driver->max_speed); return -EINVAL; + } /* * SLAVE side init ... the layer above hardware, which @@ -1784,9 +1794,10 @@ static void dummy_timer(struct timer_list *t) /* Bus speed is 500000 bytes/ms, so use a little less */ total = 490000; break; - default: + default: /* Can't happen */ dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); - return; + total = 0; + break; } /* FIXME if HZ != 1000 this will probably misbehave ... */ @@ -1828,7 +1839,7 @@ restart: /* Used up this frame's bandwidth? */ if (total <= 0) - break; + continue; /* find the gadget's ep for this request (if configured) */ address = usb_pipeendpoint (urb->pipe); diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index bc6abaea907d..cec49294bac6 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -326,6 +326,7 @@ dma_reset: static void fotg210_start_dma(struct fotg210_ep *ep, struct fotg210_request *req) { + struct device *dev = &ep->fotg210->gadget.dev; dma_addr_t d; u8 *buffer; u32 length; @@ -348,18 +349,14 @@ static void fotg210_start_dma(struct fotg210_ep *ep, length = req->req.length; } - d = dma_map_single(NULL, buffer, length, + d = dma_map_single(dev, buffer, length, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(NULL, d)) { + if (dma_mapping_error(dev, d)) { pr_err("dma_mapping_error\n"); return; } - dma_sync_single_for_device(NULL, d, length, - ep->dir_in ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - fotg210_enable_dma(ep, d, length); /* check if dma is done */ @@ -370,7 +367,7 @@ static void fotg210_start_dma(struct fotg210_ep *ep, /* update actual transfer length */ req->req.actual += length; - dma_unmap_single(NULL, d, length, DMA_TO_DEVICE); + dma_unmap_single(dev, d, length, DMA_TO_DEVICE); } static void fotg210_ep0_queue(struct fotg210_ep *ep, diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 660878a19505..c2011cd7df8c 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -945,6 +945,7 @@ net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req) break; } if (&req->req != _req) { + ep->stopped = stopped; spin_unlock_irqrestore(&ep->dev->lock, flags); return -EINVAL; } @@ -2083,7 +2084,7 @@ static irqreturn_t net2272_irq(int irq, void *_dev) #if defined(PLX_PCI_RDK2) /* see if PCI int for us by checking irqstat */ intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT); - if (!intcsr & (1 << NET2272_PCI_IRQ)) { + if (!(intcsr & (1 << NET2272_PCI_IRQ))) { spin_unlock(&dev->lock); return IRQ_NONE; } diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index e7dae5379e04..898339e5df10 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -516,8 +516,8 @@ static int net2280_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || !ep->desc || _ep->name == ep0name) { - pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); + if (!_ep || _ep->name == ep0name) { + pr_err("%s: Invalid ep=%p\n", __func__, _ep); return -EINVAL; } spin_lock_irqsave(&ep->dev->lock, flags); @@ -866,9 +866,6 @@ static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma) (void) readl(&ep->dev->pci->pcimstctl); writel(BIT(DMA_START), &dma->dmastat); - - if (!ep->is_in) - stop_out_naking(ep); } static void start_dma(struct net2280_ep *ep, struct net2280_request *req) @@ -907,6 +904,7 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req) writel(BIT(DMA_START), &dma->dmastat); return; } + stop_out_naking(ep); } tmp = dmactl_default; @@ -1275,9 +1273,9 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) break; } if (&req->req != _req) { + ep->stopped = stopped; spin_unlock_irqrestore(&ep->dev->lock, flags); - dev_err(&ep->dev->pdev->dev, "%s: Request mismatch\n", - __func__); + ep_dbg(ep->dev, "%s: Request mismatch\n", __func__); return -EINVAL; } @@ -2279,7 +2277,7 @@ static void usb_reinit_338x(struct net2280 *dev) * - It is safe to set for all connection speeds; all chip revisions. * - R-M-W to leave other bits undisturbed. * - Reference PLX TT-7372 - */ + */ val = readl(&dev->ll_chicken_reg->ll_tsn_chicken_bit); val |= BIT(RECOVERY_IDLE_TO_RECOVER_FMW); writel(val, &dev->ll_chicken_reg->ll_tsn_chicken_bit); diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index afaea11ec771..cded51f36fc1 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -368,7 +368,6 @@ struct pch_udc_dev { #define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939 #define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 -#define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D #define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 @@ -1330,7 +1329,7 @@ static void pch_vbus_gpio_work_rise(struct work_struct *irq_work) } /** - * pch_vbus_gpio_irq() - IRQ handler for GPIO intrerrupt for changing VBUS + * pch_vbus_gpio_irq() - IRQ handler for GPIO interrupt for changing VBUS * @irq: Interrupt request number * @dev: Reference to the device structure * diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index cdffbd1e0316..7dc248546fd4 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -358,6 +358,7 @@ struct renesas_usb3 { bool extcon_host; /* check id and set EXTCON_USB_HOST */ bool extcon_usb; /* check vbus and set EXTCON_USB */ bool forced_b_device; + bool start_to_connect; }; #define gadget_to_renesas_usb3(_gadget) \ @@ -476,7 +477,8 @@ static void usb3_init_axi_bridge(struct renesas_usb3 *usb3) static void usb3_init_epc_registers(struct renesas_usb3 *usb3) { usb3_write(usb3, ~0, USB3_USB_INT_STA_1); - usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG); + if (!usb3->workaround_for_vbus) + usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG); } static bool usb3_wakeup_usb2_phy(struct renesas_usb3 *usb3) @@ -700,8 +702,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev) usb3_set_mode_by_role_sw(usb3, host); usb3_vbus_out(usb3, a_dev); /* for A-Peripheral or forced B-device mode */ - if ((!host && a_dev) || - (usb3->workaround_for_vbus && usb3->forced_b_device)) + if ((!host && a_dev) || usb3->start_to_connect) usb3_connect(usb3); spin_unlock_irqrestore(&usb3->lock, flags); } @@ -2432,7 +2433,11 @@ static ssize_t renesas_usb3_b_device_write(struct file *file, if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; - if (!strncmp(buf, "1", 1)) + usb3->start_to_connect = false; + if (usb3->workaround_for_vbus && usb3->forced_b_device && + !strncmp(buf, "2", 1)) + usb3->start_to_connect = true; + else if (!strncmp(buf, "1", 1)) usb3->forced_b_device = true; else usb3->forced_b_device = false; @@ -2440,7 +2445,7 @@ static ssize_t renesas_usb3_b_device_write(struct file *file, if (usb3->workaround_for_vbus) usb3_disconnect(usb3); - /* Let this driver call usb3_connect() anyway */ + /* Let this driver call usb3_connect() if needed */ usb3_check_id(usb3); return count; @@ -2625,6 +2630,10 @@ MODULE_DEVICE_TABLE(of, usb3_of_match); static const struct soc_device_attribute renesas_usb3_quirks_match[] = { { + .soc_id = "r8a774c0", + .data = &renesas_usb3_priv_r8a77990, + }, + { .soc_id = "r8a7795", .revision = "ES1.*", .data = &renesas_usb3_priv_r8a7795_es1, }, diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 8bf5ad7a59ad..af3e63316ace 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -119,7 +119,7 @@ static void dprintk(int level, const char *fmt, ...) } #endif -static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p) +static int s3c2410_udc_debugfs_show(struct seq_file *m, void *p) { u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg; u32 ep_int_en_reg, usb_int_en_reg, ep0_csr; @@ -168,20 +168,7 @@ static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p) return 0; } - -static int s3c2410_udc_debugfs_fops_open(struct inode *inode, - struct file *file) -{ - return single_open(file, s3c2410_udc_debugfs_seq_show, NULL); -} - -static const struct file_operations s3c2410_udc_debugfs_fops = { - .open = s3c2410_udc_debugfs_fops_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(s3c2410_udc_debugfs); /* io macros */ diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index d4da47f4f6f4..3fcded31405a 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -947,15 +947,14 @@ static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp) UDC_DMA_STP_STS_BS_HOST_READY, UDC_DMA_STP_STS_BS); - - /* clear NAK by writing CNAK */ - if (ep->naking) { - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 16758b12a5e9..d809671c5fea 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Host Controller Drivers # @@ -69,13 +70,13 @@ config USB_XHCI_MTK If unsure, say N. config USB_XHCI_MVEBU - tristate "xHCI support for Marvell Armada 375/38x" + tristate "xHCI support for Marvell Armada 375/38x/37xx" select USB_XHCI_PLATFORM depends on HAS_IOMEM depends on ARCH_MVEBU || COMPILE_TEST ---help--- Say 'Y' to enable the support for the xHCI host controller - found in Marvell Armada 375/38x ARM SOCs. + found in Marvell Armada 375/38x/37xx ARM SOCs. config USB_XHCI_RCAR tristate "xHCI support for Renesas R-Car SoCs" @@ -179,8 +180,7 @@ config XPS_USB_HCD_XILINX devices only. config USB_EHCI_FSL - tristate "Support for Freescale PPC on-chip EHCI USB controller" - depends on FSL_SOC + tristate "Support for Freescale on-chip EHCI USB controller" select USB_EHCI_ROOT_HUB_TT ---help--- Variation of ARC USB block used in some Freescale chips. diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 0a9fd2022acf..e3d0c1c25160 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -23,6 +23,7 @@ #include <linux/platform_device.h> #include <linux/fsl_devices.h> #include <linux/of_platform.h> +#include <linux/io.h> #include "ehci.h" #include "ehci-fsl.h" @@ -50,6 +51,7 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) struct resource *res; int irq; int retval; + u32 tmp; pr_debug("initializing FSL-SOC USB Controller\n"); @@ -114,17 +116,22 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) } /* Enable USB controller, 83xx or 8536 */ - if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, 0x4); - + if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) { + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= 0x4; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + } /* * Enable UTMI phy and program PTS field in UTMI mode before asserting * controller reset for USB Controller version 2.5 */ if (pdata->has_fsl_erratum_a007792) { - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN); + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); } @@ -174,7 +181,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc; + u32 portsc, tmp; struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; struct device *dev = hcd->self.controller; @@ -192,11 +199,16 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrbits32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); + /* turn off UTMI PHY first */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~(CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + + /* then turn on ULPI and enable USB controller */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); } portsc |= PORT_PTS_ULPI; break; @@ -210,16 +222,21 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN); + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } /* enable UTMI PHY */ - if (pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - CTRL_UTMI_PHY_EN); + if (pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: @@ -241,9 +258,12 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); - if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN); + if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } return 0; } @@ -284,14 +304,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) return -EINVAL; if (pdata->operating_mode == FSL_USB2_MPH_HOST) { - unsigned int chip, rev, svr; - - svr = mfspr(SPRN_SVR); - chip = svr >> 16; - rev = (svr >> 4) & 0xf; /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ - if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) + if (pdata->has_fsl_erratum_14 == 1) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index f26109eafdbf..66ec1fdf9fe7 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -302,3 +302,4 @@ MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>"); MODULE_ALIAS("mv-ehci"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, ehci_mv_dt_ids); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 7e4c13346a1e..7d20296cbe9f 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -159,11 +159,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) /* get the PHY device */ phy = devm_usb_get_phy_by_phandle(dev, "phys", i); if (IS_ERR(phy)) { - /* Don't bail out if PHY is not absolutely necessary */ - if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) + ret = PTR_ERR(phy); + if (ret == -ENODEV) { /* no PHY */ + phy = NULL; continue; + } - ret = PTR_ERR(phy); if (ret != -EPROBE_DEFER) dev_err(dev, "Can't get PHY for port %d: %d\n", i, ret); diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 1ad72647a069..790acf3633e8 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -182,6 +182,23 @@ static int ehci_orion_drv_reset(struct usb_hcd *hcd) return ret; } +static int __maybe_unused ehci_orion_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return ehci_suspend(hcd, device_may_wakeup(dev)); +} + +static int __maybe_unused ehci_orion_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return ehci_resume(hcd, false); +} + +static SIMPLE_DEV_PM_OPS(ehci_orion_pm_ops, ehci_orion_drv_suspend, + ehci_orion_drv_resume); + static const struct ehci_driver_overrides orion_overrides __initconst = { .extra_priv_size = sizeof(struct orion_ehci_hcd), .reset = ehci_orion_drv_reset, @@ -257,15 +274,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) if (IS_ERR(priv->phy)) { err = PTR_ERR(priv->phy); if (err != -ENOSYS) - goto err_phy_get; - } else { - err = phy_init(priv->phy); - if (err) - goto err_phy_init; - - err = phy_power_on(priv->phy); - if (err) - goto err_phy_power_on; + goto err_dis_clk; } /* @@ -297,19 +306,12 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_add_hcd; + goto err_dis_clk; device_wakeup_enable(hcd->self.controller); return 0; -err_add_hcd: - if (!IS_ERR(priv->phy)) - phy_power_off(priv->phy); -err_phy_power_on: - if (!IS_ERR(priv->phy)) - phy_exit(priv->phy); -err_phy_init: -err_phy_get: +err_dis_clk: if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); usb_put_hcd(hcd); @@ -327,11 +329,6 @@ static int ehci_orion_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); - if (!IS_ERR(priv->phy)) { - phy_power_off(priv->phy); - phy_exit(priv->phy); - } - if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); @@ -354,6 +351,7 @@ static struct platform_driver ehci_orion_driver = { .driver = { .name = "orion-ehci", .of_match_table = ehci_orion_dt_ids, + .pm = &ehci_orion_pm_ops, }, }; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 677f9d592109..4f8b8a08c914 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -225,6 +225,12 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->has_fsl_erratum_a005697 = of_property_read_bool(np, "fsl,usb_erratum-a005697"); + if (of_get_property(np, "fsl,usb_erratum_14", NULL)) + pdata->has_fsl_erratum_14 = 1; + else + pdata->has_fsl_erratum_14 = 0; + + /* * Determine whether phy_clk_valid needs to be checked * by reading property in device tree diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index b21c386e6a46..28bf8bfb091e 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2159,25 +2159,15 @@ static int isp1362_show(struct seq_file *s, void *unused) return 0; } - -static int isp1362_open(struct inode *inode, struct file *file) -{ - return single_open(file, isp1362_show, inode); -} - -static const struct file_operations debug_ops = { - .open = isp1362_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(isp1362); /* expect just one isp1362_hcd per system */ static void create_debug_file(struct isp1362_hcd *isp1362_hcd) { isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO, usb_debug_root, - isp1362_hcd, &debug_ops); + isp1362_hcd, + &isp1362_fops); } static void remove_debug_file(struct isp1362_hcd *isp1362_hcd) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index ec6739ef3129..fc35a7993b7b 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -141,8 +141,11 @@ static struct regmap *at91_dt_syscon_sfr(void) struct regmap *regmap; regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); - if (IS_ERR(regmap)) - regmap = NULL; + if (IS_ERR(regmap)) { + regmap = syscon_regmap_lookup_by_compatible("microchip,sam9x60-sfr"); + if (IS_ERR(regmap)) + regmap = NULL; + } return regmap; } diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index a55cbba40a5a..ca8a94f15ac0 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -9,6 +9,7 @@ */ #include <linux/clk.h> +#include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/jiffies.h> @@ -40,6 +41,8 @@ struct da8xx_ohci_hcd { struct regulator *vbus_reg; struct notifier_block nb; unsigned int reg_enabled; + struct gpio_desc *vbus_gpio; + struct gpio_desc *oc_gpio; }; #define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv) @@ -86,12 +89,13 @@ static void ohci_da8xx_disable(struct usb_hcd *hcd) static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); + struct device *dev = hcd->self.controller; int ret; - if (hub && hub->set_power) - return hub->set_power(1, on); + if (da8xx_ohci->vbus_gpio) { + gpiod_set_value_cansleep(da8xx_ohci->vbus_gpio, on); + return 0; + } if (!da8xx_ohci->vbus_reg) return 0; @@ -119,11 +123,9 @@ static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on) static int ohci_da8xx_get_power(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - if (hub && hub->get_power) - return hub->get_power(1); + if (da8xx_ohci->vbus_gpio) + return gpiod_get_value_cansleep(da8xx_ohci->vbus_gpio); if (da8xx_ohci->vbus_reg) return regulator_is_enabled(da8xx_ohci->vbus_reg); @@ -134,13 +136,11 @@ static int ohci_da8xx_get_power(struct usb_hcd *hcd) static int ohci_da8xx_get_oci(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); unsigned int flags; int ret; - if (hub && hub->get_oci) - return hub->get_oci(1); + if (da8xx_ohci->oc_gpio) + return gpiod_get_value_cansleep(da8xx_ohci->oc_gpio); if (!da8xx_ohci->vbus_reg) return 0; @@ -158,10 +158,8 @@ static int ohci_da8xx_get_oci(struct usb_hcd *hcd) static int ohci_da8xx_has_set_power(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - if (hub && hub->set_power) + if (da8xx_ohci->vbus_gpio) return 1; if (da8xx_ohci->vbus_reg) @@ -173,10 +171,8 @@ static int ohci_da8xx_has_set_power(struct usb_hcd *hcd) static int ohci_da8xx_has_oci(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - if (hub && hub->get_oci) + if (da8xx_ohci->oc_gpio) return 1; if (da8xx_ohci->vbus_reg) @@ -196,19 +192,6 @@ static int ohci_da8xx_has_potpgt(struct usb_hcd *hcd) return 0; } -/* - * Handle the port over-current indicator change. - */ -static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub, - unsigned port) -{ - ocic_mask |= 1 << port; - - /* Once over-current is detected, the port needs to be powered down */ - if (hub->get_oci(port) > 0) - hub->set_power(port, 0); -} - static int ohci_da8xx_regulator_event(struct notifier_block *nb, unsigned long event, void *data) { @@ -223,16 +206,23 @@ static int ohci_da8xx_regulator_event(struct notifier_block *nb, return 0; } +static irqreturn_t ohci_da8xx_oc_handler(int irq, void *data) +{ + struct da8xx_ohci_hcd *da8xx_ohci = data; + + if (gpiod_get_value(da8xx_ohci->oc_gpio)) + gpiod_set_value(da8xx_ohci->vbus_gpio, 0); + + return IRQ_HANDLED; +} + static int ohci_da8xx_register_notify(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); int ret = 0; - if (hub && hub->ocic_notify) { - ret = hub->ocic_notify(ohci_da8xx_ocic_handler); - } else if (da8xx_ohci->vbus_reg) { + if (!da8xx_ohci->oc_gpio && da8xx_ohci->vbus_reg) { da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event; ret = devm_regulator_register_notifier(da8xx_ohci->vbus_reg, &da8xx_ohci->nb); @@ -244,15 +234,6 @@ static int ohci_da8xx_register_notify(struct usb_hcd *hcd) return ret; } -static void ohci_da8xx_unregister_notify(struct usb_hcd *hcd) -{ - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - - if (hub && hub->ocic_notify) - hub->ocic_notify(NULL); -} - static int ohci_da8xx_reset(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; @@ -402,34 +383,35 @@ MODULE_DEVICE_TABLE(of, da8xx_ohci_ids); static int ohci_da8xx_probe(struct platform_device *pdev) { struct da8xx_ohci_hcd *da8xx_ohci; + struct device *dev = &pdev->dev; + int error, hcd_irq, oc_irq; struct usb_hcd *hcd; struct resource *mem; - int error, irq; - hcd = usb_create_hcd(&ohci_da8xx_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); + + hcd = usb_create_hcd(&ohci_da8xx_hc_driver, dev, dev_name(dev)); if (!hcd) return -ENOMEM; da8xx_ohci = to_da8xx_ohci(hcd); da8xx_ohci->hcd = hcd; - da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, NULL); + da8xx_ohci->usb11_clk = devm_clk_get(dev, NULL); if (IS_ERR(da8xx_ohci->usb11_clk)) { error = PTR_ERR(da8xx_ohci->usb11_clk); if (error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get clock.\n"); + dev_err(dev, "Failed to get clock.\n"); goto err; } - da8xx_ohci->usb11_phy = devm_phy_get(&pdev->dev, "usb-phy"); + da8xx_ohci->usb11_phy = devm_phy_get(dev, "usb-phy"); if (IS_ERR(da8xx_ohci->usb11_phy)) { error = PTR_ERR(da8xx_ohci->usb11_phy); if (error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get phy.\n"); + dev_err(dev, "Failed to get phy.\n"); goto err; } - da8xx_ohci->vbus_reg = devm_regulator_get_optional(&pdev->dev, "vbus"); + da8xx_ohci->vbus_reg = devm_regulator_get_optional(dev, "vbus"); if (IS_ERR(da8xx_ohci->vbus_reg)) { error = PTR_ERR(da8xx_ohci->vbus_reg); if (error == -ENODEV) { @@ -437,13 +419,34 @@ static int ohci_da8xx_probe(struct platform_device *pdev) } else if (error == -EPROBE_DEFER) { goto err; } else { - dev_err(&pdev->dev, "Failed to get regulator\n"); + dev_err(dev, "Failed to get regulator\n"); goto err; } } + da8xx_ohci->vbus_gpio = devm_gpiod_get_optional(dev, "vbus", + GPIOD_OUT_HIGH); + if (IS_ERR(da8xx_ohci->vbus_gpio)) + goto err; + + da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN); + if (IS_ERR(da8xx_ohci->oc_gpio)) + goto err; + + if (da8xx_ohci->oc_gpio) { + oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio); + if (oc_irq < 0) + goto err; + + error = devm_request_irq(dev, oc_irq, ohci_da8xx_oc_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "OHCI over-current indicator", da8xx_ohci); + if (error) + goto err; + } + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, mem); + hcd->regs = devm_ioremap_resource(dev, mem); if (IS_ERR(hcd->regs)) { error = PTR_ERR(hcd->regs); goto err; @@ -451,13 +454,13 @@ static int ohci_da8xx_probe(struct platform_device *pdev) hcd->rsrc_start = mem->start; hcd->rsrc_len = resource_size(mem); - irq = platform_get_irq(pdev, 0); - if (irq < 0) { + hcd_irq = platform_get_irq(pdev, 0); + if (hcd_irq < 0) { error = -ENODEV; goto err; } - error = usb_add_hcd(hcd, irq, 0); + error = usb_add_hcd(hcd, hcd_irq, 0); if (error) goto err; @@ -480,7 +483,6 @@ static int ohci_da8xx_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - ohci_da8xx_unregister_notify(hcd); usb_remove_hcd(hcd); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index b3da3f12e5b1..3965ac0341eb 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -57,14 +57,10 @@ static int ohci_mem_init (struct ohci_hcd *ohci) static void ohci_mem_cleanup (struct ohci_hcd *ohci) { - if (ohci->td_cache) { - dma_pool_destroy (ohci->td_cache); - ohci->td_cache = NULL; - } - if (ohci->ed_cache) { - dma_pool_destroy (ohci->ed_cache); - ohci->ed_cache = NULL; - } + dma_pool_destroy(ohci->td_cache); + ohci->td_cache = NULL; + dma_pool_destroy(ohci->ed_cache); + ohci->ed_cache = NULL; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index c9233cddf9a2..c26228c25f99 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -126,8 +126,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) retval = dma_declare_coherent_memory(dev, mem->start, mem->start - mem->parent->start, - resource_size(mem), - DMA_MEMORY_EXCLUSIVE); + resource_size(mem)); if (retval) { dev_err(dev, "cannot declare coherent memory\n"); goto err1; diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index a631dbb369d7..f88a0370659f 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -225,7 +225,7 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev) } ret = dma_declare_coherent_memory(&dev->dev, sram->start, sram->start, - resource_size(sram), DMA_MEMORY_EXCLUSIVE); + resource_size(sram)); if (ret) goto err_dma_declare; diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index c5e6e8d0b5ef..47c5515a9ce4 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -1323,7 +1323,7 @@ static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu, } /* by default, enable interrupt on urb completion */ - qtd->hw_token |= cpu_to_le32(QTD_IOC); + qtd->hw_token |= cpu_to_le32(QTD_IOC); return head; cleanup: @@ -2253,16 +2253,12 @@ static void scan_periodic(struct oxu_hcd *oxu) for (;;) { union ehci_shadow q, *q_p; __le32 type, *hw_p; - unsigned uframes; /* don't scan past the live uframe */ frame = now_uframe >> 3; - if (frame == (clock >> 3)) - uframes = now_uframe & 0x07; - else { + if (frame != (clock >> 3)) { /* safe to scan the whole frame at once */ now_uframe |= 0x07; - uframes = 8; } restart: @@ -2832,7 +2828,6 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, { struct oxu_hcd *oxu = hcd_to_oxu(hcd); int num, rem; - int transfer_buffer_length; void *transfer_buffer; struct urb *murb; int i, ret; @@ -2843,7 +2838,6 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, /* Otherwise we should verify the USB transfer buffer size! */ transfer_buffer = urb->transfer_buffer; - transfer_buffer_length = urb->transfer_buffer_length; num = urb->transfer_buffer_length / 4096; rem = urb->transfer_buffer_length % 4096; diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 984892dd72f5..42668aeca57c 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1979,6 +1979,8 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, static void r8a66597_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) +__acquires(r8a66597->lock) +__releases(r8a66597->lock) { struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv; @@ -1991,13 +1993,14 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, return; pipenum = pipe->info.pipenum; + spin_lock_irqsave(&r8a66597->lock, flags); if (pipenum == 0) { kfree(hep->hcpriv); hep->hcpriv = NULL; + spin_unlock_irqrestore(&r8a66597->lock, flags); return; } - spin_lock_irqsave(&r8a66597->lock, flags); pipe_stop(r8a66597, pipe); pipe_irq_disable(r8a66597, pipenum); disable_irq_empty(r8a66597, pipenum); diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5b8a3d9530c4..6343fbacd244 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2477,7 +2477,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } urb->error_count = 0; + } + urb->error_count = 0; usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { @@ -2982,7 +2983,8 @@ static int u132_remove(struct platform_device *pdev) while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; u132_ring_cancel_work(u132, ring); - } while (endps-- > 0) { + } + while (endps-- > 0) { struct u132_endp *endp = u132->endp[endps]; if (endp) u132_endp_cancel_work(u132, endp); @@ -3202,6 +3204,9 @@ static int __init u132_hcd_init(void) printk(KERN_INFO "driver %s\n", hcd_name); workqueue = create_singlethread_workqueue("u132"); retval = platform_driver_register(&u132_platform_driver); + if (retval) + destroy_workqueue(workqueue); + return retval; } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 6218bfe54f52..98deb5f64268 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -596,9 +596,9 @@ static int uhci_start(struct usb_hcd *hcd) &uhci_debug_operations); #endif - uhci->frame = dma_zalloc_coherent(uhci_dev(uhci), - UHCI_NUMFRAMES * sizeof(*uhci->frame), - &uhci->frame_dma_handle, GFP_KERNEL); + uhci->frame = dma_alloc_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + &uhci->frame_dma_handle, GFP_KERNEL); if (!uhci->frame) { dev_err(uhci_dev(uhci), "unable to allocate consistent memory for frame list\n"); diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Makefile index 26df0138079e..859d20079df6 100644 --- a/drivers/usb/host/whci/Kbuild +++ b/drivers/usb/host/whci/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o whci-hcd-y := \ diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 86cff5c28eff..d932cc31711e 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -181,7 +181,7 @@ static void xhci_dbc_flush_endpoint_requests(struct dbc_ep *dep) xhci_dbc_flush_single_request(req); } -static void xhci_dbc_flush_reqests(struct xhci_dbc *dbc) +static void xhci_dbc_flush_requests(struct xhci_dbc *dbc) { xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_OUT]); xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_IN]); @@ -516,7 +516,6 @@ static int xhci_do_dbc_stop(struct xhci_hcd *xhci) return -1; writel(0, &dbc->regs->control); - xhci_dbc_mem_cleanup(xhci); dbc->state = DS_DISABLED; return 0; @@ -562,8 +561,10 @@ static void xhci_dbc_stop(struct xhci_hcd *xhci) ret = xhci_do_dbc_stop(xhci); spin_unlock_irqrestore(&dbc->lock, flags); - if (!ret) + if (!ret) { + xhci_dbc_mem_cleanup(xhci); pm_runtime_put_sync(xhci_to_hcd(xhci)->self.controller); + } } static void @@ -687,7 +688,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) !(portsc & DBC_PORTSC_CONN_STATUS)) { xhci_info(xhci, "DbC cable unplugged\n"); dbc->state = DS_ENABLED; - xhci_dbc_flush_reqests(dbc); + xhci_dbc_flush_requests(dbc); return EVT_DISC; } @@ -697,7 +698,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) xhci_info(xhci, "DbC port reset\n"); writel(portsc, &dbc->regs->portsc); dbc->state = DS_ENABLED; - xhci_dbc_flush_reqests(dbc); + xhci_dbc_flush_requests(dbc); return EVT_DISC; } diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h index ac5bc40f5c3a..f7a4e2492b00 100644 --- a/drivers/usb/host/xhci-debugfs.h +++ b/drivers/usb/host/xhci-debugfs.h @@ -80,7 +80,6 @@ struct xhci_regset { char name[DEBUGFS_NAMELEN]; struct debugfs_regset32 regset; size_t nregs; - struct dentry *parent; struct list_head list; }; diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 01b5818a4be5..96a740543183 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -714,13 +714,6 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port, } } -/* Updates Link Status for USB 2.1 port */ -static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg) -{ - if ((status_reg & PORT_PLS_MASK) == XDEV_U2) - *status |= USB_PORT_STAT_L1; -} - /* Updates Link Status for super Speed port */ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci, u32 *status, u32 status_reg) @@ -802,6 +795,100 @@ static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, } } +static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, + u32 *status, u32 portsc, + unsigned long flags) +{ + struct xhci_bus_state *bus_state; + struct xhci_hcd *xhci; + struct usb_hcd *hcd; + int slot_id; + u32 wIndex; + + hcd = port->rhub->hcd; + bus_state = &port->rhub->bus_state; + xhci = hcd_to_xhci(hcd); + wIndex = port->hcd_portnum; + + if ((portsc & PORT_RESET) || !(portsc & PORT_PE)) { + *status = 0xffffffff; + return -EINVAL; + } + /* did port event handler already start resume timing? */ + if (!bus_state->resume_done[wIndex]) { + /* If not, maybe we are in a host initated resume? */ + if (test_bit(wIndex, &bus_state->resuming_ports)) { + /* Host initated resume doesn't time the resume + * signalling using resume_done[]. + * It manually sets RESUME state, sleeps 20ms + * and sets U0 state. This should probably be + * changed, but not right now. + */ + } else { + /* port resume was discovered now and here, + * start resume timing + */ + unsigned long timeout = jiffies + + msecs_to_jiffies(USB_RESUME_TIMEOUT); + + set_bit(wIndex, &bus_state->resuming_ports); + bus_state->resume_done[wIndex] = timeout; + mod_timer(&hcd->rh_timer, timeout); + usb_hcd_start_port_resume(&hcd->self, wIndex); + } + /* Has resume been signalled for USB_RESUME_TIME yet? */ + } else if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { + int time_left; + + xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); + bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); + + set_bit(wIndex, &bus_state->rexit_ports); + + xhci_test_and_clear_bit(xhci, port, PORT_PLC); + xhci_set_link_state(xhci, port, XDEV_U0); + + spin_unlock_irqrestore(&xhci->lock, flags); + time_left = wait_for_completion_timeout( + &bus_state->rexit_done[wIndex], + msecs_to_jiffies(XHCI_MAX_REXIT_TIMEOUT_MS)); + spin_lock_irqsave(&xhci->lock, flags); + + if (time_left) { + slot_id = xhci_find_slot_id_by_port(hcd, xhci, + wIndex + 1); + if (!slot_id) { + xhci_dbg(xhci, "slot_id is zero\n"); + *status = 0xffffffff; + return -ENODEV; + } + xhci_ring_device(xhci, slot_id); + } else { + int port_status = readl(port->addr); + + xhci_warn(xhci, "Port resume %i msec timed out, portsc = 0x%x\n", + XHCI_MAX_REXIT_TIMEOUT_MS, + port_status); + *status |= USB_PORT_STAT_SUSPEND; + clear_bit(wIndex, &bus_state->rexit_ports); + } + + usb_hcd_end_port_resume(&hcd->self, wIndex); + bus_state->port_c_suspend |= 1 << wIndex; + bus_state->suspended_ports &= ~(1 << wIndex); + } else { + /* + * The resume has been signaling for less than + * USB_RESUME_TIME. Report the port status as SUSPEND, + * let the usbcore check port status again and clear + * resume signaling later. + */ + *status |= USB_PORT_STAT_SUSPEND; + } + return 0; +} + static u32 xhci_get_ext_port_status(u32 raw_port_status, u32 port_li) { u32 ext_stat = 0; @@ -818,6 +905,85 @@ static u32 xhci_get_ext_port_status(u32 raw_port_status, u32 port_li) return ext_stat; } +static void xhci_get_usb3_port_status(struct xhci_port *port, u32 *status, + u32 portsc) +{ + struct xhci_bus_state *bus_state; + struct xhci_hcd *xhci; + u32 link_state; + u32 portnum; + + bus_state = &port->rhub->bus_state; + xhci = hcd_to_xhci(port->rhub->hcd); + link_state = portsc & PORT_PLS_MASK; + portnum = port->hcd_portnum; + + /* USB3 specific wPortChange bits + * + * Port link change with port in resume state should not be + * reported to usbcore, as this is an internal state to be + * handled by xhci driver. Reporting PLC to usbcore may + * cause usbcore clearing PLC first and port change event + * irq won't be generated. + */ + + if (portsc & PORT_PLC && (link_state != XDEV_RESUME)) + *status |= USB_PORT_STAT_C_LINK_STATE << 16; + if (portsc & PORT_WRC) + *status |= USB_PORT_STAT_C_BH_RESET << 16; + if (portsc & PORT_CEC) + *status |= USB_PORT_STAT_C_CONFIG_ERROR << 16; + + /* USB3 specific wPortStatus bits */ + if (portsc & PORT_POWER) { + *status |= USB_SS_PORT_STAT_POWER; + /* link state handling */ + if (link_state == XDEV_U0) + bus_state->suspended_ports &= ~(1 << portnum); + } + + xhci_hub_report_usb3_link_state(xhci, status, portsc); + xhci_del_comp_mod_timer(xhci, portsc, portnum); +} + +static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status, + u32 portsc, unsigned long flags) +{ + struct xhci_bus_state *bus_state; + u32 link_state; + u32 portnum; + int ret; + + bus_state = &port->rhub->bus_state; + link_state = portsc & PORT_PLS_MASK; + portnum = port->hcd_portnum; + + /* USB2 wPortStatus bits */ + if (portsc & PORT_POWER) { + *status |= USB_PORT_STAT_POWER; + + /* link state is only valid if port is powered */ + if (link_state == XDEV_U3) + *status |= USB_PORT_STAT_SUSPEND; + if (link_state == XDEV_U2) + *status |= USB_PORT_STAT_L1; + if (link_state == XDEV_U0) { + bus_state->resume_done[portnum] = 0; + clear_bit(portnum, &bus_state->resuming_ports); + if (bus_state->suspended_ports & (1 << portnum)) { + bus_state->suspended_ports &= ~(1 << portnum); + bus_state->port_c_suspend |= 1 << portnum; + } + } + if (link_state == XDEV_RESUME) { + ret = xhci_handle_usb2_port_link_resume(port, status, + portsc, flags); + if (ret) + return; + } + } +} + /* * Converts a raw xHCI port status into the format that external USB 2.0 or USB * 3.0 hubs use. @@ -835,16 +1001,14 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, __releases(&xhci->lock) __acquires(&xhci->lock) { - struct xhci_hcd *xhci = hcd_to_xhci(hcd); u32 status = 0; - int slot_id; struct xhci_hub *rhub; struct xhci_port *port; rhub = xhci_get_rhub(hcd); port = rhub->ports[wIndex]; - /* wPortChange bits */ + /* common wPortChange bits */ if (raw_port_status & PORT_CSC) status |= USB_PORT_STAT_C_CONNECTION << 16; if (raw_port_status & PORT_PEC) @@ -853,107 +1017,25 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, status |= USB_PORT_STAT_C_OVERCURRENT << 16; if ((raw_port_status & PORT_RC)) status |= USB_PORT_STAT_C_RESET << 16; - /* USB3.0 only */ - if (hcd->speed >= HCD_USB3) { - /* Port link change with port in resume state should not be - * reported to usbcore, as this is an internal state to be - * handled by xhci driver. Reporting PLC to usbcore may - * cause usbcore clearing PLC first and port change event - * irq won't be generated. - */ - if ((raw_port_status & PORT_PLC) && - (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) - status |= USB_PORT_STAT_C_LINK_STATE << 16; - if ((raw_port_status & PORT_WRC)) - status |= USB_PORT_STAT_C_BH_RESET << 16; - if ((raw_port_status & PORT_CEC)) - status |= USB_PORT_STAT_C_CONFIG_ERROR << 16; - } - if (hcd->speed < HCD_USB3) { - if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3 - && (raw_port_status & PORT_POWER)) - status |= USB_PORT_STAT_SUSPEND; + /* common wPortStatus bits */ + if (raw_port_status & PORT_CONNECT) { + status |= USB_PORT_STAT_CONNECTION; + status |= xhci_port_speed(raw_port_status); } - if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME && - !DEV_SUPERSPEED_ANY(raw_port_status) && hcd->speed < HCD_USB3) { - if ((raw_port_status & PORT_RESET) || - !(raw_port_status & PORT_PE)) - return 0xffffffff; - /* did port event handler already start resume timing? */ - if (!bus_state->resume_done[wIndex]) { - /* If not, maybe we are in a host initated resume? */ - if (test_bit(wIndex, &bus_state->resuming_ports)) { - /* Host initated resume doesn't time the resume - * signalling using resume_done[]. - * It manually sets RESUME state, sleeps 20ms - * and sets U0 state. This should probably be - * changed, but not right now. - */ - } else { - /* port resume was discovered now and here, - * start resume timing - */ - unsigned long timeout = jiffies + - msecs_to_jiffies(USB_RESUME_TIMEOUT); - - set_bit(wIndex, &bus_state->resuming_ports); - bus_state->resume_done[wIndex] = timeout; - mod_timer(&hcd->rh_timer, timeout); - usb_hcd_start_port_resume(&hcd->self, wIndex); - } - /* Has resume been signalled for USB_RESUME_TIME yet? */ - } else if (time_after_eq(jiffies, - bus_state->resume_done[wIndex])) { - int time_left; - - xhci_dbg(xhci, "Resume USB2 port %d\n", - wIndex + 1); - bus_state->resume_done[wIndex] = 0; - clear_bit(wIndex, &bus_state->resuming_ports); - - set_bit(wIndex, &bus_state->rexit_ports); - - xhci_test_and_clear_bit(xhci, port, PORT_PLC); - xhci_set_link_state(xhci, port, XDEV_U0); - - spin_unlock_irqrestore(&xhci->lock, flags); - time_left = wait_for_completion_timeout( - &bus_state->rexit_done[wIndex], - msecs_to_jiffies( - XHCI_MAX_REXIT_TIMEOUT_MS)); - spin_lock_irqsave(&xhci->lock, flags); - - if (time_left) { - slot_id = xhci_find_slot_id_by_port(hcd, - xhci, wIndex + 1); - if (!slot_id) { - xhci_dbg(xhci, "slot_id is zero\n"); - return 0xffffffff; - } - xhci_ring_device(xhci, slot_id); - } else { - int port_status = readl(port->addr); - xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", - XHCI_MAX_REXIT_TIMEOUT_MS, - port_status); - status |= USB_PORT_STAT_SUSPEND; - clear_bit(wIndex, &bus_state->rexit_ports); - } + if (raw_port_status & PORT_PE) + status |= USB_PORT_STAT_ENABLE; + if (raw_port_status & PORT_OC) + status |= USB_PORT_STAT_OVERCURRENT; + if (raw_port_status & PORT_RESET) + status |= USB_PORT_STAT_RESET; - usb_hcd_end_port_resume(&hcd->self, wIndex); - bus_state->port_c_suspend |= 1 << wIndex; - bus_state->suspended_ports &= ~(1 << wIndex); - } else { - /* - * The resume has been signaling for less than - * USB_RESUME_TIME. Report the port status as SUSPEND, - * let the usbcore check port status again and clear - * resume signaling later. - */ - status |= USB_PORT_STAT_SUSPEND; - } - } + /* USB2 and USB3 specific bits, including Port Link State */ + if (hcd->speed >= HCD_USB3) + xhci_get_usb3_port_status(port, &status, raw_port_status); + else + xhci_get_usb2_port_status(port, &status, raw_port_status, + flags); /* * Clear stale usb2 resume signalling variables in case port changed * state during resume signalling. For example on error @@ -967,44 +1049,6 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, usb_hcd_end_port_resume(&hcd->self, wIndex); } - - if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 && - (raw_port_status & PORT_POWER)) { - if (bus_state->suspended_ports & (1 << wIndex)) { - bus_state->suspended_ports &= ~(1 << wIndex); - if (hcd->speed < HCD_USB3) - bus_state->port_c_suspend |= 1 << wIndex; - } - bus_state->resume_done[wIndex] = 0; - clear_bit(wIndex, &bus_state->resuming_ports); - } - if (raw_port_status & PORT_CONNECT) { - status |= USB_PORT_STAT_CONNECTION; - status |= xhci_port_speed(raw_port_status); - } - if (raw_port_status & PORT_PE) - status |= USB_PORT_STAT_ENABLE; - if (raw_port_status & PORT_OC) - status |= USB_PORT_STAT_OVERCURRENT; - if (raw_port_status & PORT_RESET) - status |= USB_PORT_STAT_RESET; - if (raw_port_status & PORT_POWER) { - if (hcd->speed >= HCD_USB3) - status |= USB_SS_PORT_STAT_POWER; - else - status |= USB_PORT_STAT_POWER; - } - /* Update Port Link State */ - if (hcd->speed >= HCD_USB3) { - xhci_hub_report_usb3_link_state(xhci, &status, raw_port_status); - /* - * Verify if all USB3 Ports Have entered U0 already. - * Delete Compliance Mode Timer if so. - */ - xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex); - } else { - xhci_hub_report_usb2_link_state(&status, raw_port_status); - } if (bus_state->port_c_suspend & (1 << wIndex)) status |= USB_PORT_STAT_C_SUSPEND << 16; @@ -1031,7 +1075,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, rhub = xhci_get_rhub(hcd); ports = rhub->ports; max_ports = rhub->num_ports; - bus_state = &xhci->bus_state[hcd_index(hcd)]; + bus_state = &rhub->bus_state; spin_lock_irqsave(&xhci->lock, flags); switch (typeReq) { @@ -1421,7 +1465,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) rhub = xhci_get_rhub(hcd); ports = rhub->ports; max_ports = rhub->num_ports; - bus_state = &xhci->bus_state[hcd_index(hcd)]; + bus_state = &rhub->bus_state; /* Initial status is no changes */ retval = (max_ports + 8) / 8; @@ -1480,7 +1524,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) rhub = xhci_get_rhub(hcd); ports = rhub->ports; max_ports = rhub->num_ports; - bus_state = &xhci->bus_state[hcd_index(hcd)]; + bus_state = &rhub->bus_state; wake_enabled = hcd->self.root_hub->do_remote_wakeup; spin_lock_irqsave(&xhci->lock, flags); @@ -1501,20 +1545,25 @@ int xhci_bus_suspend(struct usb_hcd *hcd) port_index = max_ports; while (port_index--) { u32 t1, t2; - + int retries = 10; +retry: t1 = readl(ports[port_index]->addr); t2 = xhci_port_state_to_neutral(t1); portsc_buf[port_index] = 0; - /* Bail out if a USB3 port has a new device in link training */ - if ((hcd->speed >= HCD_USB3) && + /* + * Give a USB3 port in link training time to finish, but don't + * prevent suspend as port might be stuck + */ + if ((hcd->speed >= HCD_USB3) && retries-- && (t1 & PORT_PLS_MASK) == XDEV_POLLING) { - bus_state->bus_suspended = 0; spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "Bus suspend bailout, port in polling\n"); - return -EBUSY; + msleep(XHCI_PORT_POLLING_LFPS_TIME); + spin_lock_irqsave(&xhci->lock, flags); + xhci_dbg(xhci, "port %d polling in bus suspend, waiting\n", + port_index); + goto retry; } - /* suspend ports in U0, or bail out for new connect changes */ if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) { if ((t1 & PORT_CSC) && wake_enabled) { @@ -1623,7 +1672,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) rhub = xhci_get_rhub(hcd); ports = rhub->ports; max_ports = rhub->num_ports; - bus_state = &xhci->bus_state[hcd_index(hcd)]; + bus_state = &rhub->bus_state; if (time_before(jiffies, bus_state->next_statechange)) msleep(5); @@ -1724,13 +1773,10 @@ int xhci_bus_resume(struct usb_hcd *hcd) unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd) { - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_bus_state *bus_state; - - bus_state = &xhci->bus_state[hcd_index(hcd)]; + struct xhci_hub *rhub = xhci_get_rhub(hcd); /* USB3 port wakeups are reported via usb_wakeup_notification() */ - return bus_state->resuming_ports; /* USB2 ports only */ + return rhub->bus_state.resuming_ports; /* USB2 ports only */ } #endif /* CONFIG_PM */ diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index b1f27aa38b10..cf5e17962179 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -933,7 +933,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) * that tt_info, then free the child first. Recursive. * We can't rely on udev at this point to find child-parent relationships. */ -void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) +static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) { struct xhci_virt_device *vdev; struct list_head *tt_list_head; @@ -1672,8 +1672,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma); for (i = 0; i < num_sp; i++) { dma_addr_t dma; - void *buf = dma_zalloc_coherent(dev, xhci->page_size, &dma, - flags); + void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma, + flags); if (!buf) goto fail_sp4; @@ -1799,8 +1799,8 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_erst_entry *entry; size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs; - erst->entries = dma_zalloc_coherent(xhci_to_hcd(xhci)->self.sysdev, - size, &erst->erst_dma_addr, flags); + erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, + size, &erst->erst_dma_addr, flags); if (!erst->entries) return -ENOMEM; @@ -1922,8 +1922,8 @@ no_bw: xhci->page_size = 0; xhci->page_shift = 0; - xhci->bus_state[0].bus_suspended = 0; - xhci->bus_state[1].bus_suspended = 0; + xhci->usb2_rhub.bus_state.bus_suspended = 0; + xhci->usb3_rhub.bus_state.bus_suspended = 0; } static int xhci_test_trb_in_td(struct xhci_hcd *xhci, @@ -2181,23 +2181,11 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, if (major_revision < 0x03 && xhci->num_ext_caps < max_caps) xhci->ext_caps[xhci->num_ext_caps++] = temp; - /* Check the host's USB2 LPM capability */ - if ((xhci->hci_version == 0x96) && (major_revision != 0x03) && - (temp & XHCI_L1C)) { + if ((xhci->hci_version >= 0x100) && (major_revision != 0x03) && + (temp & XHCI_HLC)) { xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "xHCI 0.96: support USB2 software lpm"); - xhci->sw_lpm_support = 1; - } - - if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "xHCI 1.0: support USB2 software lpm"); - xhci->sw_lpm_support = 1; - if (temp & XHCI_HLC) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "xHCI 1.0: support USB2 hardware lpm"); - xhci->hw_lpm_support = 1; - } + "xHCI 1.0: support USB2 hardware lpm"); + xhci->hw_lpm_support = 1; } port_offset--; @@ -2536,10 +2524,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) for (i = 0; i < MAX_HC_SLOTS; i++) xhci->devs[i] = NULL; for (i = 0; i < USB_MAXCHILDREN; i++) { - xhci->bus_state[0].resume_done[i] = 0; - xhci->bus_state[1].resume_done[i] = 0; + xhci->usb2_rhub.bus_state.resume_done[i] = 0; + xhci->usb3_rhub.bus_state.resume_done[i] = 0; /* Only the USB 2.0 completions will ever be used. */ - init_completion(&xhci->bus_state[1].rexit_done[i]); + init_completion(&xhci->usb2_rhub.bus_state.rexit_done[i]); } if (scratchpad_alloc(xhci, flags)) diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 32e158568788..60651a50770f 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -13,6 +13,7 @@ #include <linux/usb/hcd.h> #include "xhci-mvebu.h" +#include "xhci.h" #define USB3_MAX_WINDOWS 4 #define USB3_WIN_CTRL(w) (0x0 + ((w) * 8)) @@ -72,3 +73,13 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) return 0; } + +int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + /* Without reset on resume, the HC won't work at all */ + xhci->quirks |= XHCI_RESET_ON_RESUME; + + return 0; +} diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h index 09791df2cec0..ca0a3a5721dd 100644 --- a/drivers/usb/host/xhci-mvebu.h +++ b/drivers/usb/host/xhci-mvebu.h @@ -12,10 +12,16 @@ struct usb_hcd; #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); +int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd); #else static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) { return 0; } + +static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +{ + return 0; +} #endif #endif /* __LINUX_XHCI_MVEBU_H */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index a9ec7051f286..c2fe218e051f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -194,6 +194,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SSIC_PORT_UNUSED; if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; if (pdev->vendor == PCI_VENDOR_ID_INTEL && diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index ef09cb06212f..0ac4ec975547 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -98,6 +98,10 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = { .init_quirk = xhci_mvebu_mbus_init_quirk, }; +static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { + .init_quirk = xhci_mvebu_a3700_init_quirk, +}; + static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1, .init_quirk = xhci_rcar_init_quirk, @@ -124,6 +128,9 @@ static const struct of_device_id usb_xhci_of_match[] = { .compatible = "marvell,armada-380-xhci", .data = &xhci_plat_marvell_armada, }, { + .compatible = "marvell,armada3700-xhci", + .data = &xhci_plat_marvell_armada3700, + }, { .compatible = "renesas,xhci-r8a7790", .data = &xhci_plat_renesas_rcar_gen2, }, { diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index a6e463715779..671bce18782c 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -246,6 +246,7 @@ int xhci_rcar_init_quirk(struct usb_hcd *hcd) if (!xhci_rcar_wait_for_pll_active(hcd)) return -ETIMEDOUT; + xhci->quirks |= XHCI_TRUST_TX_LENGTH; return xhci_rcar_download_firmware(hcd); } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 65750582133f..9215a28dad40 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1593,7 +1593,7 @@ static void handle_port_status(struct xhci_hcd *xhci, } hcd = port->rhub->hcd; - bus_state = &xhci->bus_state[hcd_index(hcd)]; + bus_state = &port->rhub->bus_state; hcd_portnum = port->hcd_portnum; portsc = readl(port->addr); @@ -1647,10 +1647,13 @@ static void handle_port_status(struct xhci_hcd *xhci, } } - if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_U0 && - DEV_SUPERSPEED_ANY(portsc)) { + if ((portsc & PORT_PLC) && + DEV_SUPERSPEED_ANY(portsc) && + ((portsc & PORT_PLS_MASK) == XDEV_U0 || + (portsc & PORT_PLS_MASK) == XDEV_U1 || + (portsc & PORT_PLS_MASK) == XDEV_U2)) { xhci_dbg(xhci, "resume SS port %d finished\n", port_id); - /* We've just brought the device into U0 through either the + /* We've just brought the device into U0/1/2 through either the * Resume state after a device remote wakeup, or through the * U3Exit state after a host-initiated resume. If it's a device * initiated remote wake, don't pass up the link state change, diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 938ff06c0349..efb0cad8710e 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -941,9 +941,9 @@ static void tegra_xusb_powerdomain_remove(struct device *dev, device_link_del(tegra->genpd_dl_ss); if (tegra->genpd_dl_host) device_link_del(tegra->genpd_dl_host); - if (tegra->genpd_dev_ss) + if (!IS_ERR_OR_NULL(tegra->genpd_dev_ss)) dev_pm_domain_detach(tegra->genpd_dev_ss, true); - if (tegra->genpd_dev_host) + if (!IS_ERR_OR_NULL(tegra->genpd_dev_host)) dev_pm_domain_detach(tegra->genpd_dev_host, true); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index dae3be1b9c8f..7fa58c99f126 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -169,7 +169,7 @@ int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; - int ret, i; + int ret; state = readl(&xhci->op_regs->status); @@ -215,11 +215,12 @@ int xhci_reset(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, 10 * 1000 * 1000); - for (i = 0; i < 2; i++) { - xhci->bus_state[i].port_c_suspend = 0; - xhci->bus_state[i].suspended_ports = 0; - xhci->bus_state[i].resuming_ports = 0; - } + xhci->usb2_rhub.bus_state.port_c_suspend = 0; + xhci->usb2_rhub.bus_state.suspended_ports = 0; + xhci->usb2_rhub.bus_state.resuming_ports = 0; + xhci->usb3_rhub.bus_state.port_c_suspend = 0; + xhci->usb3_rhub.bus_state.suspended_ports = 0; + xhci->usb3_rhub.bus_state.resuming_ports = 0; return ret; } @@ -244,7 +245,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) * an iommu. Doing anything when there is no iommu is definitely * unsafe... */ - if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !dev->iommu_group) + if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !device_iommu_mapped(dev)) return; xhci_info(xhci, "Zeroing 64bit base registers, expecting fault\n"); @@ -1087,9 +1088,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Wait a bit if either of the roothubs need to settle from the * transition into bus suspend. */ - if (time_before(jiffies, xhci->bus_state[0].next_statechange) || - time_before(jiffies, - xhci->bus_state[1].next_statechange)) + + if (time_before(jiffies, xhci->usb2_rhub.bus_state.next_statechange) || + time_before(jiffies, xhci->usb3_rhub.bus_state.next_statechange)) msleep(100); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -1454,8 +1455,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag else num_tds = 1; - urb_priv = kzalloc(sizeof(struct urb_priv) + - num_tds * sizeof(struct xhci_td), mem_flags); + urb_priv = kzalloc(struct_size(urb_priv, td, num_tds), mem_flags); if (!urb_priv) return -ENOMEM; @@ -4388,8 +4388,7 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_hcd *xhci = hcd_to_xhci(hcd); int portnum = udev->portnum - 1; - if (hcd->speed >= HCD_USB3 || !xhci->sw_lpm_support || - !udev->lpm_capable) + if (hcd->speed >= HCD_USB3 || !udev->lpm_capable) return 0; /* we only support lpm for non-hub device connected to root hub yet */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 011dd45f8718..9334cdee382a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -452,6 +452,14 @@ struct xhci_op_regs { */ #define XHCI_DEFAULT_BESL 4 +/* + * USB3 specification define a 360ms tPollingLFPSTiemout for USB3 ports + * to complete link training. usually link trainig completes much faster + * so check status 10 times with 36ms sleep in places we need to wait for + * polling to complete. + */ +#define XHCI_PORT_POLLING_LFPS_TIME 36 + /** * struct xhci_intr_reg - Interrupt Register Set * @irq_pending: IMAN - Interrupt Management Register. Used to enable @@ -1682,13 +1690,6 @@ struct xhci_bus_state { */ #define XHCI_MAX_REXIT_TIMEOUT_MS 20 -static inline unsigned int hcd_index(struct usb_hcd *hcd) -{ - if (hcd->speed >= HCD_USB3) - return 0; - else - return 1; -} struct xhci_port { __le32 __iomem *addr; int hw_portnum; @@ -1700,6 +1701,8 @@ struct xhci_hub { struct xhci_port **ports; unsigned int num_ports; struct usb_hcd *hcd; + /* keep track of bus suspend info */ + struct xhci_bus_state bus_state; /* supported prococol extended capabiliy values */ u8 maj_rev; u8 min_rev; @@ -1854,13 +1857,9 @@ struct xhci_hcd { unsigned int num_active_eps; unsigned int limit_active_eps; - /* There are two roothubs to keep track of bus suspend info for */ - struct xhci_bus_state bus_state[2]; struct xhci_port *hw_ports; struct xhci_hub usb2_rhub; struct xhci_hub usb3_rhub; - /* support xHCI 0.96 spec USB2 software LPM */ - unsigned sw_lpm_support:1; /* support xHCI 1.0 spec USB2 hardware LPM */ unsigned hw_lpm_support:1; /* Broken Suspend flag for SNPS Suspend resume issue */ diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig index 320d368c8dac..26c75f309da9 100644 --- a/drivers/usb/image/Kconfig +++ b/drivers/usb/image/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Imaging devices configuration # diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 9f2f563c82ed..607be1f4fe27 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -632,7 +632,6 @@ static struct scsi_host_template mts_scsi_host_template = { .sg_tablesize = SG_ALL, .can_queue = 1, .this_id = -1, - .use_clustering = 1, .emulated = 1, .slave_alloc = mts_slave_alloc, .slave_configure = mts_slave_configure, diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig index c94b7d953399..b1022cc490a2 100644 --- a/drivers/usb/isp1760/Kconfig +++ b/drivers/usb/isp1760/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_ISP1760 tristate "NXP ISP 1760/1761 support" depends on USB || USB_GADGET diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 68d2f2cd17dd..be04c117fe80 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Miscellaneous driver configuration # diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 39ca31b4de46..ac92725458b5 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -69,7 +69,6 @@ struct appledisplay { struct delayed_work work; int button_pressed; - spinlock_t lock; struct mutex sysfslock; /* concurrent read and write */ }; @@ -79,7 +78,6 @@ static void appledisplay_complete(struct urb *urb) { struct appledisplay *pdata = urb->context; struct device *dev = &pdata->udev->dev; - unsigned long flags; int status = urb->status; int retval; @@ -105,8 +103,6 @@ static void appledisplay_complete(struct urb *urb) goto exit; } - spin_lock_irqsave(&pdata->lock, flags); - switch(pdata->urbdata[1]) { case ACD_BTN_BRIGHT_UP: case ACD_BTN_BRIGHT_DOWN: @@ -119,8 +115,6 @@ static void appledisplay_complete(struct urb *urb) break; } - spin_unlock_irqrestore(&pdata->lock, flags); - exit: retval = usb_submit_urb(pdata->urb, GFP_ATOMIC); if (retval) { @@ -229,7 +223,6 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->udev = udev; - spin_lock_init(&pdata->lock); INIT_DELAYED_WORK(&pdata->work, appledisplay_work); mutex_init(&pdata->sysfslock); @@ -261,6 +254,7 @@ static int appledisplay_probe(struct usb_interface *iface, usb_rcvintpipe(udev, int_in_endpointAddr), pdata->urbdata, ACD_URB_BUFFER_LEN, appledisplay_complete, pdata, 1); + pdata->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; if (usb_submit_urb(pdata->urb, GFP_KERNEL)) { retval = -EIO; dev_err(&iface->dev, "Submitting URB failed\n"); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 76c718ac8c78..257efacf3551 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -915,7 +915,6 @@ static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) int bytes_read = 0; int retry_on_empty = 1; int retry_on_timeout = 3; - int empty_packets = 0; read:{ int packet_bytes = 0; int retval = usb_bulk_msg(ftdi->udev, @@ -960,31 +959,6 @@ read:{ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", retval, packet_bytes, bytes_read, diag); return retval; - } else if (packet_bytes == 2) { - unsigned char s0 = ftdi->bulk_in_buffer[0]; - unsigned char s1 = ftdi->bulk_in_buffer[1]; - empty_packets += 1; - if (s0 == 0x31 && s1 == 0x60) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else if (s0 == 0x31 && s1 == 0x00) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } else if (packet_bytes == 1) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; } else { if (retry_on_empty-- > 0) { goto more; diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig index 36bc28c884ad..9b632ab24f03 100644 --- a/drivers/usb/misc/sisusbvga/Kconfig +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config USB_SISUSBVGA tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile index 6ed3a638261a..6551bce68ac5 100644 --- a/drivers/usb/misc/sisusbvga/Makefile +++ b/drivers/usb/misc/sisusbvga/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o -sisusbvga-y := sisusb.o sisusb_init.o sisusb_con.o +sisusbvga-y := sisusb.o +sisusbvga-$(CONFIG_USB_SISUSBVGA_CON) += sisusb_con.o sisusb_init.o diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 3198d0477cf8..9560fde621ee 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -53,7 +53,7 @@ #include "sisusb.h" #include "sisusb_init.h" -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON #include <linux/font.h> #endif @@ -61,7 +61,7 @@ /* Forward declarations / clean-up routines */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON static int sisusb_first_vc; static int sisusb_last_vc; module_param_named(first, sisusb_first_vc, int, 0); @@ -1198,7 +1198,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, /* High level: Gfx (indexed) register access */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data) { return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); @@ -1272,7 +1272,7 @@ int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, /* Write/read video ram */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data) { return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data); @@ -2255,7 +2255,7 @@ static int sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen) } -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Set up default text mode: * - Set text mode (0x03) @@ -2448,7 +2448,7 @@ void sisusb_delete(struct kref *kref) sisusb->sisusb_dev = NULL; sisusb_free_buffers(sisusb); sisusb_free_urbs(sisusb); -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON kfree(sisusb->SiS_Pr); #endif kfree(sisusb); @@ -2844,7 +2844,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, case SUCMD_HANDLETEXTMODE: retval = 0; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Gfx core must be initialized, SiS_Pr must exist */ if (!sisusb->gfxinit || !sisusb->SiS_Pr) return -ENODEV; @@ -2860,7 +2860,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, #endif break; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON case SUCMD_SETMODE: /* Gfx core must be initialized, SiS_Pr must exist */ if (!sisusb->gfxinit || !sisusb->SiS_Pr) @@ -2944,7 +2944,7 @@ static long sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) x.sisusb_vramsize = sisusb->vramsize; x.sisusb_minor = sisusb->minor; x.sisusb_fbdevactive = 0; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON x.sisusb_conactive = sisusb->haveconsole ? 1 : 0; #else x.sisusb_conactive = 0; @@ -2975,7 +2975,7 @@ err_out: return retval; } -#ifdef SISUSB_NEW_CONFIG_COMPAT +#ifdef CONFIG_COMPAT static long sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { @@ -2998,7 +2998,7 @@ static const struct file_operations usb_sisusb_fops = { .read = sisusb_read, .write = sisusb_write, .llseek = sisusb_lseek, -#ifdef SISUSB_NEW_CONFIG_COMPAT +#ifdef CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif .unlocked_ioctl = sisusb_ioctl @@ -3091,7 +3091,7 @@ static int sisusb_probe(struct usb_interface *intf, dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Allocate our SiS_Pr */ sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL); if (!sisusb->SiS_Pr) { @@ -3112,7 +3112,7 @@ static int sisusb_probe(struct usb_interface *intf, if (dev->speed == USB_SPEED_HIGH || dev->speed >= USB_SPEED_SUPER) { int initscreen = 1; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON if (sisusb_first_vc > 0 && sisusb_last_vc > 0 && sisusb_first_vc <= sisusb_last_vc && sisusb_last_vc <= MAX_NR_CONSOLES) @@ -3134,7 +3134,7 @@ static int sisusb_probe(struct usb_interface *intf, dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc); #endif @@ -3160,7 +3160,7 @@ static void sisusb_disconnect(struct usb_interface *intf) if (!sisusb) return; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_console_exit(sisusb); #endif @@ -3210,7 +3210,7 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_init_concode(); #endif diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 20f03ad0ea16..8a5e6bb07d05 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -38,17 +38,8 @@ #ifndef _SISUSB_H_ #define _SISUSB_H_ -#ifdef CONFIG_COMPAT -#define SISUSB_NEW_CONFIG_COMPAT -#endif - #include <linux/mutex.h> -/* For older kernels, support for text consoles is by default - * off. To enable text console support, change the following: - */ -/* #define CONFIG_USB_SISUSBVGA_CON */ - /* Version Information */ #define SISUSB_VERSION 0 @@ -57,10 +48,6 @@ /* Include console and mode switching code? */ -#ifdef CONFIG_USB_SISUSBVGA_CON -#define INCL_SISUSB_CON 1 -#endif - #include <linux/console.h> #include <linux/vt_kern.h> #include "sisusb_struct.h" @@ -139,7 +126,7 @@ struct sisusb_usb_data { unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON struct SiS_Private *SiS_Pr; unsigned long scrbuf; unsigned int scrbuf_size; diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index c4f017e1d17a..cd0155310fea 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -70,13 +70,6 @@ #include "sisusb.h" #include "sisusb_init.h" -#ifdef INCL_SISUSB_CON - -#define sisusbcon_writew(val, addr) (*(addr) = (val)) -#define sisusbcon_readw(addr) (*(addr)) -#define sisusbcon_memmovew(d, s, c) memmove(d, s, c) -#define sisusbcon_memcpyw(d, s, c) memcpy(d, s, c) - /* vc_data -> sisusb conversion table */ static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES]; @@ -86,9 +79,7 @@ static const struct consw sisusb_con; static inline void sisusbcon_memsetw(u16 *s, u16 c, unsigned int count) { - count /= 2; - while (count--) - sisusbcon_writew(c, s++); + memset16(s, c, count / 2); } static inline void @@ -346,25 +337,30 @@ sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count) */ while (count--) { - u16 a = sisusbcon_readw(p); - - a = ((a) & 0x88ff) | - (((a) & 0x7000) >> 4) | - (((a) & 0x0700) << 4); + u16 a = *p; - sisusbcon_writew(a, p++); + *p++ = ((a) & 0x88ff) | + (((a) & 0x7000) >> 4) | + (((a) & 0x0700) << 4); } } -#define SISUSB_VADDR(x,y) \ - ((u16 *)c->vc_origin + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) +static inline void *sisusb_vaddr(const struct sisusb_usb_data *sisusb, + const struct vc_data *c, unsigned int x, unsigned int y) +{ + return (u16 *)c->vc_origin + y * sisusb->sisusb_num_columns + x; +} + +static inline unsigned long sisusb_haddr(const struct sisusb_usb_data *sisusb, + const struct vc_data *c, unsigned int x, unsigned int y) +{ + unsigned long offset = c->vc_origin - sisusb->scrbuf; -#define SISUSB_HADDR(x,y) \ - ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) + /* 2 bytes per each character */ + offset += 2 * (y * sisusb->sisusb_num_columns + x); + + return sisusb->vrambase + offset; +} /* Interface routine */ static void @@ -382,9 +378,8 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; } - - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), 2); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), 2); mutex_unlock(&sisusb->lock); } @@ -395,8 +390,6 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, int count, int y, int x) { struct sisusb_usb_data *sisusb; - u16 *dest; - int i; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) @@ -408,18 +401,15 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, * because the vt does this AFTER calling us. */ - dest = SISUSB_VADDR(x, y); - - for (i = count; i > 0; i--) - sisusbcon_writew(sisusbcon_readw(s++), dest++); + memcpy(sisusb_vaddr(sisusb, c, x, y), s, count * 2); if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; } - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), count * 2); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), count * 2); mutex_unlock(&sisusb->lock); } @@ -446,7 +436,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) * this AFTER calling us. */ - dest = SISUSB_VADDR(x, y); + dest = sisusb_vaddr(sisusb, c, x, y); cols = sisusb->sisusb_num_columns; @@ -472,8 +462,8 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) length = ((height * cols) - x - (cols - width - x)) * 2; - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), length); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), length); mutex_unlock(&sisusb->lock); } @@ -517,12 +507,10 @@ sisusbcon_switch(struct vc_data *c) (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); /* Restore the screen contents */ - sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, - length); + memcpy((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, length); - sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, - (long)SISUSB_HADDR(0, 0), - length); + sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_haddr(sisusb, c, 0, 0), length); mutex_unlock(&sisusb->lock); @@ -556,8 +544,7 @@ sisusbcon_save_screen(struct vc_data *c) (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); /* Save the screen contents to vc's private buffer */ - sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, - length); + memcpy((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, length); mutex_unlock(&sisusb->lock); } @@ -628,10 +615,8 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) sisusbcon_memsetw((u16 *)c->vc_origin, c->vc_video_erase_char, c->vc_screenbuf_size); - sisusb_copy_memory(sisusb, - (unsigned char *)c->vc_origin, - (u32)(sisusb->vrambase + - (c->vc_origin - sisusb->scrbuf)), + sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); sisusb->con_blanked = 1; ret = 1; @@ -796,24 +781,24 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, switch (dir) { case SM_UP: - sisusbcon_memmovew(SISUSB_VADDR(0, t), - SISUSB_VADDR(0, t + lines), + memmove(sisusb_vaddr(sisusb, c, 0, t), + sisusb_vaddr(sisusb, c, 0, t + lines), (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr, - lines * cols * 2); + sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, b - lines), + eattr, lines * cols * 2); break; case SM_DOWN: - sisusbcon_memmovew(SISUSB_VADDR(0, t + lines), - SISUSB_VADDR(0, t), + memmove(sisusb_vaddr(sisusb, c, 0, t + lines), + sisusb_vaddr(sisusb, c, 0, t), (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr, + sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, t), eattr, lines * cols * 2); break; } - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (long)SISUSB_HADDR(0, t), length); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, 0, t), + sisusb_haddr(sisusb, c, 0, t), length); mutex_unlock(&sisusb->lock); @@ -830,7 +815,6 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, int copyall = 0; unsigned long oldorigin; unsigned int delta = lines * c->vc_size_row; - u32 originoffset; /* Returning != 0 means we have done the scrolling successfully. * Returning 0 makes vt do the scrolling on its own. @@ -874,7 +858,7 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, if (c->vc_scr_end + delta >= sisusb->scrbuf + sisusb->scrbuf_size) { - sisusbcon_memcpyw((u16 *)sisusb->scrbuf, + memcpy((u16 *)sisusb->scrbuf, (u16 *)(oldorigin + delta), c->vc_screenbuf_size - delta); c->vc_origin = sisusb->scrbuf; @@ -892,12 +876,10 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, case SM_DOWN: if (oldorigin - delta < sisusb->scrbuf) { - sisusbcon_memmovew((u16 *)(sisusb->scrbuf + - sisusb->scrbuf_size - - c->vc_screenbuf_size + - delta), - (u16 *)oldorigin, - c->vc_screenbuf_size - delta); + memmove((void *)sisusb->scrbuf + sisusb->scrbuf_size - + c->vc_screenbuf_size + delta, + (u16 *)oldorigin, + c->vc_screenbuf_size - delta); c->vc_origin = sisusb->scrbuf + sisusb->scrbuf_size - c->vc_screenbuf_size; @@ -913,23 +895,21 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, break; } - originoffset = (u32)(c->vc_origin - sisusb->scrbuf); - if (copyall) sisusb_copy_memory(sisusb, (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), + sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); else if (dir == SM_UP) sisusb_copy_memory(sisusb, (char *)c->vc_origin + c->vc_screenbuf_size - delta, - (u32)sisusb->vrambase + originoffset + + sisusb_haddr(sisusb, c, 0, 0) + c->vc_screenbuf_size - delta, delta); else sisusb_copy_memory(sisusb, (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), + sisusb_haddr(sisusb, c, 0, 0), delta); c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; @@ -1534,8 +1514,3 @@ void __init sisusb_init_concode(void) for (i = 0; i < MAX_NR_CONSOLES; i++) mysisusbs[i] = NULL; } - -#endif /* INCL_CON */ - - - diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 6a30e8bd9221..66f6ab5acd97 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -44,9 +44,6 @@ #include <linux/spinlock.h> #include "sisusb.h" - -#ifdef INCL_SISUSB_CON - #include "sisusb_init.h" /*********************************************/ @@ -955,5 +952,3 @@ int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) return SiSUSBSetMode(SiS_Pr, ModeNo); } - -#endif /* INCL_SISUSB_CON */ diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index a6efb9a72939..04684849d683 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -337,10 +337,12 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, struct device *dev = hub->dev; struct device_node *np = dev->of_node; int len, err, i; - u32 property_u32 = 0; + u32 port, property_u32 = 0; const u32 *cproperty_u32; const char *cproperty_char; char str[USB251XB_STRING_BUFSIZE / 2]; + struct property *prop; + const __be32 *p; if (!np) { dev_err(dev, "failed to get ofdata\n"); @@ -539,6 +541,16 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, (wchar_t *)hub->serial, USB251XB_STRING_BUFSIZE); + /* + * The datasheet documents the register as 'Port Swap' but in real the + * register controls the USB DP/DM signal swapping for each port. + */ + hub->port_swap = USB251XB_DEF_PORT_SWAP; + of_property_for_each_u32(np, "swap-dx-lanes", prop, p, port) { + if (port <= data->port_cnt) + hub->port_swap |= BIT(port); + } + /* The following parameters are currently not exposed to devicetree, but * may be as soon as needed. */ @@ -546,7 +558,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->boost_up = USB251XB_DEF_BOOST_UP; hub->boost_57 = USB251XB_DEF_BOOST_57; hub->boost_14 = USB251XB_DEF_BOOST_14; - hub->port_swap = USB251XB_DEF_PORT_SWAP; hub->port_map12 = USB251XB_DEF_PORT_MAP_12; hub->port_map34 = USB251XB_DEF_PORT_MAP_34; hub->port_map56 = USB251XB_DEF_PORT_MAP_56; @@ -601,7 +612,7 @@ static int usb251xb_probe(struct usb251xb *hub) dev); int err; - if (np) { + if (np && of_id) { err = usb251xb_get_ofdata(hub, (struct usb251xb_data *)of_id->data); if (err) { diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index f723f7b8c9ac..d5141aa79dd4 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -355,11 +355,8 @@ static int usb3503_platform_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int usb3503_i2c_suspend(struct device *dev) +static int usb3503_suspend(struct usb3503 *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb3503 *hub = i2c_get_clientdata(client); - usb3503_switch_mode(hub, USB3503_MODE_STANDBY); if (hub->clk) @@ -368,11 +365,8 @@ static int usb3503_i2c_suspend(struct device *dev) return 0; } -static int usb3503_i2c_resume(struct device *dev) +static int usb3503_resume(struct usb3503 *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb3503 *hub = i2c_get_clientdata(client); - if (hub->clk) clk_prepare_enable(hub->clk); @@ -380,11 +374,38 @@ static int usb3503_i2c_resume(struct device *dev) return 0; } + +static int usb3503_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + return usb3503_suspend(i2c_get_clientdata(client)); +} + +static int usb3503_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + return usb3503_resume(i2c_get_clientdata(client)); +} + +static int usb3503_platform_suspend(struct device *dev) +{ + return usb3503_suspend(dev_get_drvdata(dev)); +} + +static int usb3503_platform_resume(struct device *dev) +{ + return usb3503_resume(dev_get_drvdata(dev)); +} #endif static SIMPLE_DEV_PM_OPS(usb3503_i2c_pm_ops, usb3503_i2c_suspend, usb3503_i2c_resume); +static SIMPLE_DEV_PM_OPS(usb3503_platform_pm_ops, usb3503_platform_suspend, + usb3503_platform_resume); + static const struct i2c_device_id usb3503_id[] = { { USB3503_I2C_NAME, 0 }, { } @@ -415,6 +436,7 @@ static struct platform_driver usb3503_platform_driver = { .driver = { .name = USB3503_I2C_NAME, .of_match_table = of_match_ptr(usb3503_of_match), + .pm = &usb3503_platform_pm_ops, }, .probe = usb3503_platform_probe, .remove = usb3503_platform_remove, diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index c7f82310e73e..98ada1a3425c 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -347,6 +347,14 @@ static unsigned get_maxpacket(struct usb_device *udev, int pipe) return le16_to_cpup(&ep->desc.wMaxPacketSize); } +static int ss_isoc_get_packet_num(struct usb_device *udev, int pipe) +{ + struct usb_host_endpoint *ep = usb_pipe_endpoint(udev, pipe); + + return USB_SS_MULT(ep->ss_ep_comp.bmAttributes) + * (1 + ep->ss_ep_comp.bMaxBurst); +} + static void simple_fill_buf(struct urb *urb) { unsigned i; @@ -1976,8 +1984,13 @@ static struct urb *iso_alloc_urb( if (bytes < 0 || !desc) return NULL; + maxp = usb_endpoint_maxp(desc); - maxp *= usb_endpoint_maxp_mult(desc); + if (udev->speed >= USB_SPEED_SUPER) + maxp *= ss_isoc_get_packet_num(udev, pipe); + else + maxp *= usb_endpoint_maxp_mult(desc); + packets = DIV_ROUND_UP(bytes, maxp); urb = usb_alloc_urb(packets, GFP_KERNEL); @@ -2065,17 +2078,24 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, packets *= param->iterations; if (context.is_iso) { + int transaction_num; + + if (udev->speed >= USB_SPEED_SUPER) + transaction_num = ss_isoc_get_packet_num(udev, pipe); + else + transaction_num = usb_endpoint_maxp_mult(desc); + dev_info(&dev->intf->dev, "iso period %d %sframes, wMaxPacket %d, transactions: %d\n", 1 << (desc->bInterval - 1), - (udev->speed == USB_SPEED_HIGH) ? "micro" : "", + (udev->speed >= USB_SPEED_HIGH) ? "micro" : "", usb_endpoint_maxp(desc), - usb_endpoint_maxp_mult(desc)); + transaction_num); dev_info(&dev->intf->dev, "total %lu msec (%lu packets)\n", (packets * (1 << (desc->bInterval - 1))) - / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1), + / ((udev->speed >= USB_SPEED_HIGH) ? 8 : 1), packets); } diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 6d9fd5f64903..7b306aa22d25 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -314,6 +314,7 @@ static void yurex_disconnect(struct usb_interface *interface) usb_deregister_dev(interface, &yurex_class); /* prevent more I/O from starting */ + usb_poison_urb(dev->urb); mutex_lock(&dev->io_mutex); dev->interface = NULL; mutex_unlock(&dev->io_mutex); diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index 5c6ffa2a612e..48f1b2dadb24 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Monitor configuration # diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig index 40bbf1f53337..928c2cd6fc00 100644 --- a/drivers/usb/mtu3/Kconfig +++ b/drivers/usb/mtu3/Kconfig @@ -1,9 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# # For MTK USB3.0 IP config USB_MTU3 tristate "MediaTek USB3 Dual Role controller" depends on USB || USB_GADGET depends on ARCH_MEDIATEK || COMPILE_TEST + depends on EXTCON || !EXTCON select USB_XHCI_MTK if USB_SUPPORT && USB_XHCI_HCD help Say Y or M here if your system runs on MediaTek SoCs with diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index ae70b9bfd797..4fee200795a5 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -180,7 +180,7 @@ static void mtu3_intr_enable(struct mtu3 *mtu) mtu3_writel(mbase, U3D_LV1IESR, value); /* Enable U2 common USB interrupts */ - value = SUSPEND_INTR | RESUME_INTR | RESET_INTR | LPM_RESUME_INTR; + value = SUSPEND_INTR | RESUME_INTR | RESET_INTR; mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value); if (mtu->is_u3_ip) { @@ -484,7 +484,7 @@ void mtu3_ep0_setup(struct mtu3 *mtu) mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); /* Enable EP0 interrupt */ - mtu3_writel(mtu->mac_base, U3D_EPIESR, EP0ISR); + mtu3_writel(mtu->mac_base, U3D_EPIESR, EP0ISR | SETUPENDISR); } static int mtu3_mem_alloc(struct mtu3 *mtu) @@ -578,12 +578,16 @@ static void mtu3_regs_init(struct mtu3 *mtu) if (mtu->is_u3_ip) { /* disable LGO_U1/U2 by default */ mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL, - SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE | SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE); + /* enable accept LGO_U1/U2 link command from host */ + mtu3_setbits(mbase, U3D_LINK_POWER_CONTROL, + SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE); /* device responses to u3_exit from host automatically */ mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN); /* automatically build U2 link when U3 detect fail */ mtu3_setbits(mbase, U3D_USB2_TEST_MODE, U2U3_AUTO_SWITCH); + /* auto clear SOFT_CONN when clear USB3_EN if work as HS */ + mtu3_setbits(mbase, U3D_U3U2_SWITCH_CTRL, SOFTCON_CLR_AUTO_EN); } mtu3_set_speed(mtu); @@ -592,10 +596,10 @@ static void mtu3_regs_init(struct mtu3 *mtu) mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK); /* U2/U3 detected by HW */ mtu3_writel(mbase, U3D_DEVICE_CONF, 0); - /* enable QMU 16B checksum */ - mtu3_setbits(mbase, U3D_QCR0, QMU_CS16B_EN); /* vbus detected by HW */ mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON); + /* enable automatical HWRW from L1 */ + mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE); } static irqreturn_t mtu3_link_isr(struct mtu3 *mtu) @@ -708,12 +712,6 @@ static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu) if (u2comm & RESET_INTR) mtu3_gadget_reset(mtu); - if (u2comm & LPM_RESUME_INTR) { - if (!(mtu3_readl(mbase, U3D_POWER_MANAGEMENT) & LPM_HRWE)) - mtu3_setbits(mbase, U3D_USB20_MISC_CONTROL, - LPM_U3_ACK_EN); - } - return IRQ_HANDLED; } diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 25216e79cd6e..7cb7ac980446 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -336,9 +336,9 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu, lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); if (set) - lpc |= SW_U1_ACCEPT_ENABLE; + lpc |= SW_U1_REQUEST_ENABLE; else - lpc &= ~SW_U1_ACCEPT_ENABLE; + lpc &= ~SW_U1_REQUEST_ENABLE; mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); mtu->u1_enable = !!set; @@ -351,9 +351,9 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu, lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); if (set) - lpc |= SW_U2_ACCEPT_ENABLE; + lpc |= SW_U2_REQUEST_ENABLE; else - lpc &= ~SW_U2_ACCEPT_ENABLE; + lpc &= ~SW_U2_REQUEST_ENABLE; mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); mtu->u2_enable = !!set; @@ -692,9 +692,13 @@ irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu) mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */ /* only handle ep0's */ - if (!(int_status & EP0ISR)) + if (!(int_status & (EP0ISR | SETUPENDISR))) return IRQ_NONE; + /* abort current SETUP, and process new one */ + if (int_status & SETUPENDISR) + mtu->ep0_state = MU3D_EP0_STATE_SETUP; + csr = mtu3_readl(mbase, U3D_EP0CSR); dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr); diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index a45bb253939f..1d65b7476f23 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h @@ -104,6 +104,7 @@ /* U3D_EPISR */ #define EPRISR(x) (BIT(16) << (x)) +#define SETUPENDISR BIT(16) #define EPTISR(x) (BIT(0) << (x)) #define EP0ISR BIT(0) @@ -267,6 +268,8 @@ #define U3D_LTSSM_INTR_ENABLE (SSUSB_USB3_MAC_CSR_BASE + 0x013C) #define U3D_LTSSM_INTR (SSUSB_USB3_MAC_CSR_BASE + 0x0140) +#define U3D_U3U2_SWITCH_CTRL (SSUSB_USB3_MAC_CSR_BASE + 0x0170) + /*---------------- SSUSB_USB3_MAC_CSR FIELD DEFINITION ----------------*/ /* U3D_LTSSM_CTRL */ @@ -301,6 +304,9 @@ #define SS_DISABLE_INTR BIT(1) #define SS_INACTIVE_INTR BIT(0) +/* U3D_U3U2_SWITCH_CTRL */ +#define SOFTCON_CLR_AUTO_EN BIT(0) + /*---------------- SSUSB_USB3_SYS_CSR REGISTER DEFINITION ----------------*/ #define U3D_LINK_UX_INACT_TIMER (SSUSB_USB3_SYS_CSR_BASE + 0x020C) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 46551f6d16fd..e086630e41a9 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -200,6 +200,14 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb) mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); udelay(1); mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); + + /* + * device ip may be powered on in firmware/BROM stage before entering + * kernel stage; + * power down device ip, otherwise ip-sleep will fail when working as + * host only mode + */ + mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); } /* ignore the error if the clock does not exist */ diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c index ff62ba232177..09f19f70fe8f 100644 --- a/drivers/usb/mtu3/mtu3_qmu.c +++ b/drivers/usb/mtu3/mtu3_qmu.c @@ -154,27 +154,6 @@ void mtu3_gpd_ring_free(struct mtu3_ep *mep) memset(ring, 0, sizeof(*ring)); } -/* - * calculate check sum of a gpd or bd - * add "noinline" and "mb" to prevent wrong calculation - */ -static noinline u8 qmu_calc_checksum(u8 *data) -{ - u8 chksum = 0; - int i; - - data[1] = 0x0; /* set checksum to 0 */ - - mb(); /* ensure the gpd/bd is really up-to-date */ - for (i = 0; i < QMU_CHECKSUM_LEN; i++) - chksum += data[i]; - - /* Default: HWO=1, @flag[bit0] */ - chksum += 1; - - return 0xFF - chksum; -} - void mtu3_qmu_resume(struct mtu3_ep *mep) { struct mtu3 *mtu = mep->mtu; @@ -260,7 +239,6 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq) if (req->zero) gpd->ext_flag |= GPD_EXT_FLAG_ZLP; - gpd->chksum = qmu_calc_checksum((u8 *)gpd); gpd->flag |= GPD_FLAGS_HWO; mreq->gpd = gpd; @@ -295,7 +273,6 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq) gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma)); ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma)); gpd->rx_ext_addr = cpu_to_le16(ext_addr); - gpd->chksum = qmu_calc_checksum((u8 *)gpd); gpd->flag |= GPD_FLAGS_HWO; mreq->gpd = gpd; @@ -323,7 +300,6 @@ int mtu3_qmu_start(struct mtu3_ep *mep) /* set QMU start address */ write_txq_start_addr(mbase, epnum, ring->dma); mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_DMAREQEN); - mtu3_setbits(mbase, U3D_QCR0, QMU_TX_CS_EN(epnum)); /* send zero length packet according to ZLP flag in GPD */ mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum)); mtu3_writel(mbase, U3D_TQERRIESR0, @@ -338,7 +314,6 @@ int mtu3_qmu_start(struct mtu3_ep *mep) } else { write_rxq_start_addr(mbase, epnum, ring->dma); mtu3_setbits(mbase, MU3D_EP_RXCR0(epnum), RX_DMAREQEN); - mtu3_setbits(mbase, U3D_QCR0, QMU_RX_CS_EN(epnum)); /* don't expect ZLP */ mtu3_clrbits(mbase, U3D_QCR3, QMU_RX_ZLP(epnum)); /* move to next GPD when receive ZLP */ @@ -427,7 +402,7 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum) return; } - dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, mreq); + dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, req); mtu3_clrbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN); @@ -441,7 +416,6 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum) /* by pass the current GDP */ gpd_current->flag |= GPD_FLAGS_BPS; - gpd_current->chksum = qmu_calc_checksum((u8 *)gpd_current); gpd_current->flag |= GPD_FLAGS_HWO; /*enable DMAREQEN, switch back to QMU mode */ diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index ad08895e78f9..f742fddc5e2c 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Dual Role (OTG-ready) Controller Drivers # for silicon based on Mentor Graphics INVENTRA designs @@ -111,9 +112,9 @@ config USB_MUSB_UX500 config USB_MUSB_JZ4740 tristate "JZ4740" depends on NOP_USB_XCEIV - depends on MACH_JZ4740 || COMPILE_TEST + depends on MIPS || COMPILE_TEST depends on USB_MUSB_GADGET - depends on USB_OTG_BLACKLIST_HUB + depends on USB=n || USB_OTG_BLACKLIST_HUB config USB_MUSB_AM335X_CHILD tristate diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index 04d8b2bc205a..a60627bf7be3 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/usb/usb_phy_generic.h> @@ -188,11 +189,20 @@ static int jz4740_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id jz4740_musb_of_match[] = { + { .compatible = "ingenic,jz4740-musb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4740_musb_of_match); +#endif + static struct platform_driver jz4740_driver = { .probe = jz4740_probe, .remove = jz4740_remove, .driver = { .name = "musb-jz4740", + .of_match_table = of_match_ptr(jz4740_musb_of_match), }, }; diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 23a0df79ef21..403eb97915f8 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -181,9 +181,11 @@ static void dsps_musb_enable(struct musb *musb) musb_writel(reg_base, wrp->epintr_set, epmask); musb_writel(reg_base, wrp->coreintr_set, coremask); - /* start polling for ID change in dual-role idle mode */ - if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && - musb->port_mode == MUSB_OTG) + /* + * start polling for runtime PM active and idle, + * and for ID change in dual-role idle mode. + */ + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) dsps_mod_timer(glue, -1); } @@ -227,8 +229,13 @@ static int dsps_check_status(struct musb *musb, void *unused) switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_VRISE: - dsps_mod_timer_optional(glue); - break; + if (musb->port_mode == MUSB_HOST) { + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; + dsps_mod_timer_optional(glue); + break; + } + /* fall through */ + case OTG_STATE_A_WAIT_BCON: /* keep VBUS on for host-only mode */ if (musb->port_mode == MUSB_HOST) { @@ -249,6 +256,10 @@ static int dsps_check_status(struct musb *musb, void *unused) musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } + + if (musb->port_mode == MUSB_PERIPHERAL) + skip_session = 1; + if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) musb_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index eae8b1b1b45b..ffe462a657b1 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -452,13 +452,10 @@ void musb_g_tx(struct musb *musb, u8 epnum) } if (request) { - u8 is_dma = 0; - bool short_packet = false; trace_musb_req_tx(req); if (dma && (csr & MUSB_TXCSR_DMAENAB)) { - is_dma = 1; csr |= MUSB_TXCSR_P_WZC_BITS; csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET); @@ -476,16 +473,8 @@ void musb_g_tx(struct musb *musb, u8 epnum) */ if ((request->zero && request->length) && (request->length % musb_ep->packet_sz == 0) - && (request->actual == request->length)) - short_packet = true; + && (request->actual == request->length)) { - if ((musb_dma_inventra(musb) || musb_dma_ux500(musb)) && - (is_dma && (!dma->desired_mode || - (request->actual & - (musb_ep->packet_sz - 1))))) - short_packet = true; - - if (short_packet) { /* * On DMA completion, FIFO may not be * available yet... diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index b59ce9ad14ce..eb308ec35c66 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -378,7 +378,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, qh = first_qh(head); break; } - /* else: fall through */ + /* fall through */ case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: @@ -1283,7 +1283,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); } - return; + return; } done: diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index a688f7f87829..5fc6825745f2 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -346,12 +346,10 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) channel->status = MUSB_DMA_STATUS_FREE; /* completed */ - if ((devctl & MUSB_DEVCTL_HM) - && (musb_channel->transmit) - && ((channel->desired_mode == 0) - || (channel->actual_len & - (musb_channel->max_packet_sz - 1))) - ) { + if (musb_channel->transmit && + (!channel->desired_mode || + (channel->actual_len % + musb_channel->max_packet_sz))) { u8 epnum = musb_channel->epnum; int offset = musb->io.ep_offset(epnum, MUSB_TXCSR); @@ -363,11 +361,14 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) */ musb_ep_select(mbase, epnum); txcsr = musb_readw(mbase, offset); - txcsr &= ~(MUSB_TXCSR_DMAENAB + if (channel->desired_mode == 1) { + txcsr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_AUTOSET); - musb_writew(mbase, offset, txcsr); - /* Send out the packet */ - txcsr &= ~MUSB_TXCSR_DMAMODE; + musb_writew(mbase, offset, txcsr); + /* Send out the packet */ + txcsr &= ~MUSB_TXCSR_DMAMODE; + txcsr |= MUSB_TXCSR_DMAENAB; + } txcsr |= MUSB_TXCSR_TXPKTRDY; musb_writew(mbase, offset, txcsr); } diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index d7312eed6088..8c509b060c09 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Physical Layer USB driver configuration # @@ -21,7 +22,7 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM + depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM=y && PM depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 27bdb7222527..f5f0568d8533 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -61,9 +61,6 @@ static int am335x_phy_probe(struct platform_device *pdev) if (ret) return ret; - ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy); - if (ret) - return ret; am_phy->usb_phy_gen.phy.init = am335x_init; am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown; @@ -82,7 +79,7 @@ static int am335x_phy_probe(struct platform_device *pdev) device_set_wakeup_enable(dev, false); phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); - return 0; + return usb_add_phy_dev(&am_phy->usb_phy_gen.phy); } static int am335x_phy_remove(struct platform_device *pdev) diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 183550b63faa..dade34d70419 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -400,7 +400,7 @@ static int twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); - cancel_delayed_work(&twl->get_status_work); + cancel_delayed_work_sync(&twl->get_status_work); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index a3e1290d682d..249fbee97f3f 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -540,6 +540,10 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) */ static const struct of_device_id usbhs_of_match[] = { { + .compatible = "renesas,usbhs-r8a774c0", + .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, + }, + { .compatible = "renesas,usbhs-r8a7790", .data = (void *)USBHS_TYPE_RCAR_GEN2, }, @@ -841,7 +845,7 @@ static int usbhs_remove(struct platform_device *pdev) return 0; } -static int usbhsc_suspend(struct device *dev) +static __maybe_unused int usbhsc_suspend(struct device *dev) { struct usbhs_priv *priv = dev_get_drvdata(dev); struct usbhs_mod *mod = usbhs_mod_get_current(priv); @@ -857,7 +861,7 @@ static int usbhsc_suspend(struct device *dev) return 0; } -static int usbhsc_resume(struct device *dev) +static __maybe_unused int usbhsc_resume(struct device *dev) { struct usbhs_priv *priv = dev_get_drvdata(dev); struct platform_device *pdev = usbhs_priv_to_pdev(priv); @@ -874,24 +878,7 @@ static int usbhsc_resume(struct device *dev) return 0; } -static int usbhsc_runtime_nop(struct device *dev) -{ - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * This driver re-initializes all registers after - * pm_runtime_get_sync() anyway so there is no need - * to save and restore registers here. - */ - return 0; -} - -static const struct dev_pm_ops usbhsc_pm_ops = { - .suspend = usbhsc_suspend, - .resume = usbhsc_resume, - .runtime_suspend = usbhsc_runtime_nop, - .runtime_resume = usbhsc_runtime_nop, -}; +static SIMPLE_DEV_PM_OPS(usbhsc_pm_ops, usbhsc_suspend, usbhsc_resume); static struct platform_driver renesas_usbhs_driver = { .driver = { diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 4e59c649db81..ddd3be48f948 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -340,7 +340,7 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, pipe = usbhsh_uep_to_pipe(uep); if (unlikely(!pipe)) { - dev_err(dev, "uep doens't have pipe\n"); + dev_err(dev, "uep doesn't have pipe\n"); } else if (1 == uep->counter--) { /* last user */ struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index aa3820448286..5e730e9b40ef 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -59,7 +59,7 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, if (enable) { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); /* The controller on R-Car Gen3 needs to wait up to 45 usec */ - udelay(45); + usleep_range(45, 90); } else { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0); } diff --git a/drivers/usb/renesas_usbhs/rza.c b/drivers/usb/renesas_usbhs/rza.c index 5b287257ec11..8c739bd24acd 100644 --- a/drivers/usb/renesas_usbhs/rza.c +++ b/drivers/usb/renesas_usbhs/rza.c @@ -35,7 +35,7 @@ static int usbhs_rza1_hardware_init(struct platform_device *pdev) /* Enable USB PLL (NOTE: ch0 controls both ch0 and ch1) */ usbhs_bset(priv, SYSCFG, UPLLE, UPLLE); - udelay(1000); + usleep_range(1000, 2000); usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM); return 0; diff --git a/drivers/usb/roles/Kconfig b/drivers/usb/roles/Kconfig index f5a5e6f79f1b..f8b31aa67526 100644 --- a/drivers/usb/roles/Kconfig +++ b/drivers/usb/roles/Kconfig @@ -1,3 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +config USB_ROLE_SWITCH + tristate "USB Role Switch Support" + help + USB Role Switch is a device that can select the USB role - host or + device - for a USB port (connector). In most cases dual-role capable + USB controller will also represent the switch, but on some platforms + multiplexer/demultiplexer switch is used to route the data lines on + the USB connector between separate USB host and device controllers. + + Say Y here if your USB connectors support both device and host roles. + To compile the driver as module, choose M here: the module will be + called roles.ko. + if USB_ROLE_SWITCH config USB_ROLES_INTEL_XHCI diff --git a/drivers/usb/roles/Makefile b/drivers/usb/roles/Makefile index e44b179ba275..757a7d2797eb 100644 --- a/drivers/usb/roles/Makefile +++ b/drivers/usb/roles/Makefile @@ -1 +1,5 @@ -obj-$(CONFIG_USB_ROLES_INTEL_XHCI) += intel-xhci-usb-role-switch.o +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_USB_ROLE_SWITCH) += roles.o +roles-y := class.o +obj-$(CONFIG_USB_ROLES_INTEL_XHCI) += intel-xhci-usb-role-switch.o diff --git a/drivers/usb/common/roles.c b/drivers/usb/roles/class.c index 99116af07f1d..f45d8df5cfb8 100644 --- a/drivers/usb/common/roles.c +++ b/drivers/usb/roles/class.c @@ -8,6 +8,7 @@ */ #include <linux/usb/role.h> +#include <linux/property.h> #include <linux/device.h> #include <linux/module.h> #include <linux/mutex.h> @@ -84,7 +85,12 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw) } EXPORT_SYMBOL_GPL(usb_role_switch_get_role); -static int __switch_match(struct device *dev, const void *name) +static int switch_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} + +static int switch_name_match(struct device *dev, const void *name) { return !strcmp((const char *)name, dev_name(dev)); } @@ -94,8 +100,16 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, { struct device *dev; - dev = class_find_device(role_class, NULL, con->endpoint[ep], - __switch_match); + if (con->fwnode) { + if (!fwnode_property_present(con->fwnode, con->id)) + return NULL; + + dev = class_find_device(role_class, NULL, con->fwnode, + switch_fwnode_match); + } else { + dev = class_find_device(role_class, NULL, con->endpoint[ep], + switch_name_match); + } return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); } @@ -266,6 +280,7 @@ usb_role_switch_register(struct device *parent, sw->get = desc->get; sw->dev.parent = parent; + sw->dev.fwnode = desc->fwnode; sw->dev.class = role_class; sw->dev.type = &usb_role_dev_type; dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent)); diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 533f127c30ad..7d031911d04e 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Serial device configuration # diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index c0777a374a88..979bef9bfb6b 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -61,6 +61,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */ + { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */ { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ @@ -79,6 +80,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */ { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ + { USB_DEVICE(0x10C4, 0x8056) }, /* Lorenz Messtechnik devices */ { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ @@ -245,6 +247,7 @@ struct cp210x_serial_private { u8 gpio_input; #endif u8 partnum; + speed_t min_speed; speed_t max_speed; bool use_actual_rate; }; @@ -443,10 +446,10 @@ struct cp210x_pin_mode { #define CP210X_PIN_MODE_GPIO BIT(0) /* - * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes. - * Structure needs padding due to unused/unspecified bytes. + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes + * on a CP2105 chip. Structure needs padding due to unused/unspecified bytes. */ -struct cp210x_config { +struct cp210x_dual_port_config { __le16 gpio_mode; u8 __pad0[2]; __le16 reset_state; @@ -457,6 +460,19 @@ struct cp210x_config { u8 device_cfg; } __packed; +/* + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xd bytes + * on a CP2104 chip. Structure needs padding due to unused/unspecified bytes. + */ +struct cp210x_single_port_config { + __le16 gpio_mode; + u8 __pad0[2]; + __le16 reset_state; + u8 __pad1[4]; + __le16 suspend_state; + u8 device_cfg; +} __packed; + /* GPIO modes */ #define CP210X_SCI_GPIO_MODE_OFFSET 9 #define CP210X_SCI_GPIO_MODE_MASK GENMASK(11, 9) @@ -464,11 +480,19 @@ struct cp210x_config { #define CP210X_ECI_GPIO_MODE_OFFSET 2 #define CP210X_ECI_GPIO_MODE_MASK GENMASK(3, 2) +#define CP210X_GPIO_MODE_OFFSET 8 +#define CP210X_GPIO_MODE_MASK GENMASK(11, 8) + /* CP2105 port configuration values */ #define CP2105_GPIO0_TXLED_MODE BIT(0) #define CP2105_GPIO1_RXLED_MODE BIT(1) #define CP2105_GPIO1_RS485_MODE BIT(2) +/* CP2104 port configuration values */ +#define CP2104_GPIO0_TXLED_MODE BIT(0) +#define CP2104_GPIO1_RXLED_MODE BIT(1) +#define CP2104_GPIO2_RS485_MODE BIT(2) + /* CP2102N configuration array indices */ #define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2 #define CP210X_2NCONFIG_GPIO_MODE_IDX 581 @@ -1051,14 +1075,11 @@ static speed_t cp210x_get_an205_rate(speed_t baud) return cp210x_an205_table1[i].rate; } -static speed_t cp210x_get_actual_rate(struct usb_serial *serial, speed_t baud) +static speed_t cp210x_get_actual_rate(speed_t baud) { - struct cp210x_serial_private *priv = usb_get_serial_data(serial); unsigned int prescale = 1; unsigned int div; - baud = clamp(baud, 300u, priv->max_speed); - if (baud <= 365) prescale = 4; @@ -1101,20 +1122,18 @@ static void cp210x_change_speed(struct tty_struct *tty, struct cp210x_serial_private *priv = usb_get_serial_data(serial); u32 baud; - baud = tty->termios.c_ospeed; - /* * This maps the requested rate to the actual rate, a valid rate on * cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed]. * * NOTE: B0 is not implemented. */ + baud = clamp(tty->termios.c_ospeed, priv->min_speed, priv->max_speed); + if (priv->use_actual_rate) - baud = cp210x_get_actual_rate(serial, baud); + baud = cp210x_get_actual_rate(baud); else if (baud < 1000000) baud = cp210x_get_an205_rate(baud); - else if (baud > priv->max_speed) - baud = priv->max_speed; dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) { @@ -1353,8 +1372,13 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) if (priv->partnum == CP210X_PARTNUM_CP2105) req_type = REQTYPE_INTERFACE_TO_HOST; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + result = cp210x_read_vendor_block(serial, req_type, CP210X_READ_LATCH, &buf, sizeof(buf)); + usb_autopm_put_interface(serial->interface); if (result < 0) return result; @@ -1375,6 +1399,10 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) buf.mask = BIT(gpio); + result = usb_autopm_get_interface(serial->interface); + if (result) + goto out; + if (priv->partnum == CP210X_PARTNUM_CP2105) { result = cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE, @@ -1392,6 +1420,8 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) NULL, 0, USB_CTRL_SET_TIMEOUT); } + usb_autopm_put_interface(serial->interface); +out: if (result < 0) { dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n", result); @@ -1470,7 +1500,7 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); struct cp210x_pin_mode mode; - struct cp210x_config config; + struct cp210x_dual_port_config config; u8 intf_num = cp210x_interface_num(serial); u8 iface_config; int result; @@ -1529,6 +1559,56 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) return 0; } +static int cp2104_gpioconf_init(struct usb_serial *serial) +{ + struct cp210x_serial_private *priv = usb_get_serial_data(serial); + struct cp210x_single_port_config config; + u8 iface_config; + u8 gpio_latch; + int result; + u8 i; + + result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST, + CP210X_GET_PORTCONFIG, &config, + sizeof(config)); + if (result < 0) + return result; + + priv->gc.ngpio = 4; + + iface_config = config.device_cfg; + priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + gpio_latch = (u8)((le16_to_cpu(config.reset_state) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + + /* mark all pins which are not in GPIO mode */ + if (iface_config & CP2104_GPIO0_TXLED_MODE) /* GPIO 0 */ + priv->gpio_altfunc |= BIT(0); + if (iface_config & CP2104_GPIO1_RXLED_MODE) /* GPIO 1 */ + priv->gpio_altfunc |= BIT(1); + if (iface_config & CP2104_GPIO2_RS485_MODE) /* GPIO 2 */ + priv->gpio_altfunc |= BIT(2); + + /* + * Like CP2102N, CP2104 has also no strict input and output pin + * modes. + * Do the same input mode emulation as CP2102N. + */ + for (i = 0; i < priv->gc.ngpio; ++i) { + /* + * Set direction to "input" iff pin is open-drain and reset + * value is 1. + */ + if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i))) + priv->gpio_input |= BIT(i); + } + + return 0; +} + static int cp2102n_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); @@ -1574,12 +1654,6 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) if (config_version != 0x01) return -ENOTSUPP; - /* - * We only support 4 GPIOs even on the QFN28 package, because - * config locations of GPIOs 4-6 determined using reverse - * engineering revealed conflicting offsets with other - * documented functions. So we'll just play it safe for now. - */ priv->gc.ngpio = 4; /* @@ -1594,6 +1668,19 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) /* 0 indicates GPIO mode, 1 is alternate function */ priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f; + if (priv->partnum == CP210X_PARTNUM_CP2102N_QFN28) { + /* + * For the QFN28 package, GPIO4-6 are controlled by + * the low three bits of the mode/latch fields. + * Contrary to the document linked above, the bits for + * the SUSPEND pins are elsewhere. No alternate + * function is available for these pins. + */ + priv->gc.ngpio = 7; + gpio_latch |= (gpio_rst_latch & 7) << 4; + priv->gpio_pushpull |= (gpio_pushpull & 7) << 4; + } + /* * The CP2102N does not strictly has input and output pin modes, * it only knows open-drain and push-pull modes which is set at @@ -1620,6 +1707,9 @@ static int cp210x_gpio_init(struct usb_serial *serial) int result; switch (priv->partnum) { + case CP210X_PARTNUM_CP2104: + result = cp2104_gpioconf_init(serial); + break; case CP210X_PARTNUM_CP2105: result = cp2105_gpioconf_init(serial); break; @@ -1716,6 +1806,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); bool use_actual_rate = false; + speed_t min = 300; speed_t max; switch (priv->partnum) { @@ -1738,6 +1829,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) use_actual_rate = true; max = 2000000; /* ECI */ } else { + min = 2400; max = 921600; /* SCI */ } break; @@ -1752,6 +1844,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) break; } + priv->min_speed = min; priv->max_speed = max; priv->use_actual_rate = use_actual_rate; } diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 380933db34dd..2b39bda035c7 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -45,14 +45,17 @@ #define F81534_CONFIG1_REG (0x09 + F81534_UART_BASE_ADDRESS) #define F81534_DEF_CONF_ADDRESS_START 0x3000 -#define F81534_DEF_CONF_SIZE 8 +#define F81534_DEF_CONF_SIZE 12 #define F81534_CUSTOM_ADDRESS_START 0x2f00 #define F81534_CUSTOM_DATA_SIZE 0x10 #define F81534_CUSTOM_NO_CUSTOM_DATA 0xff #define F81534_CUSTOM_VALID_TOKEN 0xf0 #define F81534_CONF_OFFSET 1 -#define F81534_CONF_GPIO_OFFSET 4 +#define F81534_CONF_INIT_GPIO_OFFSET 4 +#define F81534_CONF_WORK_GPIO_OFFSET 8 +#define F81534_CONF_GPIO_SHUTDOWN 7 +#define F81534_CONF_GPIO_RS232 1 #define F81534_MAX_DATA_BLOCK 64 #define F81534_MAX_BUS_RETRY 20 @@ -1337,8 +1340,19 @@ static int f81534_set_port_output_pin(struct usb_serial_port *port) serial_priv = usb_get_serial_data(serial); port_priv = usb_get_serial_port_data(port); - idx = F81534_CONF_GPIO_OFFSET + port_priv->phy_num; + idx = F81534_CONF_INIT_GPIO_OFFSET + port_priv->phy_num; value = serial_priv->conf_data[idx]; + if (value >= F81534_CONF_GPIO_SHUTDOWN) { + /* + * Newer IC configure will make transceiver in shutdown mode on + * initial power on. We need enable it before using UARTs. + */ + idx = F81534_CONF_WORK_GPIO_OFFSET + port_priv->phy_num; + value = serial_priv->conf_data[idx]; + if (value >= F81534_CONF_GPIO_SHUTDOWN) + value = F81534_CONF_GPIO_RS232; + } + pins = &f81534_port_out_pins[port_priv->phy_num]; for (i = 0; i < ARRAY_SIZE(pins->pin); ++i) { diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 609198d9594c..1d8461ae2c34 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -609,6 +609,8 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLX_PLUS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NT_ORION_IO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2_PID) }, @@ -1025,6 +1027,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) }, { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) }, + /* EZPrototypes devices */ + { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) }, { } /* Terminating entry */ }; @@ -1130,7 +1134,7 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base) { unsigned short int divisor; /* divisor shifted 3 bits to the left */ - int divisor3 = base / 2 / baud; + int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); if ((divisor3 & 0x7) == 7) divisor3++; /* round x.7/8 up to x+1 */ divisor = divisor3 >> 3; @@ -1156,7 +1160,7 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base) static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; u32 divisor; /* divisor shifted 3 bits to the left */ - int divisor3 = base / 2 / baud; + int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); divisor = divisor3 >> 3; divisor |= (u32)divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ @@ -1179,7 +1183,7 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) int divisor3; /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ - divisor3 = base * 8 / (baud * 10); + divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud); divisor = divisor3 >> 3; divisor |= (u32)divfrac[divisor3 & 0x7] << 14; @@ -1783,6 +1787,10 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) int result; u16 val; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -1795,6 +1803,8 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) val, result); } + usb_autopm_put_interface(serial->interface); + return result; } @@ -1846,9 +1856,15 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) unsigned char *buf; int result; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + buf = kmalloc(1, GFP_KERNEL); - if (!buf) + if (!buf) { + usb_autopm_put_interface(serial->interface); return -ENOMEM; + } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -1863,6 +1879,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) } kfree(buf); + usb_autopm_put_interface(serial->interface); return result; } diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 975d02666c5a..5755f0df0025 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -567,7 +567,9 @@ /* * NovaTech product ids (FTDI_VID) */ -#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */ +#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */ +#define FTDI_NT_ORIONLX_PLUS_PID 0x7c91 /* OrionLX+ Substation Automation Platform */ +#define FTDI_NT_ORION_IO_PID 0x7c92 /* Orion I/O */ /* * Synapse Wireless product ids (FTDI_VID) @@ -1309,6 +1311,12 @@ #define IONICS_PLUGCOMPUTER_PID 0x0102 /* + * EZPrototypes (PID reseller) + */ +#define EZPROTOTYPES_VID 0x1c40 +#define HJELMSLUND_USB485_ISO_PID 0x0477 + +/* * Dresden Elektronik Sensor Terminal Board */ #define DE_VID 0x1cf1 /* Vendor ID */ diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h index 09e21e84fc4e..a68f1fb25b8a 100644 --- a/drivers/usb/serial/keyspan_usa26msg.h +++ b/drivers/usb/serial/keyspan_usa26msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa26msg.h diff --git a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h index dee454c4609a..a19f3fe5d98d 100644 --- a/drivers/usb/serial/keyspan_usa28msg.h +++ b/drivers/usb/serial/keyspan_usa28msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa28msg.h diff --git a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h index 163b2dea2ec5..8c3970fdd868 100644 --- a/drivers/usb/serial/keyspan_usa49msg.h +++ b/drivers/usb/serial/keyspan_usa49msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa49msg.h diff --git a/drivers/usb/serial/keyspan_usa67msg.h b/drivers/usb/serial/keyspan_usa67msg.h index 20fa3e2f7187..dcf502fdbb44 100644 --- a/drivers/usb/serial/keyspan_usa67msg.h +++ b/drivers/usb/serial/keyspan_usa67msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa67msg.h diff --git a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h index 86708ecd8735..c4ca0f631d20 100644 --- a/drivers/usb/serial/keyspan_usa90msg.h +++ b/drivers/usb/serial/keyspan_usa90msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa90msg.h diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index fc52ac75fbf6..18110225d506 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -366,8 +366,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, if (!urbtrack) return -ENOMEM; - kref_get(&mos_parport->ref_count); - urbtrack->mos_parport = mos_parport; urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urbtrack->urb) { kfree(urbtrack); @@ -388,6 +386,8 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, usb_sndctrlpipe(usbdev, 0), (unsigned char *)urbtrack->setup, NULL, 0, async_complete, urbtrack); + kref_get(&mos_parport->ref_count); + urbtrack->mos_parport = mos_parport; kref_init(&urbtrack->ref_count); INIT_LIST_HEAD(&urbtrack->urblist_entry); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 88828b4b8c44..a698d46ba773 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -94,6 +94,7 @@ /* The native mos7840/7820 component */ #define USB_VENDOR_ID_MOSCHIP 0x9710 #define MOSCHIP_DEVICE_ID_7840 0x7840 +#define MOSCHIP_DEVICE_ID_7843 0x7843 #define MOSCHIP_DEVICE_ID_7820 0x7820 #define MOSCHIP_DEVICE_ID_7810 0x7810 /* The native component can have its vendor/device id's overridden @@ -176,6 +177,7 @@ enum mos7840_flag { static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, + {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7843)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, @@ -298,15 +300,10 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg, val = val & 0x00ff; /* For the UART control registers, the application number need to be Or'ed */ - if (port->serial->num_ports == 4) { + if (port->serial->num_ports == 2 && port->port_number != 0) + val |= ((__u16)port->port_number + 2) << 8; + else val |= ((__u16)port->port_number + 1) << 8; - } else { - if (port->port_number == 0) { - val |= ((__u16)port->port_number + 1) << 8; - } else { - val |= ((__u16)port->port_number + 2) << 8; - } - } dev_dbg(&port->dev, "%s application number is %x\n", __func__, val); return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, val, reg, NULL, 0, @@ -332,15 +329,10 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, return -ENOMEM; /* Wval is same as application number */ - if (port->serial->num_ports == 4) { + if (port->serial->num_ports == 2 && port->port_number != 0) + Wval = ((__u16)port->port_number + 2) << 8; + else Wval = ((__u16)port->port_number + 1) << 8; - } else { - if (port->port_number == 0) { - Wval = ((__u16)port->port_number + 1) << 8; - } else { - Wval = ((__u16)port->port_number + 2) << 8; - } - } dev_dbg(&port->dev, "%s application number is %x\n", __func__, Wval); ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH, @@ -601,7 +593,7 @@ static void mos7840_interrupt_callback(struct urb *urb) struct usb_serial *serial; __u16 Data; unsigned char *data; - __u8 sp[5], st; + __u8 sp[5]; int i, rv = 0; __u16 wval, wreg = 0; int status = urb->status; @@ -644,7 +636,6 @@ static void mos7840_interrupt_callback(struct urb *urb) sp[1] = (__u8) data[1]; sp[2] = (__u8) data[2]; sp[3] = (__u8) data[3]; - st = (__u8) data[4]; for (i = 0; i < serial->num_ports; i++) { mos7840_port = mos7840_get_port_private(serial->port[i]); @@ -1300,7 +1291,6 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, struct urb *urb; /* __u16 Data; */ const unsigned char *current_position = data; - unsigned char *data1; if (mos7840_port_paranoia_check(port, __func__)) return -1; @@ -1361,7 +1351,6 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, mos7840_bulk_out_data_callback, mos7840_port); } - data1 = urb->transfer_buffer; dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress); if (mos7840_port->has_led) @@ -1592,7 +1581,6 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, int divisor = 0; int status; __u16 Data; - unsigned char number; __u16 clk_sel_val; struct usb_serial_port *port; @@ -1606,8 +1594,6 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, if (mos7840_serial_paranoia_check(port->serial, __func__)) return -1; - number = mos7840_port->port->port_number; - dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudRate); /* reset clk_uart_sel in spregOffset */ if (baudRate > 115200) { @@ -1697,14 +1683,12 @@ static void mos7840_change_port_settings(struct tty_struct *tty, { int baud; unsigned cflag; - unsigned iflag; __u8 lData; __u8 lParity; __u8 lStop; int status; __u16 Data; struct usb_serial_port *port; - struct usb_serial *serial; if (mos7840_port == NULL) return; @@ -1717,8 +1701,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (mos7840_serial_paranoia_check(port->serial, __func__)) return; - serial = port->serial; - if (!mos7840_port->open) { dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; @@ -1729,7 +1711,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty, lParity = LCR_PAR_NONE; cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; /* Change the number of bits */ switch (cflag & CSIZE) { @@ -2043,7 +2024,8 @@ static int mos7840_probe(struct usb_serial *serial, int device_type; if (product == MOSCHIP_DEVICE_ID_7810 || - product == MOSCHIP_DEVICE_ID_7820) { + product == MOSCHIP_DEVICE_ID_7820 || + product == MOSCHIP_DEVICE_ID_7843) { device_type = product; goto out; } @@ -2077,7 +2059,10 @@ static int mos7840_calc_num_ports(struct usb_serial *serial, int device_type = (unsigned long)usb_get_serial_data(serial); int num_ports; - num_ports = (device_type >> 4) & 0x000F; + if (device_type == MOSCHIP_DEVICE_ID_7843) + num_ports = 3; + else + num_ports = (device_type >> 4) & 0x000F; /* * num_ports is currently never zero as device_type is one of @@ -2132,22 +2117,16 @@ static int mos7840_port_probe(struct usb_serial_port *port) mos7840_port->SpRegOffset = 0x0; mos7840_port->ControlRegOffset = 0x1; mos7840_port->DcrRegOffset = 0x4; - } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0x8; - mos7840_port->ControlRegOffset = 0x9; - mos7840_port->DcrRegOffset = 0x16; - } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 2)) { - mos7840_port->SpRegOffset = 0xa; - mos7840_port->ControlRegOffset = 0xb; - mos7840_port->DcrRegOffset = 0x19; - } else if ((mos7840_port->port_num == 3) && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0xa; - mos7840_port->ControlRegOffset = 0xb; - mos7840_port->DcrRegOffset = 0x19; - } else if ((mos7840_port->port_num == 4) && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0xc; - mos7840_port->ControlRegOffset = 0xd; - mos7840_port->DcrRegOffset = 0x1c; + } else { + u8 phy_num = mos7840_port->port_num; + + /* Port 2 in the 2-port case uses registers of port 3 */ + if (serial->num_ports == 2) + phy_num = 3; + + mos7840_port->SpRegOffset = 0x8 + 2 * (phy_num - 2); + mos7840_port->ControlRegOffset = 0x9 + 2 * (phy_num - 2); + mos7840_port->DcrRegOffset = 0x16 + 3 * (phy_num - 2); } mos7840_dump_serial_port(port, mos7840_port); mos7840_set_port_private(port, mos7840_port); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 1ce27f3ff7a7..83869065b802 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -246,6 +246,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EC25 0x0125 #define QUECTEL_PRODUCT_BG96 0x0296 #define QUECTEL_PRODUCT_EP06 0x0306 +#define QUECTEL_PRODUCT_EM12 0x0512 #define CMOTECH_VENDOR_ID 0x16d8 #define CMOTECH_PRODUCT_6001 0x6001 @@ -1066,7 +1067,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(3) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ - { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */ + .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) }, /* Quectel products using Qualcomm vendor ID */ { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)}, { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20), @@ -1087,6 +1089,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff), .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff), + .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), @@ -1148,6 +1153,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), .driver_info = NCTRL(0) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */ + .driver_info = NCTRL(0) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), @@ -1938,10 +1945,12 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */ .driver_info = RSVD(4) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */ - { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) }, /* OLICARD300 - MT6225 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */ + { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2031, 0xff), /* Olicard 600 */ + .driver_info = RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) }, /* OLICARD300 - MT6225 */ { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) }, { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) }, { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) }, @@ -1955,6 +1964,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, + { USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */ + .driver_info = RSVD(4) | RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */ + .driver_info = RSVD(6) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index a4e0d13fc121..bb3f9aa4a909 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -46,6 +46,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), @@ -91,9 +92,14 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD220TA_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD960TA_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LM920_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LM940_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_TD620_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 26965cc23c17..559941ca884d 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -8,6 +8,7 @@ #define PL2303_VENDOR_ID 0x067b #define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_TB 0x2304 #define PL2303_PRODUCT_ID_RSAQ2 0x04bb #define PL2303_PRODUCT_ID_DCU11 0x1234 #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 @@ -20,6 +21,7 @@ #define PL2303_PRODUCT_ID_MOTOROLA 0x0307 #define PL2303_PRODUCT_ID_ZTEK 0xe1f1 + #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 #define ATEN_PRODUCT_ID 0x2008 @@ -119,10 +121,15 @@ /* Hewlett-Packard POS Pole Displays */ #define HP_VENDOR_ID 0x03f0 +#define HP_LM920_PRODUCT_ID 0x026b +#define HP_TD620_PRODUCT_ID 0x0956 #define HP_LD960_PRODUCT_ID 0x0b39 #define HP_LCM220_PRODUCT_ID 0x3139 #define HP_LCM960_PRODUCT_ID 0x3239 #define HP_LD220_PRODUCT_ID 0x3524 +#define HP_LD220TA_PRODUCT_ID 0x4349 +#define HP_LD960TA_PRODUCT_ID 0x4439 +#define HP_LM940_PRODUCT_ID 0x5039 /* Cressi Edy (diving computer) PC interface */ #define CRESSI_VENDOR_ID 0x04b8 diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index f2fbe1ec9701..a62981ca7a73 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -500,7 +500,6 @@ static void qt2_process_read_urb(struct urb *urb) struct usb_serial *serial; struct qt2_serial_private *serial_priv; struct usb_serial_port *port; - struct qt2_port_private *port_priv; bool escapeflag; unsigned char *ch; int i; @@ -514,7 +513,6 @@ static void qt2_process_read_urb(struct urb *urb) serial = urb->context; serial_priv = usb_get_serial_data(serial); port = serial->port[serial_priv->current_port]; - port_priv = usb_get_serial_port_data(port); for (i = 0; i < urb->actual_length; i++) { ch = (unsigned char *)urb->transfer_buffer + i; @@ -566,7 +564,6 @@ static void qt2_process_read_urb(struct urb *urb) serial_priv->current_port = newport; port = serial->port[serial_priv->current_port]; - port_priv = usb_get_serial_port_data(port); i += 3; escapeflag = true; break; diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 4d0273508043..edbbb13d6de6 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -85,7 +85,8 @@ DEVICE(moto_modem, MOTO_IDS); /* Motorola Tetra driver */ #define MOTOROLA_TETRA_IDS() \ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ - { USB_DEVICE(0x0cad, 0x9012) } /* MTP6550 */ + { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \ + { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); /* Novatel Wireless GPS driver */ diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 6fd427284b12..59aad38b490a 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Storage driver configuration # diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 4d261e4de9ad..c26129d5b943 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -1131,7 +1131,7 @@ static int ms_lib_alloc_writebuf(struct us_data *us) ms_lib_clear_writebuf(us); -return 0; + return 0; } static int ms_lib_force_setlogical_pair(struct us_data *us, u16 logblk, u16 phyblk) diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index edcf2be0e0eb..395cf8fb5870 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -167,6 +167,7 @@ static int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us) static void rio_karma_destructor(void *extra) { struct karma_data *data = (struct karma_data *) extra; + kfree(data->recv); } @@ -174,6 +175,7 @@ static int rio_karma_init(struct us_data *us) { int ret = 0; struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO); + if (!data) goto out; diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 31b024441938..cc794e25a0b6 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -763,18 +763,16 @@ static void rts51x_suspend_timer_fn(struct timer_list *t) break; case RTS51X_STAT_IDLE: case RTS51X_STAT_SS: - usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n", - atomic_read(&us->pusb_intf->pm_usage_cnt), + usb_stor_dbg(us, "RTS51X_STAT_SS, power.usage:%d\n", atomic_read(&us->pusb_intf->dev.power.usage_count)); - if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) { + if (atomic_read(&us->pusb_intf->dev.power.usage_count) > 0) { usb_stor_dbg(us, "Ready to enter SS state\n"); rts51x_set_stat(chip, RTS51X_STAT_SS); /* ignore mass storage interface's children */ pm_suspend_ignore_children(&us->pusb_intf->dev, true); usb_autopm_put_interface_async(us->pusb_intf); - usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n", - atomic_read(&us->pusb_intf->pm_usage_cnt), + usb_stor_dbg(us, "RTS51X_STAT_SS 01, power.usage:%d\n", atomic_read(&us->pusb_intf->dev.power.usage_count)); } break; @@ -807,11 +805,10 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) int ret; if (working_scsi(srb)) { - usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n", - atomic_read(&us->pusb_intf->pm_usage_cnt), + usb_stor_dbg(us, "working scsi, power.usage:%d\n", atomic_read(&us->pusb_intf->dev.power.usage_count)); - if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) { + if (atomic_read(&us->pusb_intf->dev.power.usage_count) <= 0) { ret = usb_autopm_get_interface(us->pusb_intf); usb_stor_dbg(us, "working scsi, ret=%d\n", ret); } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e227bb5b794f..a73ea495d5a7 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -235,8 +235,12 @@ static int slave_configure(struct scsi_device *sdev) if (!(us->fflags & US_FL_NEEDS_CAP16)) sdev->try_rc_10_first = 1; - /* assume SPC3 or latter devices support sense size > 18 */ - if (sdev->scsi_level > SCSI_SPC_2) + /* + * assume SPC3 or latter devices support sense size > 18 + * unless US_FL_BAD_SENSE quirk is specified. + */ + if (sdev->scsi_level > SCSI_SPC_2 && + !(us->fflags & US_FL_BAD_SENSE)) us->fflags |= US_FL_SANE_SENSE; /* @@ -639,13 +643,6 @@ static const struct scsi_host_template usb_stor_host_template = { */ .max_sectors = 240, - /* - * merge commands... this seems to help performance, but - * periodically someone should test to see which setting is more - * optimal. - */ - .use_clustering = 1, - /* emulated HBA */ .emulated = 1, diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 1f7b401c4d04..a6d68191c861 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -368,25 +368,19 @@ static void uas_data_cmplt(struct urb *urb) struct scsi_cmnd *cmnd = urb->context; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; - struct scsi_data_buffer *sdb = NULL; + struct scsi_data_buffer *sdb = &cmnd->sdb; unsigned long flags; int status = urb->status; spin_lock_irqsave(&devinfo->lock, flags); if (cmdinfo->data_in_urb == urb) { - sdb = scsi_in(cmnd); cmdinfo->state &= ~DATA_IN_URB_INFLIGHT; cmdinfo->data_in_urb = NULL; } else if (cmdinfo->data_out_urb == urb) { - sdb = scsi_out(cmnd); cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT; cmdinfo->data_out_urb = NULL; } - if (sdb == NULL) { - WARN_ON_ONCE(1); - goto out; - } if (devinfo->resetting) goto out; @@ -401,9 +395,9 @@ static void uas_data_cmplt(struct urb *urb) if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN) uas_log_cmd_state(cmnd, "data cmplt err", status); /* error: no data transfered */ - sdb->resid = sdb->length; + scsi_set_resid(cmnd, sdb->length); } else { - sdb->resid = sdb->length - urb->actual_length; + scsi_set_resid(cmnd, sdb->length - urb->actual_length); } uas_try_complete(cmnd, __func__); out: @@ -426,8 +420,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, struct usb_device *udev = devinfo->udev; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct urb *urb = usb_alloc_urb(0, gfp); - struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE) - ? scsi_in(cmnd) : scsi_out(cmnd); + struct scsi_data_buffer *sdb = &cmnd->sdb; unsigned int pipe = (dir == DMA_FROM_DEVICE) ? devinfo->data_in_pipe : devinfo->data_out_pipe; @@ -879,6 +872,7 @@ static struct scsi_host_template uas_host_template = { .this_id = -1, .sg_tablesize = SG_NONE, .skip_settle_delay = 1, + .dma_boundary = PAGE_SIZE - 1, }; #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f7f83b21dc74..ea0d27a94afe 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1266,6 +1266,18 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, US_FL_FIX_CAPACITY ), /* + * Reported by Icenowy Zheng <icenowy@aosc.io> + * The SMI SM3350 USB-UFS bridge controller will enter a wrong state + * that do not process read/write command if a long sense is requested, + * so force to use 18-byte sense. + */ +UNUSUAL_DEV( 0x090c, 0x3350, 0x0000, 0xffff, + "SMI", + "SM3350 UFS-to-USB-Mass-Storage bridge", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BAD_SENSE ), + +/* * Reported by Paul Hartman <paul.hartman+linux@gmail.com> * This card reader returns "Illegal Request, Logical Block Address * Out of Range" for the first READ(10) after a new card is inserted. diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index 30a847c2089d..89d9193bd1cf 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 menuconfig TYPEC tristate "USB Type-C Support" diff --git a/drivers/usb/typec/altmodes/Kconfig b/drivers/usb/typec/altmodes/Kconfig index efef2a64bc51..ef2226eb7a33 100644 --- a/drivers/usb/typec/altmodes/Kconfig +++ b/drivers/usb/typec/altmodes/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 menu "USB Type-C Alternate Mode drivers" diff --git a/drivers/usb/typec/altmodes/Makefile b/drivers/usb/typec/altmodes/Makefile index 5caf094ef71a..eda8456f1c92 100644 --- a/drivers/usb/typec/altmodes/Makefile +++ b/drivers/usb/typec/altmodes/Makefile @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_TYPEC_DP_ALTMODE) += typec_displayport.o typec_displayport-y := displayport.o diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 3f06e94771a7..610d790bc9be 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -24,10 +24,6 @@ enum { DP_CONF_DUAL_D, }; -/* Helper for setting/getting the pin assignement value to the configuration */ -#define DP_CONF_SET_PIN_ASSIGN(_a_) ((_a_) << 8) -#define DP_CONF_GET_PIN_ASSIGN(_conf_) (((_conf_) & GENMASK(15, 8)) >> 8) - /* Pin assignments that use USB3.1 Gen2 signaling to carry DP protocol */ #define DP_PIN_ASSIGN_GEN2_BR_MASK (BIT(DP_PIN_ASSIGN_A) | \ BIT(DP_PIN_ASSIGN_B)) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 5db0593ca0bd..2eb623841847 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -9,6 +9,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> #include <linux/slab.h> #include "bus.h" @@ -204,15 +205,32 @@ static void typec_altmode_put_partner(struct altmode *altmode) put_device(&adev->dev); } -static int __typec_port_match(struct device *dev, const void *name) +static int typec_port_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} + +static int typec_port_name_match(struct device *dev, const void *name) { return !strcmp((const char *)name, dev_name(dev)); } static void *typec_port_match(struct device_connection *con, int ep, void *data) { - return class_find_device(typec_class, NULL, con->endpoint[ep], - __typec_port_match); + struct device *dev; + + /* + * FIXME: Check does the fwnode supports the requested SVID. If it does + * we need to return ERR_PTR(-PROBE_DEFER) when there is no device. + */ + if (con->fwnode) + return class_find_device(typec_class, NULL, con->fwnode, + typec_port_fwnode_match); + + dev = class_find_device(typec_class, NULL, con->endpoint[ep], + typec_port_name_match); + + return dev ? dev : ERR_PTR(-EPROBE_DEFER); } struct typec_altmode * @@ -277,7 +295,7 @@ void typec_altmode_update_active(struct typec_altmode *adev, bool active) if (adev->active == active) return; - if (!is_typec_port(adev->dev.parent)) { + if (!is_typec_port(adev->dev.parent) && adev->dev.driver) { if (!active) module_put(adev->dev.driver->owner); else @@ -1496,11 +1514,8 @@ typec_port_register_altmode(struct typec_port *port, { struct typec_altmode *adev; struct typec_mux *mux; - char id[10]; - - sprintf(id, "id%04xm%02x", desc->svid, desc->mode); - mux = typec_mux_get(&port->dev, id); + mux = typec_mux_get(&port->dev, desc); if (IS_ERR(mux)) return ERR_CAST(mux); @@ -1593,7 +1608,7 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_CAST(port->sw); } - port->mux = typec_mux_get(&port->dev, "typec-mux"); + port->mux = typec_mux_get(&port->dev, NULL); if (IS_ERR(port->mux)) { put_device(&port->dev); return ERR_CAST(port->mux); diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index d990aa510fab..2ce54f3fc79c 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -11,6 +11,8 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> +#include <linux/slab.h> #include <linux/usb/typec_mux.h> static DEFINE_MUTEX(switch_lock); @@ -23,15 +25,25 @@ static void *typec_switch_match(struct device_connection *con, int ep, { struct typec_switch *sw; - list_for_each_entry(sw, &switch_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) - return sw; + if (!con->fwnode) { + list_for_each_entry(sw, &switch_list, entry) + if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) + return sw; + return ERR_PTR(-EPROBE_DEFER); + } /* - * We only get called if a connection was found, tell the caller to - * wait for the switch to show up. + * With OF graph the mux node must have a boolean device property named + * "orientation-switch". */ - return ERR_PTR(-EPROBE_DEFER); + if (con->id && !fwnode_property_present(con->fwnode, con->id)) + return NULL; + + list_for_each_entry(sw, &switch_list, entry) + if (dev_fwnode(sw->dev) == con->fwnode) + return sw; + + return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL; } /** @@ -48,7 +60,7 @@ struct typec_switch *typec_switch_get(struct device *dev) struct typec_switch *sw; mutex_lock(&switch_lock); - sw = device_connection_find_match(dev, "typec-switch", NULL, + sw = device_connection_find_match(dev, "orientation-switch", NULL, typec_switch_match); if (!IS_ERR_OR_NULL(sw)) { WARN_ON(!try_module_get(sw->dev->driver->owner)); @@ -112,35 +124,87 @@ EXPORT_SYMBOL_GPL(typec_switch_unregister); static void *typec_mux_match(struct device_connection *con, int ep, void *data) { + const struct typec_altmode_desc *desc = data; struct typec_mux *mux; + int nval; + bool match; + u16 *val; + int i; - list_for_each_entry(mux, &mux_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) - return mux; + if (!con->fwnode) { + list_for_each_entry(mux, &mux_list, entry) + if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) + return mux; + return ERR_PTR(-EPROBE_DEFER); + } /* - * We only get called if a connection was found, tell the caller to - * wait for the switch to show up. + * Check has the identifier already been "consumed". If it + * has, no need to do any extra connection identification. */ + match = !con->id; + if (match) + goto find_mux; + + /* Accessory Mode muxes */ + if (!desc) { + match = fwnode_property_present(con->fwnode, "accessory"); + if (match) + goto find_mux; + return NULL; + } + + /* Alternate Mode muxes */ + nval = fwnode_property_read_u16_array(con->fwnode, "svid", NULL, 0); + if (nval <= 0) + return NULL; + + val = kcalloc(nval, sizeof(*val), GFP_KERNEL); + if (!val) + return ERR_PTR(-ENOMEM); + + nval = fwnode_property_read_u16_array(con->fwnode, "svid", val, nval); + if (nval < 0) { + kfree(val); + return ERR_PTR(nval); + } + + for (i = 0; i < nval; i++) { + match = val[i] == desc->svid; + if (match) { + kfree(val); + goto find_mux; + } + } + kfree(val); + return NULL; + +find_mux: + list_for_each_entry(mux, &mux_list, entry) + if (dev_fwnode(mux->dev) == con->fwnode) + return mux; + return ERR_PTR(-EPROBE_DEFER); } /** * typec_mux_get - Find USB Type-C Multiplexer * @dev: The caller device - * @name: Mux identifier + * @desc: Alt Mode description * * Finds a mux linked to the caller. This function is primarily meant for the * Type-C drivers. Returns a reference to the mux on success, NULL if no * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection * was found but the mux has not been enumerated yet. */ -struct typec_mux *typec_mux_get(struct device *dev, const char *name) +struct typec_mux *typec_mux_get(struct device *dev, + const struct typec_altmode_desc *desc) { struct typec_mux *mux; mutex_lock(&mux_lock); - mux = device_connection_find_match(dev, name, NULL, typec_mux_match); + mux = device_connection_find_match(dev, "mode-switch", (void *)desc, + typec_mux_match); if (!IS_ERR_OR_NULL(mux)) { WARN_ON(!try_module_get(mux->dev->driver->owner)); get_device(mux->dev); diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 9a954d2b8d8f..01ed0d5e10e8 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + menu "USB Type-C Multiplexer/DeMultiplexer Switch support" config TYPEC_MUX_PI3USB30532 diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index f03ea8a61768..72481bbb2af3 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config TYPEC_TCPM tristate "USB Type-C Port Controller Manager" depends on USB diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 43b64d9309d0..e9344997329c 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -1765,7 +1765,7 @@ static int fusb302_probe(struct i2c_client *client, * to be set by the platform code which also registers the i2c client * for the fusb302. */ - if (device_property_read_string(dev, "fcs,extcon-name", &name) == 0) { + if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) { chip->extcon = extcon_get_extcon_dev(name); if (!chip->extcon) return -EPROBE_DEFER; diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index dbbd71f754d0..a2233d72ae7c 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -37,6 +37,7 @@ S(SRC_ATTACHED), \ S(SRC_STARTUP), \ S(SRC_SEND_CAPABILITIES), \ + S(SRC_SEND_CAPABILITIES_TIMEOUT), \ S(SRC_NEGOTIATE_CAPABILITIES), \ S(SRC_TRANSITION_SUPPLY), \ S(SRC_READY), \ @@ -317,6 +318,9 @@ struct tcpm_port { /* Deadline in jiffies to exit src_try_wait state */ unsigned long max_wait; + /* port belongs to a self powered device */ + bool self_powered; + #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -2210,7 +2214,8 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) unsigned int i, j, max_mw = 0, max_mv = 0; unsigned int min_src_mv, max_src_mv, src_ma, src_mw; unsigned int min_snk_mv, max_snk_mv; - u32 pdo; + unsigned int max_op_mv; + u32 pdo, src, snk; unsigned int src_pdo = 0, snk_pdo = 0; /* @@ -2260,16 +2265,18 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) continue; } - if (max_src_mv <= max_snk_mv && - min_src_mv >= min_snk_mv) { + if (min_src_mv <= max_snk_mv && + max_src_mv >= min_snk_mv) { + max_op_mv = min(max_src_mv, max_snk_mv); + src_mw = (max_op_mv * src_ma) / 1000; /* Prefer higher voltages if available */ if ((src_mw == max_mw && - min_src_mv > max_mv) || + max_op_mv > max_mv) || src_mw > max_mw) { src_pdo = i; snk_pdo = j; max_mw = src_mw; - max_mv = max_src_mv; + max_mv = max_op_mv; } } } @@ -2282,16 +2289,19 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) } if (src_pdo) { - pdo = port->source_caps[src_pdo]; - - port->pps_data.min_volt = pdo_pps_apdo_min_voltage(pdo); - port->pps_data.max_volt = pdo_pps_apdo_max_voltage(pdo); - port->pps_data.max_curr = - min_pps_apdo_current(pdo, port->snk_pdo[snk_pdo]); - port->pps_data.out_volt = - min(pdo_pps_apdo_max_voltage(pdo), port->pps_data.out_volt); - port->pps_data.op_curr = - min(port->pps_data.max_curr, port->pps_data.op_curr); + src = port->source_caps[src_pdo]; + snk = port->snk_pdo[snk_pdo]; + + port->pps_data.min_volt = max(pdo_pps_apdo_min_voltage(src), + pdo_pps_apdo_min_voltage(snk)); + port->pps_data.max_volt = min(pdo_pps_apdo_max_voltage(src), + pdo_pps_apdo_max_voltage(snk)); + port->pps_data.max_curr = min_pps_apdo_current(src, snk); + port->pps_data.out_volt = min(port->pps_data.max_volt, + max(port->pps_data.min_volt, + port->pps_data.out_volt)); + port->pps_data.op_curr = min(port->pps_data.max_curr, + port->pps_data.op_curr); } return src_pdo; @@ -2957,10 +2967,34 @@ static void run_state_machine(struct tcpm_port *port) /* port->hard_reset_count = 0; */ port->caps_count = 0; port->pd_capable = true; - tcpm_set_state_cond(port, hard_reset_state(port), + tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT, PD_T_SEND_SOURCE_CAP); } break; + case SRC_SEND_CAPABILITIES_TIMEOUT: + /* + * Error recovery for a PD_DATA_SOURCE_CAP reply timeout. + * + * PD 2.0 sinks are supposed to accept src-capabilities with a + * 3.0 header and simply ignore any src PDOs which the sink does + * not understand such as PPS but some 2.0 sinks instead ignore + * the entire PD_DATA_SOURCE_CAP message, causing contract + * negotiation to fail. + * + * After PD_N_HARD_RESET_COUNT hard-reset attempts, we try + * sending src-capabilities with a lower PD revision to + * make these broken sinks work. + */ + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) { + tcpm_set_state(port, HARD_RESET_SEND, 0); + } else if (port->negotiated_rev > PD_REV20) { + port->negotiated_rev--; + port->hard_reset_count = 0; + tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); + } else { + tcpm_set_state(port, hard_reset_state(port), 0); + } + break; case SRC_NEGOTIATE_CAPABILITIES: ret = tcpm_pd_check_request(port); if (ret < 0) { @@ -3254,7 +3288,8 @@ static void run_state_machine(struct tcpm_port *port) case SRC_HARD_RESET_VBUS_OFF: tcpm_set_vconn(port, true); tcpm_set_vbus(port, false); - tcpm_set_roles(port, false, TYPEC_SOURCE, TYPEC_HOST); + tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE, + TYPEC_HOST); tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER); break; case SRC_HARD_RESET_VBUS_ON: @@ -3266,8 +3301,10 @@ static void run_state_machine(struct tcpm_port *port) case SNK_HARD_RESET_SINK_OFF: memset(&port->pps_data, 0, sizeof(port->pps_data)); tcpm_set_vconn(port, false); - tcpm_set_charge(port, false); - tcpm_set_roles(port, false, TYPEC_SINK, TYPEC_DEVICE); + if (port->pd_capable) + tcpm_set_charge(port, false); + tcpm_set_roles(port, port->self_powered, TYPEC_SINK, + TYPEC_DEVICE); /* * VBUS may or may not toggle, depending on the adapter. * If it doesn't toggle, transition to SNK_HARD_RESET_SINK_ON @@ -3297,6 +3334,12 @@ static void run_state_machine(struct tcpm_port *port) * Similar, dual-mode ports in source mode should transition * to PE_SNK_Transition_to_default. */ + if (port->pd_capable) { + tcpm_set_current_limit(port, + tcpm_get_current_limit(port), + 5000); + tcpm_set_charge(port, true); + } tcpm_set_attached_state(port, true); tcpm_set_state(port, SNK_STARTUP, 0); break; @@ -4412,68 +4455,10 @@ sink: return -EINVAL; port->operating_snk_mw = mw / 1000; - return 0; -} - -int tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo) -{ - if (tcpm_validate_caps(port, pdo, nr_pdo)) - return -EINVAL; - - mutex_lock(&port->lock); - port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, pdo, nr_pdo); - switch (port->state) { - case SRC_UNATTACHED: - case SRC_ATTACH_WAIT: - case SRC_TRYWAIT: - tcpm_set_cc(port, tcpm_rp_cc(port)); - break; - case SRC_SEND_CAPABILITIES: - case SRC_NEGOTIATE_CAPABILITIES: - case SRC_READY: - case SRC_WAIT_NEW_CAPABILITIES: - tcpm_set_cc(port, tcpm_rp_cc(port)); - tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); - break; - default: - break; - } - mutex_unlock(&port->lock); - return 0; -} -EXPORT_SYMBOL_GPL(tcpm_update_source_capabilities); - -int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo, - unsigned int operating_snk_mw) -{ - if (tcpm_validate_caps(port, pdo, nr_pdo)) - return -EINVAL; - - mutex_lock(&port->lock); - port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, pdo, nr_pdo); - port->operating_snk_mw = operating_snk_mw; - port->update_sink_caps = true; + port->self_powered = fwnode_property_read_bool(fwnode, "self-powered"); - switch (port->state) { - case SNK_NEGOTIATE_CAPABILITIES: - case SNK_NEGOTIATE_PPS_CAPABILITIES: - case SNK_READY: - case SNK_TRANSITION_SINK: - case SNK_TRANSITION_SINK_VBUS: - if (port->pps_data.active) - tcpm_set_state(port, SNK_NEGOTIATE_PPS_CAPABILITIES, 0); - else - tcpm_set_state(port, SNK_NEGOTIATE_CAPABILITIES, 0); - break; - default: - break; - } - mutex_unlock(&port->lock); return 0; } -EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities); /* Power Supply access to expose source power information */ enum tcpm_psy_online_states { @@ -4720,6 +4705,7 @@ static int tcpm_copy_caps(struct tcpm_port *port, port->typec_caps.prefer_role = tcfg->default_role; port->typec_caps.type = tcfg->type; port->typec_caps.data = tcfg->data; + port->self_powered = port->tcpc->config->self_powered; return 0; } @@ -4790,12 +4776,12 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) err = devm_tcpm_psy_register(port); if (err) - goto out_destroy_wq; + goto out_role_sw_put; port->typec_port = typec_register_port(port->dev, &port->typec_caps); if (IS_ERR(port->typec_port)) { err = PTR_ERR(port->typec_port); - goto out_destroy_wq; + goto out_role_sw_put; } if (tcpc->config && tcpc->config->alt_modes) { @@ -4828,8 +4814,10 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpm_log(port, "%s: registered", dev_name(dev)); return port; -out_destroy_wq: +out_role_sw_put: usb_role_switch_put(port->role_sw); +out_destroy_wq: + tcpm_debugfs_exit(port); destroy_workqueue(port->wq); return ERR_PTR(err); } diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c index 423208e19383..6770afd40765 100644 --- a/drivers/usb/typec/tcpm/wcove.c +++ b/drivers/usb/typec/tcpm/wcove.c @@ -615,8 +615,13 @@ static int wcove_typec_probe(struct platform_device *pdev) wcove->dev = &pdev->dev; wcove->regmap = pmic->regmap; - irq = regmap_irq_get_virq(pmic->irq_chip_data_chgr, - platform_get_irq(pdev, 0)); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); + return irq; + } + + irq = regmap_irq_get_virq(pmic->irq_chip_data_chgr, irq); if (irq < 0) return irq; diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index c84c8c189e90..c674abe3cf99 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -14,6 +14,8 @@ #include <linux/usb/typec.h> /* Register offsets */ +#define TPS_REG_VID 0x00 +#define TPS_REG_MODE 0x03 #define TPS_REG_CMD1 0x08 #define TPS_REG_DATA1 0x09 #define TPS_REG_INT_EVENT1 0x14 @@ -66,6 +68,20 @@ struct tps6598x_rx_identity_reg { #define TPS_TASK_TIMEOUT 1 #define TPS_TASK_REJECTED 3 +enum { + TPS_MODE_APP, + TPS_MODE_BOOT, + TPS_MODE_BIST, + TPS_MODE_DISC, +}; + +static const char *const modes[] = { + [TPS_MODE_APP] = "APP ", + [TPS_MODE_BOOT] = "BOOT", + [TPS_MODE_BIST] = "BIST", + [TPS_MODE_DISC] = "DISC", +}; + /* Unrecognized commands will be replaced with "!CMD" */ #define INVALID_CMD(_cmd_) (_cmd_ == 0x444d4321) @@ -110,6 +126,20 @@ tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len) return 0; } +static int tps6598x_block_write(struct tps6598x *tps, u8 reg, + void *val, size_t len) +{ + u8 data[TPS_MAX_LEN + 1]; + + if (!tps->i2c_protocol) + return regmap_raw_write(tps->regmap, reg, val, len); + + data[0] = len; + memcpy(&data[1], val, len); + + return regmap_raw_write(tps->regmap, reg, data, sizeof(data)); +} + static inline int tps6598x_read16(struct tps6598x *tps, u8 reg, u16 *val) { return tps6598x_block_read(tps, reg, val, sizeof(u16)); @@ -127,23 +157,23 @@ static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val) static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u16)); + return tps6598x_block_write(tps, reg, &val, sizeof(u16)); } static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u32)); + return tps6598x_block_write(tps, reg, &val, sizeof(u32)); } static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u64)); + return tps6598x_block_write(tps, reg, &val, sizeof(u64)); } static inline int tps6598x_write_4cc(struct tps6598x *tps, u8 reg, const char *val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u32)); + return tps6598x_block_write(tps, reg, &val, sizeof(u32)); } static int tps6598x_read_partner_identity(struct tps6598x *tps) @@ -229,8 +259,8 @@ static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, return -EBUSY; if (in_len) { - ret = regmap_raw_write(tps->regmap, TPS_REG_DATA1, - in_data, in_len); + ret = tps6598x_block_write(tps, TPS_REG_DATA1, + in_data, in_len); if (ret) return ret; } @@ -384,6 +414,32 @@ err_unlock: return IRQ_HANDLED; } +static int tps6598x_check_mode(struct tps6598x *tps) +{ + char mode[5] = { }; + int ret; + + ret = tps6598x_read32(tps, TPS_REG_MODE, (void *)mode); + if (ret) + return ret; + + switch (match_string(modes, ARRAY_SIZE(modes), mode)) { + case TPS_MODE_APP: + return 0; + case TPS_MODE_BOOT: + dev_warn(tps->dev, "dead-battery condition\n"); + return 0; + case TPS_MODE_BIST: + case TPS_MODE_DISC: + default: + dev_err(tps->dev, "controller in unsupported mode \"%s\"\n", + mode); + break; + } + + return -ENODEV; +} + static const struct regmap_config tps6598x_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -409,10 +465,8 @@ static int tps6598x_probe(struct i2c_client *client) if (IS_ERR(tps->regmap)) return PTR_ERR(tps->regmap); - ret = tps6598x_read32(tps, 0, &vid); - if (ret < 0) - return ret; - if (!vid) + ret = tps6598x_read32(tps, TPS_REG_VID, &vid); + if (ret < 0 || !vid) return -ENODEV; /* @@ -425,6 +479,11 @@ static int tps6598x_probe(struct i2c_client *client) if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) tps->i2c_protocol = true; + /* Make sure the controller has application firmware running */ + ret = tps6598x_check_mode(tps); + if (ret) + return ret; + ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); if (ret < 0) return ret; @@ -501,19 +560,19 @@ static int tps6598x_remove(struct i2c_client *client) return 0; } -static const struct acpi_device_id tps6598x_acpi_match[] = { - { "INT3515", 0 }, +static const struct i2c_device_id tps6598x_id[] = { + { "tps6598x" }, { } }; -MODULE_DEVICE_TABLE(acpi, tps6598x_acpi_match); +MODULE_DEVICE_TABLE(i2c, tps6598x_id); static struct i2c_driver tps6598x_i2c_driver = { .driver = { .name = "tps6598x", - .acpi_match_table = tps6598x_acpi_match, }, .probe_new = tps6598x_probe, .remove = tps6598x_remove, + .id_table = tps6598x_id, }; module_i2c_driver(tps6598x_i2c_driver); diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 78118883f96c..15c2ac7db02d 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config TYPEC_UCSI tristate "USB Type-C Connector System Software Interface driver" depends on !CPU_BIG_ENDIAN diff --git a/drivers/usb/typec/ucsi/debug.h b/drivers/usb/typec/ucsi/debug.h deleted file mode 100644 index fdeff39df120..000000000000 --- a/drivers/usb/typec/ucsi/debug.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __UCSI_DEBUG_H -#define __UCSI_DEBUG_H - -#include "ucsi.h" - -static const char * const ucsi_cmd_strs[] = { - [0] = "Unknown command", - [UCSI_PPM_RESET] = "PPM_RESET", - [UCSI_CANCEL] = "CANCEL", - [UCSI_CONNECTOR_RESET] = "CONNECTOR_RESET", - [UCSI_ACK_CC_CI] = "ACK_CC_CI", - [UCSI_SET_NOTIFICATION_ENABLE] = "SET_NOTIFICATION_ENABLE", - [UCSI_GET_CAPABILITY] = "GET_CAPABILITY", - [UCSI_GET_CONNECTOR_CAPABILITY] = "GET_CONNECTOR_CAPABILITY", - [UCSI_SET_UOM] = "SET_UOM", - [UCSI_SET_UOR] = "SET_UOR", - [UCSI_SET_PDM] = "SET_PDM", - [UCSI_SET_PDR] = "SET_PDR", - [UCSI_GET_ALTERNATE_MODES] = "GET_ALTERNATE_MODES", - [UCSI_GET_CAM_SUPPORTED] = "GET_CAM_SUPPORTED", - [UCSI_GET_CURRENT_CAM] = "GET_CURRENT_CAM", - [UCSI_SET_NEW_CAM] = "SET_NEW_CAM", - [UCSI_GET_PDOS] = "GET_PDOS", - [UCSI_GET_CABLE_PROPERTY] = "GET_CABLE_PROPERTY", - [UCSI_GET_CONNECTOR_STATUS] = "GET_CONNECTOR_STATUS", - [UCSI_GET_ERROR_STATUS] = "GET_ERROR_STATUS", -}; - -static inline const char *ucsi_cmd_str(u64 raw_cmd) -{ - u8 cmd = raw_cmd & GENMASK(7, 0); - - return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; -} - -static const char * const ucsi_ack_strs[] = { - [0] = "", - [UCSI_ACK_EVENT] = "event", - [UCSI_ACK_CMD] = "command", -}; - -static inline const char *ucsi_ack_str(u8 ack) -{ - return ucsi_ack_strs[(ack >= ARRAY_SIZE(ucsi_ack_strs)) ? 0 : ack]; -} - -static inline const char *ucsi_cci_str(u32 cci) -{ - if (cci & GENMASK(7, 0)) { - if (cci & BIT(29)) - return "Event pending (ACK completed)"; - if (cci & BIT(31)) - return "Event pending (command completed)"; - return "Connector Change"; - } - if (cci & BIT(29)) - return "ACK completed"; - if (cci & BIT(31)) - return "Command completed"; - - return ""; -} - -#endif /* __UCSI_DEBUG_H */ diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c index d9a6ff6e673c..ffa3b4c3f338 100644 --- a/drivers/usb/typec/ucsi/trace.c +++ b/drivers/usb/typec/ucsi/trace.c @@ -1,3 +1,62 @@ // SPDX-License-Identifier: GPL-2.0 #define CREATE_TRACE_POINTS +#include "ucsi.h" #include "trace.h" + +static const char * const ucsi_cmd_strs[] = { + [0] = "Unknown command", + [UCSI_PPM_RESET] = "PPM_RESET", + [UCSI_CANCEL] = "CANCEL", + [UCSI_CONNECTOR_RESET] = "CONNECTOR_RESET", + [UCSI_ACK_CC_CI] = "ACK_CC_CI", + [UCSI_SET_NOTIFICATION_ENABLE] = "SET_NOTIFICATION_ENABLE", + [UCSI_GET_CAPABILITY] = "GET_CAPABILITY", + [UCSI_GET_CONNECTOR_CAPABILITY] = "GET_CONNECTOR_CAPABILITY", + [UCSI_SET_UOM] = "SET_UOM", + [UCSI_SET_UOR] = "SET_UOR", + [UCSI_SET_PDM] = "SET_PDM", + [UCSI_SET_PDR] = "SET_PDR", + [UCSI_GET_ALTERNATE_MODES] = "GET_ALTERNATE_MODES", + [UCSI_GET_CAM_SUPPORTED] = "GET_CAM_SUPPORTED", + [UCSI_GET_CURRENT_CAM] = "GET_CURRENT_CAM", + [UCSI_SET_NEW_CAM] = "SET_NEW_CAM", + [UCSI_GET_PDOS] = "GET_PDOS", + [UCSI_GET_CABLE_PROPERTY] = "GET_CABLE_PROPERTY", + [UCSI_GET_CONNECTOR_STATUS] = "GET_CONNECTOR_STATUS", + [UCSI_GET_ERROR_STATUS] = "GET_ERROR_STATUS", +}; + +const char *ucsi_cmd_str(u64 raw_cmd) +{ + u8 cmd = raw_cmd & GENMASK(7, 0); + + return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; +} + +static const char * const ucsi_ack_strs[] = { + [0] = "", + [UCSI_ACK_EVENT] = "event", + [UCSI_ACK_CMD] = "command", +}; + +const char *ucsi_ack_str(u8 ack) +{ + return ucsi_ack_strs[(ack >= ARRAY_SIZE(ucsi_ack_strs)) ? 0 : ack]; +} + +const char *ucsi_cci_str(u32 cci) +{ + if (cci & GENMASK(7, 0)) { + if (cci & BIT(29)) + return "Event pending (ACK completed)"; + if (cci & BIT(31)) + return "Event pending (command completed)"; + return "Connector Change"; + } + if (cci & BIT(29)) + return "ACK completed"; + if (cci & BIT(31)) + return "Command completed"; + + return ""; +} diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h index d5092446ecc6..5e2906df2db7 100644 --- a/drivers/usb/typec/ucsi/trace.h +++ b/drivers/usb/typec/ucsi/trace.h @@ -7,8 +7,11 @@ #define __UCSI_TRACE_H #include <linux/tracepoint.h> -#include "ucsi.h" -#include "debug.h" + +const char *ucsi_cmd_str(u64 raw_cmd); +const char *ucsi_ack_str(u8 ack); +const char *ucsi_cci_str(u32 cci); +const char *ucsi_recipient_str(u8 recipient); DECLARE_EVENT_CLASS(ucsi_log_ack, TP_PROTO(u8 ack), diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index a20b65cb6678..2f86b28fa3da 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USBIP_CORE tristate "USB/IP support" depends on NET diff --git a/drivers/usb/usbip/README b/drivers/usb/usbip/README deleted file mode 100644 index 41a2cf2e77a6..000000000000 --- a/drivers/usb/usbip/README +++ /dev/null @@ -1,7 +0,0 @@ -TODO: - - more discussion about the protocol - - testing - - review of the userspace interface - - document the protocol - -Please send patches for this code to Greg Kroah-Hartman <greg@kroah.com> diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 97b09a42a10c..dbfb2f24d71e 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -361,16 +361,10 @@ static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu) } if (usb_endpoint_xfer_isoc(epd)) { - /* validate packet size and number of packets */ - unsigned int maxp, packets, bytes; - - maxp = usb_endpoint_maxp(epd); - maxp *= usb_endpoint_maxp_mult(epd); - bytes = pdu->u.cmd_submit.transfer_buffer_length; - packets = DIV_ROUND_UP(bytes, maxp); - + /* validate number of packets */ if (pdu->u.cmd_submit.number_of_packets < 0 || - pdu->u.cmd_submit.number_of_packets > packets) { + pdu->u.cmd_submit.number_of_packets > + USBIP_MAX_ISO_PACKETS) { dev_err(&sdev->udev->dev, "CMD_SUBMIT: isoc invalid num packets %d\n", pdu->u.cmd_submit.number_of_packets); diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index bf8afe9b5883..8be857a4fa13 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -121,6 +121,13 @@ extern struct device_attribute dev_attr_usbip_debug; #define USBIP_DIR_OUT 0x00 #define USBIP_DIR_IN 0x01 +/* + * Arbitrary limit for the maximum number of isochronous packets in an URB, + * compare for example the uhci_submit_isochronous function in + * drivers/usb/host/uhci-q.c + */ +#define USBIP_MAX_ISO_PACKETS 1024 + /** * struct usbip_header_basic - data pertinent to every request * @command: the usbip request type diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 1e592ec94ba4..f46ee1fefe02 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -702,8 +702,10 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag } vdev = &vhci_hcd->vdev[portnum-1]; - /* patch to usb_sg_init() is in 2.5.60 */ - BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); + if (!urb->transfer_buffer && urb->transfer_buffer_length) { + dev_dbg(dev, "Null URB transfer buffer\n"); + return -EINVAL; + } spin_lock_irqsave(&vhci->lock, flags); diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c index 1634d8698e15..a72c17ff1c6a 100644 --- a/drivers/usb/usbip/vudc_dev.c +++ b/drivers/usb/usbip/vudc_dev.c @@ -297,7 +297,8 @@ static void vep_free_request(struct usb_ep *_ep, struct usb_request *_req) { struct vrequest *req; - if (WARN_ON(!_ep || !_req)) + /* ep is always valid here - see usb_ep_free_request() */ + if (!_req) return; req = to_vrequest(_req); diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig index 348de1d6726e..12e89189ca7d 100644 --- a/drivers/usb/wusbcore/Kconfig +++ b/drivers/usb/wusbcore/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Wireless USB Core configuration # diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c index 222228c5c1e1..af77064c7456 100644 --- a/drivers/usb/wusbcore/cbaf.c +++ b/drivers/usb/wusbcore/cbaf.c @@ -302,10 +302,8 @@ static ssize_t cbaf_wusb_chid_show(struct device *dev, { struct usb_interface *iface = to_usb_interface(dev); struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_chid[WUSB_CKHDID_STRSIZE]; - ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_chid); + return sprintf(buf, "%16ph\n", cbaf->chid.data); } static ssize_t cbaf_wusb_chid_store(struct device *dev, @@ -415,10 +413,8 @@ static ssize_t cbaf_wusb_cdid_show(struct device *dev, { struct usb_interface *iface = to_usb_interface(dev); struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_cdid[WUSB_CKHDID_STRSIZE]; - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_cdid); + return sprintf(buf, "%16ph\n", cbaf->cdid.data); } static ssize_t cbaf_wusb_cdid_store(struct device *dev, @@ -503,7 +499,6 @@ static int cbaf_cc_upload(struct cbaf *cbaf) int result; struct device *dev = &cbaf->usb_iface->dev; struct wusb_cbaf_cc_data *ccd; - char pr_cdid[WUSB_CKHDID_STRSIZE]; ccd = cbaf->buffer; *ccd = cbaf_cc_data_defaults; @@ -513,10 +508,8 @@ static int cbaf_cc_upload(struct cbaf *cbaf) ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups); dev_dbg(dev, "Trying to upload CC:\n"); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID); - dev_dbg(dev, " CHID %s\n", pr_cdid); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID); - dev_dbg(dev, " CDID %s\n", pr_cdid); + dev_dbg(dev, " CHID %16ph\n", ccd->CHID.data); + dev_dbg(dev, " CDID %16ph\n", ccd->CDID.data); dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups); result = usb_control_msg( diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 68ddee86a886..edb7263bff40 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -316,7 +316,7 @@ ssize_t wusb_prf(void *out, size_t out_size, goto error_setkey_cbc; } - tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + tfm_aes = crypto_alloc_cipher("aes", 0, 0); if (IS_ERR(tfm_aes)) { result = PTR_ERR(tfm_aes); printk(KERN_ERR "E: can't load AES: %d\n", (int)result); diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c index 85a1acf3a729..67b0a4c412b2 100644 --- a/drivers/usb/wusbcore/dev-sysfs.c +++ b/drivers/usb/wusbcore/dev-sysfs.c @@ -50,10 +50,9 @@ static ssize_t wusb_cdid_show(struct device *dev, wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev)); if (wusb_dev == NULL) return -ENODEV; - result = ckhdid_printf(buf, PAGE_SIZE, &wusb_dev->cdid); - strcat(buf, "\n"); + result = sprintf(buf, "%16ph\n", wusb_dev->cdid.data); wusb_dev_put(wusb_dev); - return result + 1; + return result; } static DEVICE_ATTR_RO(wusb_cdid); diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index fcb06aef2675..a93837d57d53 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -532,7 +532,7 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, } dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &dnc->CDID); + sprintf(pr_cdid, "%16ph", dnc->CDID.data); dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n", pr_cdid, wusb_dn_connect_prev_dev_addr(dnc), diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 01f2f21830c0..abf88cea37bb 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -662,9 +662,9 @@ static void __wa_setup_isoc_packet_descr( /* populate isoc packet descriptor. */ packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO; - packet_desc->wLength = cpu_to_le16(sizeof(*packet_desc) + - (sizeof(packet_desc->PacketLength[0]) * - seg->isoc_frame_count)); + packet_desc->wLength = cpu_to_le16(struct_size(packet_desc, + PacketLength, + seg->isoc_frame_count)); for (frame_index = 0; frame_index < seg->isoc_frame_count; ++frame_index) { int offset_index = frame_index + seg->isoc_frame_offset; @@ -2438,7 +2438,7 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb) struct wa_rpipe *rpipe; unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index; unsigned first_frame_index = 0, rpipe_ready = 0; - int expected_size; + size_t expected_size; /* We have a xfer result buffer; check it */ dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n", @@ -2460,11 +2460,10 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb) goto error_bad_seg; seg = xfer->seg[wa->dti_isoc_xfer_seg]; rpipe = xfer->ep->hcpriv; - expected_size = sizeof(*packet_status) + - (sizeof(packet_status->PacketStatus[0]) * - seg->isoc_frame_count); + expected_size = struct_size(packet_status, PacketStatus, + seg->isoc_frame_count); if (urb->actual_length != expected_size) { - dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %d needed)\n", + dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %zu needed)\n", urb->actual_length, expected_size); goto error_bad_seg; } diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index e5ba6140c1ba..d0b404d258e8 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -80,17 +80,13 @@ static ssize_t wusb_chid_show(struct device *dev, { struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); const struct wusb_ckhdid *chid; - ssize_t result = 0; if (wusbhc->wuie_host_info != NULL) chid = &wusbhc->wuie_host_info->CHID; else chid = &wusb_ckhdid_zero; - result += ckhdid_printf(buf, PAGE_SIZE, chid); - result += sprintf(buf + result, "\n"); - - return result; + return sprintf(buf, "%16ph\n", chid->data); } /* |