From d6759133e9815ef807b17dc752aff8c3771b7444 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 24 Jun 2014 17:14:42 +0300 Subject: [PATCH 001/211] usb: xhci: Correct last context entry calculation for Configure Endpoint The current XHCI driver recalculates the Context Entries field in the Slot Context on every add_endpoint() and drop_endpoint() call. In the case of drop_endpoint(), it seems to assume that the add_flags will always contain every endpoint for the new configuration, which is not necessarily correct if you don't make assumptions about how the USB core uses the add_endpoint/drop_endpoint interface (add_flags only contains endpoints that are new additions in the new configuration). Furthermore, EP0_FLAG is not consistently set in add_flags throughout the lifetime of a device. This means that when all endpoints are dropped, the Context Entries field can be set to 0 (which is invalid and may cause a Parameter Error) or -1 (which is interpreted as 31 and causes the driver to keep using the old, incorrect value). The only surefire way to set this field right is to also take all existing endpoints into account, and to force the value to 1 (meaning only EP0 is active) if no other endpoint is found. This patch implements that as a single step in the final check_bandwidth() call and removes the intermediary calculations from add_endpoint() and drop_endpoint(). Signed-off-by: Julius Werner Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 51 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 2b8d9a24af09..013aabb5b379 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1582,12 +1582,10 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct xhci_hcd *xhci; struct xhci_container_ctx *in_ctx, *out_ctx; struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_slot_ctx *slot_ctx; - unsigned int last_ctx; unsigned int ep_index; struct xhci_ep_ctx *ep_ctx; u32 drop_flag; - u32 new_add_flags, new_drop_flags, new_slot_info; + u32 new_add_flags, new_drop_flags; int ret; ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); @@ -1634,24 +1632,13 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, ctrl_ctx->add_flags &= cpu_to_le32(~drop_flag); new_add_flags = le32_to_cpu(ctrl_ctx->add_flags); - last_ctx = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags)); - slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); - /* Update the last valid endpoint context, if we deleted the last one */ - if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) > - LAST_CTX(last_ctx)) { - slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx)); - } - new_slot_info = le32_to_cpu(slot_ctx->dev_info); - xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); - xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", + xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, (unsigned int) new_drop_flags, - (unsigned int) new_add_flags, - (unsigned int) new_slot_info); + (unsigned int) new_add_flags); return 0; } @@ -1674,11 +1661,9 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct xhci_hcd *xhci; struct xhci_container_ctx *in_ctx, *out_ctx; unsigned int ep_index; - struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; u32 added_ctxs; - unsigned int last_ctx; - u32 new_add_flags, new_drop_flags, new_slot_info; + u32 new_add_flags, new_drop_flags; struct xhci_virt_device *virt_dev; int ret = 0; @@ -1693,7 +1678,6 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return -ENODEV; added_ctxs = xhci_get_endpoint_flag(&ep->desc); - last_ctx = xhci_last_valid_endpoint(added_ctxs); if (added_ctxs == SLOT_FLAG || added_ctxs == EP0_FLAG) { /* FIXME when we have to issue an evaluate endpoint command to * deal with ep0 max packet size changing once we get the @@ -1759,24 +1743,14 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, */ new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags); - slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); - /* Update the last valid endpoint context, if we just added one past */ - if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) < - LAST_CTX(last_ctx)) { - slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx)); - } - new_slot_info = le32_to_cpu(slot_ctx->dev_info); - /* Store the usb_device pointer for later use */ ep->hcpriv = udev; - xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", + xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, (unsigned int) new_drop_flags, - (unsigned int) new_add_flags, - (unsigned int) new_slot_info); + (unsigned int) new_add_flags); return 0; } @@ -2746,8 +2720,19 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ret = 0; goto command_cleanup; } - xhci_dbg(xhci, "New Input Control Context:\n"); + /* Fix up Context Entries field. Minimum value is EP0 == BIT(1). */ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); + for (i = 31; i >= 1; i--) { + __le32 le32 = cpu_to_le32(BIT(i)); + + if ((virt_dev->eps[i-1].ring && !(ctrl_ctx->drop_flags & le32)) + || (ctrl_ctx->add_flags & le32) || i == 1) { + slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); + slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(i)); + break; + } + } + xhci_dbg(xhci, "New Input Control Context:\n"); xhci_dbg_ctx(xhci, virt_dev->in_ctx, LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info))); From fc7af215f9151316e9b4ce261f52043966f06976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Mon, 30 Jun 2014 13:17:26 +0200 Subject: [PATCH 002/211] usb: musb: dsps: coding style cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no reason for the register accessor functions not to adhere to the CodingStyle rules. Signed-off-by: Lothar Waßmann Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 51beb13c7e1a..56c5d3fd6f6c 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -56,16 +56,24 @@ static const struct of_device_id musb_dsps_of_match[]; * dependent on musb core layer symbols. */ static inline u8 dsps_readb(const void __iomem *addr, unsigned offset) - { return __raw_readb(addr + offset); } +{ + return __raw_readb(addr + offset); +} static inline u32 dsps_readl(const void __iomem *addr, unsigned offset) - { return __raw_readl(addr + offset); } +{ + return __raw_readl(addr + offset); +} static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data) - { __raw_writeb(data, addr + offset); } +{ + __raw_writeb(data, addr + offset); +} static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data) - { __raw_writel(data, addr + offset); } +{ + __raw_writel(data, addr + offset); +} /** * DSPS musb wrapper register offset. From c63d2225e7be975357164871e996805003e5e735 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 22 Jun 2014 12:47:51 +0530 Subject: [PATCH 003/211] usb: gadget: pxa25x_udc: use devm_ functions This patch introduces the use of devm_request_irq, devm_gpio_request, devm_clk_get etc. instead of the corresponding unmanaged interfaces. The calls to the functions like free_irq to free the allocated resources are removed as they are no longer required. Some labels in the probe function are also done away with and the name of the label err_gpio_pullup is changed to make it less specific to the context. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/gadget/pxa25x_udc.c | 73 ++++++++++----------------------- 1 file changed, 22 insertions(+), 51 deletions(-) diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 9984437d2952..f1a5cdcd70ff 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -2105,11 +2105,9 @@ static int pxa25x_udc_probe(struct platform_device *pdev) if (irq < 0) return -ENODEV; - dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) { - retval = PTR_ERR(dev->clk); - goto err_clk; - } + dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); pr_debug("%s: IRQ %d%s%s\n", driver_name, irq, dev->has_cfr ? "" : " (!cfr)", @@ -2120,15 +2118,16 @@ static int pxa25x_udc_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->mach = dev_get_platdata(&pdev->dev); - dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + dev->transceiver = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (gpio_is_valid(dev->mach->gpio_pullup)) { - if ((retval = gpio_request(dev->mach->gpio_pullup, - "pca25x_udc GPIO PULLUP"))) { + retval = devm_gpio_request(&pdev->dev, dev->mach->gpio_pullup, + "pca25x_udc GPIO PULLUP"); + if (retval) { dev_dbg(&pdev->dev, "can't get pullup gpio %d, err: %d\n", dev->mach->gpio_pullup, retval); - goto err_gpio_pullup; + goto err; } gpio_direction_output(dev->mach->gpio_pullup, 0); } @@ -2146,30 +2145,32 @@ static int pxa25x_udc_probe(struct platform_device *pdev) dev->vbus = 0; /* irq setup after old hardware state is cleaned up */ - retval = request_irq(irq, pxa25x_udc_irq, - 0, driver_name, dev); + retval = devm_request_irq(&pdev->dev, irq, pxa25x_udc_irq, 0, + driver_name, dev); if (retval != 0) { pr_err("%s: can't get irq %d, err %d\n", driver_name, irq, retval); - goto err_irq1; + goto err; } dev->got_irq = 1; #ifdef CONFIG_ARCH_LUBBOCK if (machine_is_lubbock()) { - retval = request_irq(LUBBOCK_USB_DISC_IRQ, lubbock_vbus_irq, - 0, driver_name, dev); + retval = devm_request_irq(&pdev->dev, LUBBOCK_USB_DISC_IRQ, + lubbock_vbus_irq, 0, driver_name, + dev); if (retval != 0) { pr_err("%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_DISC_IRQ, retval); - goto err_irq_lub; + goto err; } - retval = request_irq(LUBBOCK_USB_IRQ, lubbock_vbus_irq, - 0, driver_name, dev); + retval = devm_request_irq(&pdev->dev, LUBBOCK_USB_IRQ, + lubbock_vbus_irq, 0, driver_name, + dev); if (retval != 0) { pr_err("%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_IRQ, retval); - goto lubbock_fail0; + goto err; } } else #endif @@ -2180,22 +2181,9 @@ static int pxa25x_udc_probe(struct platform_device *pdev) return retval; remove_debug_files(dev); -#ifdef CONFIG_ARCH_LUBBOCK -lubbock_fail0: - free_irq(LUBBOCK_USB_DISC_IRQ, dev); - err_irq_lub: - free_irq(irq, dev); -#endif - err_irq1: - if (gpio_is_valid(dev->mach->gpio_pullup)) - gpio_free(dev->mach->gpio_pullup); - err_gpio_pullup: - if (!IS_ERR_OR_NULL(dev->transceiver)) { - usb_put_phy(dev->transceiver); + err: + if (!IS_ERR_OR_NULL(dev->transceiver)) dev->transceiver = NULL; - } - clk_put(dev->clk); - err_clk: return retval; } @@ -2217,25 +2205,8 @@ static int pxa25x_udc_remove(struct platform_device *pdev) remove_debug_files(dev); - if (dev->got_irq) { - free_irq(platform_get_irq(pdev, 0), dev); - dev->got_irq = 0; - } -#ifdef CONFIG_ARCH_LUBBOCK - if (machine_is_lubbock()) { - free_irq(LUBBOCK_USB_DISC_IRQ, dev); - free_irq(LUBBOCK_USB_IRQ, dev); - } -#endif - if (gpio_is_valid(dev->mach->gpio_pullup)) - gpio_free(dev->mach->gpio_pullup); - - clk_put(dev->clk); - - if (!IS_ERR_OR_NULL(dev->transceiver)) { - usb_put_phy(dev->transceiver); + if (!IS_ERR_OR_NULL(dev->transceiver)) dev->transceiver = NULL; - } the_controller = NULL; return 0; From d7dc5bde6d7f26a19e9792b7952fd61f875373fe Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sat, 21 Jun 2014 02:10:25 +0530 Subject: [PATCH 004/211] usb: musb: ux500: use devm_ functions This patch introduces the use of managed interfaces for clk_get and kzalloc and removes the corresponding free function calls in the probe and remove functions. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/musb/ux500.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index c2e45e632723..f18c03795ed5 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -246,7 +246,7 @@ static int ux500_probe(struct platform_device *pdev) } } - glue = kzalloc(sizeof(*glue), GFP_KERNEL); + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&pdev->dev, "failed to allocate glue context\n"); goto err0; @@ -255,20 +255,20 @@ static int ux500_probe(struct platform_device *pdev) musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err0; } - clk = clk_get(&pdev->dev, NULL); + clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); ret = PTR_ERR(clk); - goto err3; + goto err1; } ret = clk_prepare_enable(clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); - goto err4; + goto err1; } musb->dev.parent = &pdev->dev; @@ -302,34 +302,28 @@ static int ux500_probe(struct platform_device *pdev) ARRAY_SIZE(musb_resources)); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err5; + goto err2; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err5; + goto err2; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err5; + goto err2; } return 0; -err5: +err2: clk_disable_unprepare(clk); -err4: - clk_put(clk); - -err3: - platform_device_put(musb); - err1: - kfree(glue); + platform_device_put(musb); err0: return ret; @@ -341,8 +335,6 @@ static int ux500_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); clk_disable_unprepare(glue->clk); - clk_put(glue->clk); - kfree(glue); return 0; } From 492240b0a7d41db69d463a77306451e91b8f80a1 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:42:44 +0900 Subject: [PATCH 005/211] usb: phy: msm: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-msm-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index ced34f39bdd4..625c14494c9a 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1427,7 +1427,7 @@ static void msm_otg_debugfs_cleanup(void) debugfs_remove(msm_otg_dbg_root); } -static struct of_device_id msm_otg_dt_match[] = { +static const struct of_device_id msm_otg_dt_match[] = { { .compatible = "qcom,usb-otg-ci", .data = (void *) CI_45NM_INTEGRATED_PHY From 0f0520ba83e6eeeadfabb2b8750b9616219810ad Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:43:50 +0900 Subject: [PATCH 006/211] usb: phy: tegra: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index bbe4f8e6e8d7..cd36cb43ecc0 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -965,7 +965,7 @@ static const struct tegra_phy_soc_config tegra30_soc_config = { .requires_extra_tuning_parameters = true, }; -static struct of_device_id tegra_usb_phy_id_table[] = { +static const struct of_device_id tegra_usb_phy_id_table[] = { { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config }, { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config }, { }, From 61107d9f1b4a61ea9cc615d3b510545b292ead15 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:40:31 +0900 Subject: [PATCH 007/211] usb: gadget: gr_udc: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Acked-by: Andreas Larsson Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/gr_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index 99a37ed03e27..5d93f2b1e394 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -2212,7 +2212,7 @@ static int gr_probe(struct platform_device *pdev) return retval; } -static struct of_device_id gr_match[] = { +static const struct of_device_id gr_match[] = { {.name = "GAISLER_USBDC"}, {.name = "01_021"}, {}, From ca118b78da329ee22d3072f1844f3e37375e94ac Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:41:39 +0900 Subject: [PATCH 008/211] usb: gadget: lpc32xx_udc: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/lpc32xx_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index e471580a2a3b..c77c6872b3ef 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -3397,7 +3397,7 @@ static int lpc32xx_udc_resume(struct platform_device *pdev) #endif #ifdef CONFIG_OF -static struct of_device_id lpc32xx_udc_of_match[] = { +static const struct of_device_id lpc32xx_udc_of_match[] = { { .compatible = "nxp,lpc3220-udc", }, { }, }; From e1815053d6c3c4e2d89be0837509a76afadcc336 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:14:54 +0100 Subject: [PATCH 009/211] usb: gadget: r8a66597-udc: use devm_ioremap_resource() for registers trivial patch removing boilerplate clode. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index b698a490cc7d..4e86ec5cbecf 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1826,7 +1826,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev) usb_del_gadget_udc(&r8a66597->gadget); del_timer_sync(&r8a66597->timer); - iounmap(r8a66597->reg); if (r8a66597->pdata->sudmac) iounmap(r8a66597->sudmac_reg); free_irq(platform_get_irq(pdev, 0), r8a66597); @@ -1877,11 +1876,9 @@ static int __init r8a66597_probe(struct platform_device *pdev) unsigned long irq_trigger; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_err(&pdev->dev, "platform_get_resource error.\n"); - goto clean_up; - } + reg = devm_ioremap_resource(&pdev->dev, res); + if (!reg) + return -ENODEV; ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = ires->start; @@ -1893,13 +1890,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) goto clean_up; } - reg = ioremap(res->start, resource_size(res)); - if (reg == NULL) { - ret = -ENOMEM; - dev_err(&pdev->dev, "ioremap error.\n"); - goto clean_up; - } - /* initialize ucd */ r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); if (r8a66597 == NULL) { @@ -2007,8 +1997,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->ep0_req); kfree(r8a66597); } - if (reg) - iounmap(reg); return ret; } From f390f57c91c9c948c36ee2a5c65d2339cbfe1b37 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:14:55 +0100 Subject: [PATCH 010/211] usb: gadget: r8a66597-udc: keep dev as reference to &pdev->dev Remove usages of &pdev->dev in the driver probe function with just dev to make the references to it easier to write. Convert all the current users of it to use it. Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 4e86ec5cbecf..78f855ffb1da 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1866,6 +1866,7 @@ static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, static int __init r8a66597_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; char clk_name[8]; struct resource *res, *ires; int irq; @@ -1886,7 +1887,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) if (irq < 0) { ret = -ENODEV; - dev_err(&pdev->dev, "platform_get_irq error.\n"); + dev_err(dev, "platform_get_irq error.\n"); goto clean_up; } @@ -1899,7 +1900,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) spin_lock_init(&r8a66597->lock); platform_set_drvdata(pdev, r8a66597); - r8a66597->pdata = dev_get_platdata(&pdev->dev); + r8a66597->pdata = dev_get_platdata(dev); r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; r8a66597->gadget.ops = &r8a66597_gadget_ops; @@ -1913,10 +1914,9 @@ static int __init r8a66597_probe(struct platform_device *pdev) if (r8a66597->pdata->on_chip) { snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id); - r8a66597->clk = clk_get(&pdev->dev, clk_name); + r8a66597->clk = clk_get(dev, clk_name); if (IS_ERR(r8a66597->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", - clk_name); + dev_err(dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(r8a66597->clk); goto clean_up; } @@ -1934,7 +1934,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) ret = request_irq(irq, r8a66597_irq, IRQF_SHARED, udc_name, r8a66597); if (ret < 0) { - dev_err(&pdev->dev, "request_irq error (%d)\n", ret); + dev_err(dev, "request_irq error (%d)\n", ret); goto clean_up2; } @@ -1972,11 +1972,11 @@ static int __init r8a66597_probe(struct platform_device *pdev) } r8a66597->ep0_req->complete = nop_completion; - ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget); + ret = usb_add_gadget_udc(dev, &r8a66597->gadget); if (ret) goto err_add_udc; - dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); + dev_info(dev, "version %s\n", DRIVER_VERSION); return 0; err_add_udc: From 531bc938f9c54c5c0998ec537195ed4a3c74a608 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:14:56 +0100 Subject: [PATCH 011/211] usb: gadget: r8a66597-udc: use devm_kzalloc() to allocate driver state Update driver to use devm_kzalloc() to make tracking of resources easier. Also remove the exit point via cleanup as there's no cleanup necessary from this point now. As a note, also removes the error print as the allocation calls produce errors if they do not return memory. Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 78f855ffb1da..48a9e0bbe6a6 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1836,7 +1836,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev) clk_put(r8a66597->clk); } - kfree(r8a66597); return 0; } @@ -1892,11 +1891,9 @@ static int __init r8a66597_probe(struct platform_device *pdev) } /* initialize ucd */ - r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); - if (r8a66597 == NULL) { - ret = -ENOMEM; - goto clean_up; - } + r8a66597 = devm_kzalloc(dev, sizeof(struct r8a66597), GFP_KERNEL); + if (r8a66597 == NULL) + return -ENOMEM; spin_lock_init(&r8a66597->lock); platform_set_drvdata(pdev, r8a66597); @@ -1995,7 +1992,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) if (r8a66597->ep0_req) r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); - kfree(r8a66597); } return ret; From 9a6d5d4475d8c0ef5e59fecf9f425e786a914dbc Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:14:57 +0100 Subject: [PATCH 012/211] usb: gadget: r8a66597-udc: handle sudmac registers with devm_ioremap_resource() Change the sudmac register handling in the devm_ioremap_resource to use the devm variant. Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 48a9e0bbe6a6..2662853d96f4 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1826,8 +1826,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev) usb_del_gadget_udc(&r8a66597->gadget); del_timer_sync(&r8a66597->timer); - if (r8a66597->pdata->sudmac) - iounmap(r8a66597->sudmac_reg); free_irq(platform_get_irq(pdev, 0), r8a66597); r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); @@ -1849,15 +1847,10 @@ static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, struct resource *res; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac"); - if (!res) { - dev_err(&pdev->dev, "platform_get_resource error(sudmac).\n"); - return -ENODEV; - } - - r8a66597->sudmac_reg = ioremap(res->start, resource_size(res)); - if (r8a66597->sudmac_reg == NULL) { + r8a66597->sudmac_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(r8a66597->sudmac_reg)) { dev_err(&pdev->dev, "ioremap error(sudmac).\n"); - return -ENOMEM; + return PTR_ERR(r8a66597->sudmac_reg); } return 0; @@ -1987,8 +1980,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) } clean_up: if (r8a66597) { - if (r8a66597->sudmac_reg) - iounmap(r8a66597->sudmac_reg); if (r8a66597->ep0_req) r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); From 776976a67ae25d18be42794fd783a50757402cbe Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:14:58 +0100 Subject: [PATCH 013/211] usb: gadget: r8a66597-udc: cleanup error path With the updates for devm, the cleanup path no longer needs to check for NULL device state, so remove it and return directly if the irq resource missing Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 2662853d96f4..9ebe2c0b75a5 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1878,9 +1878,8 @@ static int __init r8a66597_probe(struct platform_device *pdev) irq_trigger = ires->flags & IRQF_TRIGGER_MASK; if (irq < 0) { - ret = -ENODEV; dev_err(dev, "platform_get_irq error.\n"); - goto clean_up; + return -ENODEV; } /* initialize ucd */ @@ -1979,11 +1978,8 @@ static int __init r8a66597_probe(struct platform_device *pdev) clk_put(r8a66597->clk); } clean_up: - if (r8a66597) { - if (r8a66597->ep0_req) - r8a66597_free_request(&r8a66597->ep[0].ep, - r8a66597->ep0_req); - } + if (r8a66597->ep0_req) + r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); return ret; } From 3d7037b76ba81a35daf627391b67be6463e56353 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:14:59 +0100 Subject: [PATCH 014/211] usb: gadget: r8a66597-udc: use devm_clk_get() to get clock Change to using the devm_clk_get() to get the clock and have it automatically freed on exit. Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 9ebe2c0b75a5..51eaedda2bb5 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1831,7 +1831,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev) if (r8a66597->pdata->on_chip) { clk_disable_unprepare(r8a66597->clk); - clk_put(r8a66597->clk); } return 0; @@ -1903,11 +1902,10 @@ static int __init r8a66597_probe(struct platform_device *pdev) if (r8a66597->pdata->on_chip) { snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id); - r8a66597->clk = clk_get(dev, clk_name); + r8a66597->clk = devm_clk_get(dev, clk_name); if (IS_ERR(r8a66597->clk)) { dev_err(dev, "cannot get clock \"%s\"\n", clk_name); - ret = PTR_ERR(r8a66597->clk); - goto clean_up; + return PTR_ERR(r8a66597->clk); } clk_prepare_enable(r8a66597->clk); } @@ -1973,10 +1971,8 @@ static int __init r8a66597_probe(struct platform_device *pdev) clean_up3: free_irq(irq, r8a66597); clean_up2: - if (r8a66597->pdata->on_chip) { + if (r8a66597->pdata->on_chip) clk_disable_unprepare(r8a66597->clk); - clk_put(r8a66597->clk); - } clean_up: if (r8a66597->ep0_req) r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); From 4b526951c356c9270f1737ca4e100e9b420d8223 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:15:00 +0100 Subject: [PATCH 015/211] usb: gadget: r8a66597-udc: use devm_request_irq() to get device irq Use the devm_request_irq() call to get the interrupt for the device and have it automatically free on exit. Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 51eaedda2bb5..8414ba501d7c 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1826,7 +1826,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev) usb_del_gadget_udc(&r8a66597->gadget); del_timer_sync(&r8a66597->timer); - free_irq(platform_get_irq(pdev, 0), r8a66597); r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); if (r8a66597->pdata->on_chip) { @@ -1918,8 +1917,8 @@ static int __init r8a66597_probe(struct platform_device *pdev) disable_controller(r8a66597); /* make sure controller is disabled */ - ret = request_irq(irq, r8a66597_irq, IRQF_SHARED, - udc_name, r8a66597); + ret = devm_request_irq(dev, irq, r8a66597_irq, IRQF_SHARED, + udc_name, r8a66597); if (ret < 0) { dev_err(dev, "request_irq error (%d)\n", ret); goto clean_up2; @@ -1969,7 +1968,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) err_add_udc: r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); clean_up3: - free_irq(irq, r8a66597); clean_up2: if (r8a66597->pdata->on_chip) clk_disable_unprepare(r8a66597->clk); From 885162d171841ed7c7b25f26e72ca6def5cdfc4d Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 17 Jun 2014 16:15:01 +0100 Subject: [PATCH 016/211] usb: gadget: r8a66597-udc: remove now unused clean_up and clean_up3 label. With the devm additions, the clean_up and clean_up3 are now not needed or used. Change clean_up3 and make everything use clean_up2 and just remove clean_up. Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 8414ba501d7c..6ad60286ceb3 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1954,7 +1954,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) GFP_KERNEL); if (r8a66597->ep0_req == NULL) { ret = -ENOMEM; - goto clean_up3; + goto clean_up2; } r8a66597->ep0_req->complete = nop_completion; @@ -1967,11 +1967,10 @@ static int __init r8a66597_probe(struct platform_device *pdev) err_add_udc: r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); -clean_up3: clean_up2: if (r8a66597->pdata->on_chip) clk_disable_unprepare(r8a66597->clk); -clean_up: + if (r8a66597->ep0_req) r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); From 7b0a12ab2e49379d7c6754996446020e117eef0b Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sat, 14 Jun 2014 20:48:27 +0530 Subject: [PATCH 017/211] usb: gadget: fsl_qe_udc: Introduce use of managed version of kzalloc This patch moves data allocated using kzalloc to managed data allocated using devm_kzalloc and cleans now unnecessary kfrees in probe and remove functions. Also, the unnecesary labels are removed and some labels are renamed to preserve ordering. The following Coccinelle semantic patch was used for making the change: @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } Signed-off-by: Himangi Saraogi Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fsl_qe_udc.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index ad5483335167..732430804841 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2539,7 +2539,7 @@ static int qe_udc_probe(struct platform_device *ofdev) goto err2; /* create a buf for ZLP send, need to remain zeroed */ - udc->nullbuf = kzalloc(256, GFP_KERNEL); + udc->nullbuf = devm_kzalloc(&ofdev->dev, 256, GFP_KERNEL); if (udc->nullbuf == NULL) { dev_err(udc->dev, "cannot alloc nullbuf\n"); ret = -ENOMEM; @@ -2547,10 +2547,10 @@ static int qe_udc_probe(struct platform_device *ofdev) } /* buffer for data of get_status request */ - udc->statusbuf = kzalloc(2, GFP_KERNEL); + udc->statusbuf = devm_kzalloc(&ofdev->dev, 2, GFP_KERNEL); if (udc->statusbuf == NULL) { ret = -ENOMEM; - goto err4; + goto err3; } udc->nullp = virt_to_phys((void *)udc->nullbuf); @@ -2581,13 +2581,13 @@ static int qe_udc_probe(struct platform_device *ofdev) if (ret) { dev_err(udc->dev, "cannot request irq %d err %d\n", udc->usb_irq, ret); - goto err5; + goto err4; } ret = usb_add_gadget_udc_release(&ofdev->dev, &udc->gadget, qe_udc_release); if (ret) - goto err6; + goto err5; platform_set_drvdata(ofdev, udc); dev_info(udc->dev, @@ -2595,9 +2595,9 @@ static int qe_udc_probe(struct platform_device *ofdev) (udc->soc_type == PORT_QE) ? "QE" : "CPM"); return 0; -err6: - free_irq(udc->usb_irq, udc); err5: + free_irq(udc->usb_irq, udc); +err4: irq_dispose_mapping(udc->usb_irq); err_noirq: if (udc->nullmap) { @@ -2610,9 +2610,6 @@ static int qe_udc_probe(struct platform_device *ofdev) udc->nullp, 256, DMA_TO_DEVICE); } - kfree(udc->statusbuf); -err4: - kfree(udc->nullbuf); err3: ep = &udc->eps[0]; cpm_muram_free(cpm_muram_offset(ep->rxbase)); @@ -2660,8 +2657,6 @@ static int qe_udc_remove(struct platform_device *ofdev) udc->nullp, 256, DMA_TO_DEVICE); } - kfree(udc->statusbuf); - kfree(udc->nullbuf); ep = &udc->eps[0]; cpm_muram_free(cpm_muram_offset(ep->rxbase)); From f32a5e2325caf3dd0d720932cc241d8ba22875a8 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Wed, 4 Jun 2014 14:34:52 +0530 Subject: [PATCH 018/211] usb: dwc3: Keeping 'resource' related code together Putting together the code related to getting the 'IORESOURCE_MEM' and assigning the same to dwc->xhci_resources, for increasing the readability. Signed-off-by: Vivek Gautam Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 44 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index eb69eb9f06c8..fbe446350e28 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -656,6 +656,31 @@ static int dwc3_probe(struct platform_device *pdev) return -ENODEV; } + dwc->xhci_resources[0].start = res->start; + dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + + DWC3_XHCI_REGS_END; + dwc->xhci_resources[0].flags = res->flags; + dwc->xhci_resources[0].name = res->name; + + res->start += DWC3_GLOBALS_REGS_START; + + /* + * Request memory region but exclude xHCI regs, + * since it will be requested by the xhci-plat driver. + */ + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + dwc->regs = regs; + dwc->regs_size = resource_size(res); + /* + * restore res->start back to its original value so that, + * in case the probe is deferred, we don't end up getting error in + * request the memory region the next time probe is called. + */ + res->start -= DWC3_GLOBALS_REGS_START; + if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); @@ -676,28 +701,9 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) return ret; - dwc->xhci_resources[0].start = res->start; - dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + - DWC3_XHCI_REGS_END; - dwc->xhci_resources[0].flags = res->flags; - dwc->xhci_resources[0].name = res->name; - - res->start += DWC3_GLOBALS_REGS_START; - - /* - * Request memory region but exclude xHCI regs, - * since it will be requested by the xhci-plat driver. - */ - regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) - return PTR_ERR(regs); - spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); - dwc->regs = regs; - dwc->regs_size = resource_size(res); - dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); From 9f7b23ce88e9eb1194485b3399dfc83c24fb3634 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 4 Jun 2014 02:49:53 +0530 Subject: [PATCH 019/211] usb: phy: phy-gpio-vbus-usb: use devm_ functions The various devm_ functions allocate memory that is released when a driver detaches. This patch uses devm_kzalloc, devm_request_irq, devm_gpio_request, devm_regulator_get etc. for data that is allocated in the probe function of a platform device and is only freed in the remove function. The corresponding free functions are removed and the labels are done away with. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-gpio-vbus-usb.c | 45 +++++++++-------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 69462e09d014..ea9e705555df 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -253,11 +253,13 @@ static int gpio_vbus_probe(struct platform_device *pdev) return -EINVAL; gpio = pdata->gpio_vbus; - gpio_vbus = kzalloc(sizeof(struct gpio_vbus_data), GFP_KERNEL); + gpio_vbus = devm_kzalloc(&pdev->dev, sizeof(struct gpio_vbus_data), + GFP_KERNEL); if (!gpio_vbus) return -ENOMEM; - gpio_vbus->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL); + gpio_vbus->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), + GFP_KERNEL); if (!gpio_vbus->phy.otg) { kfree(gpio_vbus); return -ENOMEM; @@ -274,11 +276,11 @@ static int gpio_vbus_probe(struct platform_device *pdev) gpio_vbus->phy.otg->phy = &gpio_vbus->phy; gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral; - err = gpio_request(gpio, "vbus_detect"); + err = devm_gpio_request(&pdev->dev, gpio, "vbus_detect"); if (err) { dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n", gpio, err); - goto err_gpio; + return err; } gpio_direction_input(gpio); @@ -296,27 +298,27 @@ static int gpio_vbus_probe(struct platform_device *pdev) /* if data line pullup is in use, initialize it to "not pulling up" */ gpio = pdata->gpio_pullup; if (gpio_is_valid(gpio)) { - err = gpio_request(gpio, "udc_pullup"); + err = devm_gpio_request(&pdev->dev, gpio, "udc_pullup"); if (err) { dev_err(&pdev->dev, "can't request pullup gpio %d, err: %d\n", gpio, err); - gpio_free(pdata->gpio_vbus); - goto err_gpio; + return err; } gpio_direction_output(gpio, pdata->gpio_pullup_inverted); } - err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev); + err = devm_request_irq(&pdev->dev, irq, gpio_vbus_irq, irqflags, + "vbus_detect", pdev); if (err) { dev_err(&pdev->dev, "can't request irq %i, err: %d\n", irq, err); - goto err_irq; + return err; } INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); - gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw"); + gpio_vbus->vbus_draw = devm_regulator_get(&pdev->dev, "vbus_draw"); if (IS_ERR(gpio_vbus->vbus_draw)) { dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n", PTR_ERR(gpio_vbus->vbus_draw)); @@ -328,44 +330,23 @@ static int gpio_vbus_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "can't register transceiver, err: %d\n", err); - goto err_otg; + return err; } device_init_wakeup(&pdev->dev, pdata->wakeup); return 0; -err_otg: - regulator_put(gpio_vbus->vbus_draw); - free_irq(irq, pdev); -err_irq: - if (gpio_is_valid(pdata->gpio_pullup)) - gpio_free(pdata->gpio_pullup); - gpio_free(pdata->gpio_vbus); -err_gpio: - kfree(gpio_vbus->phy.otg); - kfree(gpio_vbus); - return err; } static int gpio_vbus_remove(struct platform_device *pdev) { struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); - struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); - int gpio = pdata->gpio_vbus; device_init_wakeup(&pdev->dev, 0); cancel_delayed_work_sync(&gpio_vbus->work); - regulator_put(gpio_vbus->vbus_draw); usb_remove_phy(&gpio_vbus->phy); - free_irq(gpio_vbus->irq, pdev); - if (gpio_is_valid(pdata->gpio_pullup)) - gpio_free(pdata->gpio_pullup); - gpio_free(gpio); - kfree(gpio_vbus->phy.otg); - kfree(gpio_vbus); - return 0; } From 276f146a492d45a6384caade9f35cc712f07ca05 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Mon, 2 Jun 2014 21:56:01 +0530 Subject: [PATCH 020/211] usb: musb: davinci: use devm_ functions. This patch moves data allocated using kzalloc to managed data allocated using devm_kzalloc and cleans now unnecessary kfrees in probe and remove functions. Also, a label is done away with and clk_get is replaced by it corresponding devm version and the clk_puts are done away with. The labels are renamed to make them ordered. The following Coccinelle semantic patch was used for making the change: @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/musb/davinci.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index de8492b06e46..110b78415bf0 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -519,23 +519,23 @@ static int davinci_probe(struct platform_device *pdev) int ret = -ENOMEM; - glue = kzalloc(sizeof(*glue), GFP_KERNEL); + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&pdev->dev, "failed to allocate glue context\n"); goto err0; } - clk = clk_get(&pdev->dev, "usb"); + clk = devm_clk_get(&pdev->dev, "usb"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); ret = PTR_ERR(clk); - goto err3; + goto err0; } ret = clk_enable(clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); - goto err4; + goto err0; } glue->dev = &pdev->dev; @@ -579,20 +579,14 @@ static int davinci_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err5; + goto err1; } return 0; -err5: +err1: clk_disable(clk); -err4: - clk_put(clk); - -err3: - kfree(glue); - err0: return ret; } @@ -604,8 +598,6 @@ static int davinci_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); usb_phy_generic_unregister(); clk_disable(glue->clk); - clk_put(glue->clk); - kfree(glue); return 0; } From cdfe35fb2acfd6d95c1d34caa713d4498f8d6271 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Mon, 2 Jun 2014 21:15:05 +0530 Subject: [PATCH 021/211] usb: musb: tusb6010: Introduce the use of the managed version of kzalloc This patch moves data allocated using kzalloc to managed data allocated using devm_kzalloc and cleans now unnecessary kfrees in probe and remove functions. Also, the unnecesary labels are removed and linux/device.h is added to make sure the devm_*() routine declarations are unambiguously available. The following Coccinelle semantic patch was used for making the change: @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/musb/tusb6010.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 159ef4be1ef2..7dfc6cb732c9 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1160,12 +1161,12 @@ static int tusb_probe(struct platform_device *pdev) struct platform_device *musb; struct tusb6010_glue *glue; struct platform_device_info pinfo; - int ret = -ENOMEM; + int ret; - glue = kzalloc(sizeof(*glue), GFP_KERNEL); + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; + return -ENOMEM; } glue->dev = &pdev->dev; @@ -1204,16 +1205,10 @@ static int tusb_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err3; + return ret; } return 0; - -err3: - kfree(glue); - -err0: - return ret; } static int tusb_remove(struct platform_device *pdev) @@ -1222,7 +1217,6 @@ static int tusb_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->phy); - kfree(glue); return 0; } From f875bf351889ace841ce9477b058a023e2414690 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Mon, 2 Jun 2014 02:13:21 +0530 Subject: [PATCH 022/211] usb: musb: backfin: Introduce the use of the managed version of kzalloc This patch moves data allocated using kzalloc to managed data allocated using devm_kzalloc and cleans now unnecessary kfrees in probe and remove functions. Also, a label is done away with and err2 and err3 renamed. The following Coccinelle semantic patch was used for making the change: @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/musb/blackfin.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index d40d5f0b5528..ac4422b33dcd 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -455,7 +455,7 @@ static int bfin_probe(struct platform_device *pdev) int ret = -ENOMEM; - glue = kzalloc(sizeof(*glue), GFP_KERNEL); + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&pdev->dev, "failed to allocate glue context\n"); goto err0; @@ -464,7 +464,7 @@ static int bfin_probe(struct platform_device *pdev) musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err0; } musb->dev.parent = &pdev->dev; @@ -478,7 +478,7 @@ static int bfin_probe(struct platform_device *pdev) glue->phy = usb_phy_generic_register(); if (IS_ERR(glue->phy)) - goto err2; + goto err1; platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -498,31 +498,28 @@ static int bfin_probe(struct platform_device *pdev) ARRAY_SIZE(musb_resources)); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err3; + goto err2; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err3; + goto err2; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err3; + goto err2; } return 0; -err3: +err2: usb_phy_generic_unregister(glue->phy); -err2: - platform_device_put(musb); - err1: - kfree(glue); + platform_device_put(musb); err0: return ret; @@ -534,7 +531,6 @@ static int bfin_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->phy); - kfree(glue); return 0; } From eac44dc4e769a0f1db244dea13e10923c2877887 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 1 Jun 2014 15:48:12 +0200 Subject: [PATCH 023/211] usb: musb: musb_host.c: Cleaning up uninitialized variables There is a risk that the variable will be used without being initialized. This was largely found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index eb06291a40c8..3b11f98f3a56 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1957,7 +1957,7 @@ static int musb_schedule( struct musb_qh *qh, int is_in) { - int idle; + int idle = 0; int best_diff; int best_end, epnum; struct musb_hw_ep *hw_ep = NULL; From 58b949e0842a4751eec77edd60bd6178cef5b8de Mon Sep 17 00:00:00 2001 From: Benoit Taine Date: Mon, 26 May 2014 17:21:20 +0200 Subject: [PATCH 024/211] usb: gadget: Use kmemdup instead of kmalloc + memcpy This issue was reported by coccicheck using the semantic patch at scripts/coccinelle/api/memdup.cocci Signed-off-by: Benoit Taine Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 4 +--- drivers/usb/gadget/lpc32xx_udc.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 2ddcd635ca2a..bcc2a6248187 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1021,12 +1021,10 @@ static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop, if (page[len - 1] == '\n' || page[len - 1] == '\0') --len; - new_data = kzalloc(len, GFP_KERNEL); + new_data = kmemdup(page, len, GFP_KERNEL); if (!new_data) return -ENOMEM; - memcpy(new_data, page, len); - if (desc->opts_mutex) mutex_lock(desc->opts_mutex); kfree(ext_prop->data); diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index c77c6872b3ef..a93f64b9e632 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -3045,11 +3045,10 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev) dma_addr_t dma_handle; struct device_node *isp1301_node; - udc = kzalloc(sizeof(*udc), GFP_KERNEL); + udc = kmemdup(&controller_template, sizeof(*udc), GFP_KERNEL); if (!udc) return -ENOMEM; - memcpy(udc, &controller_template, sizeof(*udc)); for (i = 0; i <= 15; i++) udc->ep[i].udc = udc; udc->gadget.ep0 = &udc->ep[0].ep; From 56700178493eaab243b7b7b04077775cea6a87bd Mon Sep 17 00:00:00 2001 From: George Cherian Date: Mon, 26 May 2014 14:50:10 +0530 Subject: [PATCH 025/211] usb: musb: dsps: Call usb_phy(_shutdown/_init) during musb_platform_reset() For DSPS platform usb_phy_vbus(_off/_on) are NOPs. So during musb_platform_reset() call usb_phy(_shutdown/_init) Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 56c5d3fd6f6c..b29f59f718bb 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -551,7 +551,11 @@ static void dsps_musb_reset(struct musb *musb) const struct dsps_musb_wrapper *wrp = glue->wrp; dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); - udelay(100); + usleep_range(100, 200); + usb_phy_shutdown(musb->xceiv); + usleep_range(100, 200); + usb_phy_init(musb->xceiv); + } static struct musb_platform_ops dsps_ops = { From 0e1e5c47f7a92853a92ef97494fb4fee26d333ac Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 23 May 2014 11:39:24 -0700 Subject: [PATCH 026/211] usb: dwc3: add support for USB 2.0-only core configuration Newer DWC3 controllers can be built for USB 2.0-only mode, where most of the USB 3.0 circuitry is left out. To support this mode, the driver must limit the speed programmed into the DCFG register to Hi-Speed or lower. Reads and writes to the PIPECTL register are left as-is, since they should be no-ops in USB 2.0-only mode. Calls to phy_init() etc. for the USB3 phy are also left as-is, since the no-op USB3 phy should be used for USB 2.0-only mode controllers. Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 7 +++++++ drivers/usb/dwc3/core.h | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index fbe446350e28..b769c1faaf03 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -386,6 +386,13 @@ static int dwc3_core_init(struct dwc3 *dwc) } dwc->revision = reg; + /* Handle USB2.0-only core configuration */ + if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == + DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { + if (dwc->maximum_speed == USB_SPEED_SUPER) + dwc->maximum_speed = USB_SPEED_HIGH; + } + /* issue device SoftReset too */ timeout = jiffies + msecs_to_jiffies(500); dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 57332e3768e4..48fb264065db 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -191,6 +191,19 @@ #define DWC3_GHWPARAMS1_PWROPT(n) ((n) << 24) #define DWC3_GHWPARAMS1_PWROPT_MASK DWC3_GHWPARAMS1_PWROPT(3) +/* Global HWPARAMS3 Register */ +#define DWC3_GHWPARAMS3_SSPHY_IFC(n) ((n) & 3) +#define DWC3_GHWPARAMS3_SSPHY_IFC_DIS 0 +#define DWC3_GHWPARAMS3_SSPHY_IFC_ENA 1 +#define DWC3_GHWPARAMS3_HSPHY_IFC(n) (((n) & (3 << 2)) >> 2) +#define DWC3_GHWPARAMS3_HSPHY_IFC_DIS 0 +#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI 1 +#define DWC3_GHWPARAMS3_HSPHY_IFC_ULPI 2 +#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI 3 +#define DWC3_GHWPARAMS3_FSPHY_IFC(n) (((n) & (3 << 4)) >> 4) +#define DWC3_GHWPARAMS3_FSPHY_IFC_DIS 0 +#define DWC3_GHWPARAMS3_FSPHY_IFC_ENA 1 + /* Global HWPARAMS4 Register */ #define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13) #define DWC3_MAX_HIBER_SCRATCHBUFS 15 From 03d6a9c9aeac8da795a7df52d2b28bed4236e428 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sun, 18 May 2014 15:19:02 +0800 Subject: [PATCH 027/211] usb: gadget: atmel_usba_udc: delete __init marker for probe The probe function may be probed deferal and called after .init section has freed. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/atmel_usba_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 76023ce449a3..906e65f0e4fa 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1979,7 +1979,7 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev, return eps; } -static int __init usba_udc_probe(struct platform_device *pdev) +static int usba_udc_probe(struct platform_device *pdev) { struct resource *regs, *fifo; struct clk *pclk, *hclk; From da150573648a190d99986e1258bebae3a1766d02 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sun, 18 May 2014 15:19:03 +0800 Subject: [PATCH 028/211] usb: gadget: fsl_udc_core: delete __init marker for probe The probe function may be probed deferal and called after .init section has freed. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fsl_udc_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 28e4fc957026..ccbb3023cf42 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2246,7 +2246,7 @@ static void fsl_udc_release(struct device *dev) * init resource for globle controller * Return the udc handle on success or NULL on failure ------------------------------------------------------------------*/ -static int __init struct_udc_setup(struct fsl_udc *udc, +static int struct_udc_setup(struct fsl_udc *udc, struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata; @@ -2298,7 +2298,7 @@ static int __init struct_udc_setup(struct fsl_udc *udc, * ep0out is not used so do nothing here * ep0in should be taken care *--------------------------------------------------------------*/ -static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, +static int struct_ep_setup(struct fsl_udc *udc, unsigned char index, char *name, int link) { struct fsl_ep *ep = &udc->eps[index]; @@ -2331,7 +2331,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, * all intialization operations implemented here except enabling usb_intr reg * board setup should have been done in the platform code */ -static int __init fsl_udc_probe(struct platform_device *pdev) +static int fsl_udc_probe(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata; struct resource *res; From b1a7c4f2b1ad0556f12c2a665277ea1320cd76ff Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sun, 18 May 2014 15:19:04 +0800 Subject: [PATCH 029/211] usb: gadget: lpc32xx: delete __init marker for probe The probe function may be probed deferal and called after .init section has freed. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/lpc32xx_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index a93f64b9e632..1629ad7dcb80 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -3036,7 +3036,7 @@ struct lpc32xx_usbd_cfg lpc32xx_usbddata = { static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F; -static int __init lpc32xx_udc_probe(struct platform_device *pdev) +static int lpc32xx_udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct lpc32xx_udc *udc; From 880ce065879a4e5f15e61acfa3beedf3eddedff2 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sun, 18 May 2014 15:19:05 +0800 Subject: [PATCH 030/211] usb: gadget: m66592-udc: delete __init marker for probe The probe function may be probed deferal and called after .init section has freed. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/m66592-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 0d17174b86f8..3d6609b5265e 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1553,7 +1553,7 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r) { } -static int __init m66592_probe(struct platform_device *pdev) +static int m66592_probe(struct platform_device *pdev) { struct resource *res, *ires; void __iomem *reg = NULL; From c440380751ba0b85ce9f09cf54619053cadd90e9 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sun, 18 May 2014 15:19:06 +0800 Subject: [PATCH 031/211] usb: gadget: fusb300_udc: delete __init marker for probe The probe function may be probed deferal and called after .init section has freed. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fusb300_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 3deb4e938071..d8e2c0c40106 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1359,7 +1359,7 @@ static int __exit fusb300_remove(struct platform_device *pdev) return 0; } -static int __init fusb300_probe(struct platform_device *pdev) +static int fusb300_probe(struct platform_device *pdev) { struct resource *res, *ires, *ires1; void __iomem *reg = NULL; From dad833823f842bb038abd079da8f7eca9e654f5f Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sun, 18 May 2014 15:19:07 +0800 Subject: [PATCH 032/211] usb: gadget: r8a66597-udc: delete __init marker for probe The probe function may be probed deferal and called after .init section has freed. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 6ad60286ceb3..46008421c1ec 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1839,7 +1839,7 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r) { } -static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, +static int r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, struct platform_device *pdev) { struct resource *res; @@ -1854,7 +1854,7 @@ static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, return 0; } -static int __init r8a66597_probe(struct platform_device *pdev) +static int r8a66597_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; char clk_name[8]; From adc82f77bee3487651f8ad253fb1c8a7bf4ec658 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:03 +0200 Subject: [PATCH 033/211] usb: gadget: net2280: Add support for PLX USB338X This patch adds support for the PLX USB3380 and USB3382. This driver is based on the driver from the manufacturer. Since USB338X is register compatible with NET2280, I thought that it would be better to include this hardware into net2280 driver. Manufacturer's driver only supported the USB33X, did not follow the Kernel Style and contain some trivial errors. This patch has tried to address this issues. This patch has only been tested on USB338x hardware, but the merge has been done trying to not affect the behaviour of NET2280. Tested-by: Alan Stern Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 10 +- drivers/usb/gadget/net2280.c | 1117 +++++++++++++++++++++++++++++++--- drivers/usb/gadget/net2280.h | 121 +++- include/linux/usb/usb338x.h | 199 ++++++ 4 files changed, 1350 insertions(+), 97 deletions(-) create mode 100644 include/linux/usb/usb338x.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index ba18e9c110cc..49e434ec527d 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -409,7 +409,7 @@ config USB_NET2272_DMA If unsure, say "N" here. The driver works fine in PIO mode. config USB_NET2280 - tristate "NetChip 228x" + tristate "NetChip 228x / PLX USB338x" depends on PCI help NetChip 2280 / 2282 is a PCI based USB peripheral controller which @@ -419,6 +419,14 @@ config USB_NET2280 (for control transfers) and several endpoints with dedicated functions. + PLX 3380 / 3382 is a PCIe based USB peripheral controller which + supports full, high speed USB 2.0 and super speed USB 3.0 + data transfers. + + It has eight configurable endpoints, as well as endpoint zero + (for control transfers) and several endpoints with dedicated + functions. + Say "y" to link the driver statically, or "m" to build a dynamically linked module called "net2280" and force all gadget drivers to also be dynamically linked. diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 300b3a71383b..8112d9140a90 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -18,6 +18,9 @@ * hint to completely eliminate some IRQs, if a later IRQ is guaranteed * and DMA chaining is enabled. * + * MSI is enabled by default. The legacy IRQ is used if MSI couldn't + * be enabled. + * * Note that almost all the errata workarounds here are only needed for * rev1 chips. Rev1a silicon (0110) fixes almost all of them. */ @@ -25,10 +28,14 @@ /* * Copyright (C) 2003 David Brownell * Copyright (C) 2003-2005 PLX Technology, Inc. + * Copyright (C) 2014 Ricardo Ribalda - Qtechnology/AS * * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility * with 2282 chip * + * Modified Ricardo Ribalda Qtechnology AS to provide compatibility + * with usb 338x chip. Based on PLX driver + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -61,9 +68,8 @@ #include #include - -#define DRIVER_DESC "PLX NET228x USB Peripheral Controller" -#define DRIVER_VERSION "2005 Sept 27" +#define DRIVER_DESC "PLX NET228x/USB338x USB Peripheral Controller" +#define DRIVER_VERSION "2005 Sept 27/v3.0" #define EP_DONTUSE 13 /* nonzero */ @@ -73,11 +79,12 @@ static const char driver_name [] = "net2280"; static const char driver_desc [] = DRIVER_DESC; +static const u32 ep_bit[9] = { 0, 17, 2, 19, 4, 1, 18, 3, 20 }; static const char ep0name [] = "ep0"; static const char *const ep_name [] = { ep0name, "ep-a", "ep-b", "ep-c", "ep-d", - "ep-e", "ep-f", + "ep-e", "ep-f", "ep-g", "ep-h", }; /* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO) @@ -90,11 +97,12 @@ static const char *const ep_name [] = { */ static bool use_dma = 1; static bool use_dma_chaining = 0; +static bool use_msi = 1; /* "modprobe net2280 use_dma=n" etc */ module_param (use_dma, bool, S_IRUGO); module_param (use_dma_chaining, bool, S_IRUGO); - +module_param(use_msi, bool, S_IRUGO); /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable @@ -140,6 +148,18 @@ static char *type_string (u8 bmAttributes) #define dma_done_ie cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE) /*-------------------------------------------------------------------------*/ +static inline void enable_pciirqenb(struct net2280_ep *ep) +{ + u32 tmp = readl(&ep->dev->regs->pciirqenb0); + + if (ep->dev->pdev->vendor == 0x17cc) + tmp |= 1 << ep->num; + else + tmp |= 1 << ep_bit[ep->num]; + writel(tmp, &ep->dev->regs->pciirqenb0); + + return; +} static int net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) @@ -148,6 +168,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) struct net2280_ep *ep; u32 max, tmp; unsigned long flags; + static const u32 ep_key[9] = { 1, 0, 1, 0, 1, 1, 0, 1, 0 }; ep = container_of (_ep, struct net2280_ep, ep); if (!_ep || !desc || ep->desc || _ep->name == ep0name @@ -161,9 +182,17 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) return -EDOM; + if (dev->pdev->vendor == 0x10b5) { + if ((desc->bEndpointAddress & 0x0f) >= 0x0c) + return -EDOM; + ep->is_in = !!usb_endpoint_dir_in(desc); + if (dev->enhanced_mode && ep->is_in && ep_key[ep->num]) + return -EINVAL; + } + /* sanity check ep-e/ep-f since their fifos are small */ max = usb_endpoint_maxp (desc) & 0x1fff; - if (ep->num > 4 && max > 64) + if (ep->num > 4 && max > 64 && (dev->pdev->vendor == 0x17cc)) return -ERANGE; spin_lock_irqsave (&dev->lock, flags); @@ -176,7 +205,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ep->out_overflow = 0; /* set speed-dependent max packet; may kick in high bandwidth */ - set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max); + set_max_speed(ep, max); /* FIFO lines can't go to different packets. PIO is ok, so * use it instead of troublesome (non-bulk) multi-packet DMA. @@ -199,23 +228,43 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) &ep->regs->ep_rsp); } else if (tmp == USB_ENDPOINT_XFER_BULK) { /* catch some particularly blatant driver bugs */ - if ((dev->gadget.speed == USB_SPEED_HIGH - && max != 512) - || (dev->gadget.speed == USB_SPEED_FULL - && max > 64)) { - spin_unlock_irqrestore (&dev->lock, flags); + if ((dev->gadget.speed == USB_SPEED_SUPER && max != 1024) || + (dev->gadget.speed == USB_SPEED_HIGH && max != 512) || + (dev->gadget.speed == USB_SPEED_FULL && max > 64)) { + spin_unlock_irqrestore(&dev->lock, flags); return -ERANGE; } } ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; - tmp <<= ENDPOINT_TYPE; - tmp |= desc->bEndpointAddress; - tmp |= (4 << ENDPOINT_BYTE_COUNT); /* default full fifo lines */ - tmp |= 1 << ENDPOINT_ENABLE; - wmb (); + /* Enable this endpoint */ + if (dev->pdev->vendor == 0x17cc) { + tmp <<= ENDPOINT_TYPE; + tmp |= desc->bEndpointAddress; + /* default full fifo lines */ + tmp |= (4 << ENDPOINT_BYTE_COUNT); + tmp |= 1 << ENDPOINT_ENABLE; + ep->is_in = (tmp & USB_DIR_IN) != 0; + } else { + /* In Legacy mode, only OUT endpoints are used */ + if (dev->enhanced_mode && ep->is_in) { + tmp <<= IN_ENDPOINT_TYPE; + tmp |= (1 << IN_ENDPOINT_ENABLE); + /* Not applicable to Legacy */ + tmp |= (1 << ENDPOINT_DIRECTION); + } else { + tmp <<= OUT_ENDPOINT_TYPE; + tmp |= (1 << OUT_ENDPOINT_ENABLE); + tmp |= (ep->is_in << ENDPOINT_DIRECTION); + } + + tmp |= usb_endpoint_num(desc); + tmp |= (ep->ep.maxburst << MAX_BURST_SIZE); + } + + /* Make sure all the registers are written before ep_rsp*/ + wmb(); /* for OUT transfers, block the rx fifo until a read is posted */ - ep->is_in = (tmp & USB_DIR_IN) != 0; if (!ep->is_in) writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); else if (dev->pdev->device != 0x2280) { @@ -226,12 +275,11 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); } - writel (tmp, &ep->regs->ep_cfg); + writel(tmp, &ep->cfg->ep_cfg); /* enable irqs */ if (!ep->dma) { /* pio, per-packet */ - tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0); - writel (tmp, &dev->regs->pciirqenb0); + enable_pciirqenb(ep); tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); @@ -251,8 +299,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE); writel (tmp, &ep->regs->ep_irqenb); - tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0); - writel (tmp, &dev->regs->pciirqenb0); + enable_pciirqenb(ep); } } @@ -286,7 +333,8 @@ static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) static const struct usb_ep_ops net2280_ep_ops; -static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) +static void ep_reset_228x(struct net2280_regs __iomem *regs, + struct net2280_ep *ep) { u32 tmp; @@ -361,6 +409,55 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) /* fifo size is handled separately */ } +static void ep_reset_338x(struct net2280_regs __iomem *regs, + struct net2280_ep *ep) +{ + u32 tmp, dmastat; + + ep->desc = NULL; + INIT_LIST_HEAD(&ep->queue); + + usb_ep_set_maxpacket_limit(&ep->ep, ~0); + ep->ep.ops = &net2280_ep_ops; + + /* disable the dma, irqs, endpoint... */ + if (ep->dma) { + writel(0, &ep->dma->dmactl); + writel((1 << DMA_ABORT_DONE_INTERRUPT) | + (1 << DMA_PAUSE_DONE_INTERRUPT) | + (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) | + (1 << DMA_TRANSACTION_DONE_INTERRUPT) + /* | (1 << DMA_ABORT) */ + , &ep->dma->dmastat); + + dmastat = readl(&ep->dma->dmastat); + if (dmastat == 0x5002) { + WARNING(ep->dev, "The dmastat return = %x!!\n", + dmastat); + writel(0x5a, &ep->dma->dmastat); + } + + tmp = readl(®s->pciirqenb0); + tmp &= ~(1 << ep_bit[ep->num]); + writel(tmp, ®s->pciirqenb0); + } else { + if (ep->num < 5) { + tmp = readl(®s->pciirqenb1); + tmp &= ~(1 << (8 + ep->num)); /* completion */ + writel(tmp, ®s->pciirqenb1); + } + } + writel(0, &ep->regs->ep_irqenb); + + writel((1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | + (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | + (1 << FIFO_OVERFLOW) | + (1 << DATA_PACKET_RECEIVED_INTERRUPT) | + (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) | + (1 << DATA_OUT_PING_TOKEN_INTERRUPT) | + (1 << DATA_IN_TOKEN_INTERRUPT), &ep->regs->ep_stat); +} + static void nuke (struct net2280_ep *); static int net2280_disable (struct usb_ep *_ep) @@ -374,13 +471,17 @@ static int net2280_disable (struct usb_ep *_ep) spin_lock_irqsave (&ep->dev->lock, flags); nuke (ep); - ep_reset (ep->dev->regs, ep); + + if (ep->dev->pdev->vendor == 0x10b5) + ep_reset_338x(ep->dev->regs, ep); + else + ep_reset_228x(ep->dev->regs, ep); VDEBUG (ep->dev, "disabled %s %s\n", ep->dma ? "dma" : "pio", _ep->name); /* synch memory views with the device */ - (void) readl (&ep->regs->ep_cfg); + (void)readl(&ep->cfg->ep_cfg); if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4) ep->dma = &ep->dev->dma [ep->num - 1]; @@ -698,6 +799,8 @@ static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) writel (readl (&dma->dmastat), &dma->dmastat); writel (td_dma, &dma->dmadesc); + if (ep->dev->pdev->vendor == 0x10b5) + dmactl |= (0x01 << DMA_REQUEST_OUTSTANDING); writel (dmactl, &dma->dmactl); /* erratum 0116 workaround part 3: pci arbiter away from net2280 */ @@ -772,6 +875,21 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) start_queue (ep, tmp, req->td_dma); } +static inline void resume_dma(struct net2280_ep *ep) +{ + writel(readl(&ep->dma->dmactl) | (1 << DMA_ENABLE), &ep->dma->dmactl); + + ep->dma_started = true; +} + +static inline void ep_stop_dma(struct net2280_ep *ep) +{ + writel(readl(&ep->dma->dmactl) & ~(1 << DMA_ENABLE), &ep->dma->dmactl); + spin_stop_dma(ep->dma); + + ep->dma_started = false; +} + static inline void queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid) { @@ -874,8 +992,23 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* kickstart this i/o queue? */ if (list_empty (&ep->queue) && !ep->stopped) { + /* DMA request while EP halted */ + if (ep->dma && + (readl(&ep->regs->ep_rsp) & (1 << CLEAR_ENDPOINT_HALT)) && + (dev->pdev->vendor == 0x10b5)) { + int valid = 1; + if (ep->is_in) { + int expect; + expect = likely(req->req.zero || + ((req->req.length % + ep->ep.maxpacket) != 0)); + if (expect != ep->in_fifo_validate) + valid = 0; + } + queue_dma(ep, req, valid); + } /* use DMA if the endpoint supports it, else pio */ - if (ep->dma) + else if (ep->dma) start_dma (ep, req); else { /* maybe there's no control data, just status ack */ @@ -993,6 +1126,8 @@ static void scan_dma_completions (struct net2280_ep *ep) } else if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { tmp = readl (&ep->regs->ep_stat); + if (ep->dev->pdev->vendor == 0x10b5) + return dma_done(ep, req, tmp, 0); /* AVOID TROUBLE HERE by not issuing short reads from * your gadget driver. That helps avoids errata 0121, @@ -1079,7 +1214,7 @@ static void restart_dma (struct net2280_ep *ep) start_queue (ep, dmactl, req->td_dma); } -static void abort_dma (struct net2280_ep *ep) +static void abort_dma_228x(struct net2280_ep *ep) { /* abort the current transfer */ if (likely (!list_empty (&ep->queue))) { @@ -1091,6 +1226,19 @@ static void abort_dma (struct net2280_ep *ep) scan_dma_completions (ep); } +static void abort_dma_338x(struct net2280_ep *ep) +{ + writel((1 << DMA_ABORT), &ep->dma->dmastat); + spin_stop_dma(ep->dma); +} + +static void abort_dma(struct net2280_ep *ep) +{ + if (ep->dev->pdev->vendor == 0x17cc) + return abort_dma_228x(ep); + return abort_dma_338x(ep); +} + /* dequeue ALL requests */ static void nuke (struct net2280_ep *ep) { @@ -1244,6 +1392,9 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) ep->wedged = 1; } else { clear_halt (ep); + if (ep->dev->pdev->vendor == 0x10b5 && + !list_empty(&ep->queue) && ep->td_dma) + restart_dma(ep); ep->wedged = 0; } (void) readl (&ep->regs->ep_rsp); @@ -1367,10 +1518,13 @@ static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) spin_lock_irqsave (&dev->lock, flags); tmp = readl (&dev->usb->usbctl); - if (value) + if (value) { tmp |= (1 << SELF_POWERED_STATUS); - else + dev->selfpowered = 1; + } else { tmp &= ~(1 << SELF_POWERED_STATUS); + dev->selfpowered = 0; + } writel (tmp, &dev->usb->usbctl); spin_unlock_irqrestore (&dev->lock, flags); @@ -1504,14 +1658,14 @@ static ssize_t registers_show(struct device *_dev, /* DMA Control Registers */ /* Configurable EP Control Registers */ - for (i = 0; i < 7; i++) { + for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep; ep = &dev->ep [i]; if (i && !ep->desc) continue; - t1 = readl (&ep->regs->ep_cfg); + t1 = readl(&ep->cfg->ep_cfg); t2 = readl (&ep->regs->ep_rsp) & 0xff; t = scnprintf (next, size, "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" @@ -1571,7 +1725,7 @@ static ssize_t registers_show(struct device *_dev, t = scnprintf (next, size, "\nirqs: "); size -= t; next += t; - for (i = 0; i < 7; i++) { + for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep; ep = &dev->ep [i]; @@ -1606,7 +1760,7 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr, size = PAGE_SIZE; spin_lock_irqsave (&dev->lock, flags); - for (i = 0; i < 7; i++) { + for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep = &dev->ep [i]; struct net2280_request *req; int t; @@ -1735,6 +1889,121 @@ static void set_fifo_mode (struct net2280 *dev, int mode) list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); } +static void defect7374_disable_data_eps(struct net2280 *dev) +{ + /* + * For Defect 7374, disable data EPs (and more): + * - This phase undoes the earlier phase of the Defect 7374 workaround, + * returing ep regs back to normal. + */ + struct net2280_ep *ep; + int i; + unsigned char ep_sel; + u32 tmp_reg; + + for (i = 1; i < 5; i++) { + ep = &dev->ep[i]; + writel(0, &ep->cfg->ep_cfg); + } + + /* CSROUT, CSRIN, PCIOUT, PCIIN, STATIN, RCIN */ + for (i = 0; i < 6; i++) + writel(0, &dev->dep[i].dep_cfg); + + for (ep_sel = 0; ep_sel <= 21; ep_sel++) { + /* Select an endpoint for subsequent operations: */ + tmp_reg = readl(&dev->plregs->pl_ep_ctrl); + writel(((tmp_reg & ~0x1f) | ep_sel), &dev->plregs->pl_ep_ctrl); + + if (ep_sel < 2 || (ep_sel > 9 && ep_sel < 14) || + ep_sel == 18 || ep_sel == 20) + continue; + + /* Change settings on some selected endpoints */ + tmp_reg = readl(&dev->plregs->pl_ep_cfg_4); + tmp_reg &= ~(1 << NON_CTRL_IN_TOLERATE_BAD_DIR); + writel(tmp_reg, &dev->plregs->pl_ep_cfg_4); + tmp_reg = readl(&dev->plregs->pl_ep_ctrl); + tmp_reg |= (1 << EP_INITIALIZED); + writel(tmp_reg, &dev->plregs->pl_ep_ctrl); + } +} + +static void defect7374_enable_data_eps_zero(struct net2280 *dev) +{ + u32 tmp = 0, tmp_reg; + u32 fsmvalue, scratch; + int i; + unsigned char ep_sel; + + scratch = get_idx_reg(dev->regs, SCRATCH); + fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD); + scratch &= ~(0xf << DEFECT7374_FSM_FIELD); + + /*See if firmware needs to set up for workaround*/ + if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) { + WARNING(dev, "Operate Defect 7374 workaround soft this time"); + WARNING(dev, "It will operate on cold-reboot and SS connect"); + + /*GPEPs:*/ + tmp = ((0 << ENDPOINT_NUMBER) | (1 << ENDPOINT_DIRECTION) | + (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) | + ((dev->enhanced_mode) ? + 1 << OUT_ENDPOINT_ENABLE : 1 << ENDPOINT_ENABLE) | + (1 << IN_ENDPOINT_ENABLE)); + + for (i = 1; i < 5; i++) + writel(tmp, &dev->ep[i].cfg->ep_cfg); + + /* CSRIN, PCIIN, STATIN, RCIN*/ + tmp = ((0 << ENDPOINT_NUMBER) | (1 << ENDPOINT_ENABLE)); + writel(tmp, &dev->dep[1].dep_cfg); + writel(tmp, &dev->dep[3].dep_cfg); + writel(tmp, &dev->dep[4].dep_cfg); + writel(tmp, &dev->dep[5].dep_cfg); + + /*Implemented for development and debug. + * Can be refined/tuned later.*/ + for (ep_sel = 0; ep_sel <= 21; ep_sel++) { + /* Select an endpoint for subsequent operations: */ + tmp_reg = readl(&dev->plregs->pl_ep_ctrl); + writel(((tmp_reg & ~0x1f) | ep_sel), + &dev->plregs->pl_ep_ctrl); + + if (ep_sel == 1) { + tmp = + (readl(&dev->plregs->pl_ep_ctrl) | + (1 << CLEAR_ACK_ERROR_CODE) | 0); + writel(tmp, &dev->plregs->pl_ep_ctrl); + continue; + } + + if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) || + ep_sel == 18 || ep_sel == 20) + continue; + + tmp = (readl(&dev->plregs->pl_ep_cfg_4) | + (1 << NON_CTRL_IN_TOLERATE_BAD_DIR) | 0); + writel(tmp, &dev->plregs->pl_ep_cfg_4); + + tmp = readl(&dev->plregs->pl_ep_ctrl) & + ~(1 << EP_INITIALIZED); + writel(tmp, &dev->plregs->pl_ep_ctrl); + + } + + /* Set FSM to focus on the first Control Read: + * - Tip: Connection speed is known upon the first + * setup request.*/ + scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ; + set_idx_reg(dev->regs, SCRATCH, scratch); + + } else{ + WARNING(dev, "Defect 7374 workaround soft will NOT operate"); + WARNING(dev, "It will operate on cold-reboot and SS connect"); + } +} + /* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second @@ -1744,7 +2013,7 @@ static void set_fifo_mode (struct net2280 *dev, int mode) * perhaps to bind specific drivers to specific devices. */ -static void usb_reset (struct net2280 *dev) +static void usb_reset_228x(struct net2280 *dev) { u32 tmp; @@ -1760,11 +2029,11 @@ static void usb_reset (struct net2280 *dev) /* clear old dma and irq state */ for (tmp = 0; tmp < 4; tmp++) { - struct net2280_ep *ep = &dev->ep [tmp + 1]; - + struct net2280_ep *ep = &dev->ep[tmp + 1]; if (ep->dma) - abort_dma (ep); + abort_dma(ep); } + writel (~0, &dev->regs->irqstat0), writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), @@ -1780,7 +2049,67 @@ static void usb_reset (struct net2280 *dev) set_fifo_mode (dev, (fifo_mode <= 2) ? fifo_mode : 0); } -static void usb_reinit (struct net2280 *dev) +static void usb_reset_338x(struct net2280 *dev) +{ + u32 tmp; + u32 fsmvalue; + + dev->gadget.speed = USB_SPEED_UNKNOWN; + (void)readl(&dev->usb->usbctl); + + net2280_led_init(dev); + + fsmvalue = get_idx_reg(dev->regs, SCRATCH) & + (0xf << DEFECT7374_FSM_FIELD); + + /* See if firmware needs to set up for workaround: */ + if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) { + INFO(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__, + fsmvalue); + } else { + /* disable automatic responses, and irqs */ + writel(0, &dev->usb->stdrsp); + writel(0, &dev->regs->pciirqenb0); + writel(0, &dev->regs->pciirqenb1); + } + + /* clear old dma and irq state */ + for (tmp = 0; tmp < 4; tmp++) { + struct net2280_ep *ep = &dev->ep[tmp + 1]; + + if (ep->dma) + abort_dma(ep); + } + + writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1); + + if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) { + /* reset, and enable pci */ + tmp = readl(&dev->regs->devinit) | + (1 << PCI_ENABLE) | + (1 << FIFO_SOFT_RESET) | + (1 << USB_SOFT_RESET) | + (1 << M8051_RESET); + + writel(tmp, &dev->regs->devinit); + } + + /* always ep-{1,2,3,4} ... maybe not ep-3 or ep-4 */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + + for (tmp = 1; tmp < dev->n_ep; tmp++) + list_add_tail(&dev->ep[tmp].ep.ep_list, &dev->gadget.ep_list); + +} + +static void usb_reset(struct net2280 *dev) +{ + if (dev->pdev->vendor == 0x17cc) + return usb_reset_228x(dev); + return usb_reset_338x(dev); +} + +static void usb_reinit_228x(struct net2280 *dev) { u32 tmp; int init_dma; @@ -1803,7 +2132,8 @@ static void usb_reinit (struct net2280 *dev) } else ep->fifo_size = 64; ep->regs = &dev->epregs [tmp]; - ep_reset (dev->regs, ep); + ep->cfg = &dev->epregs[tmp]; + ep_reset_228x(dev->regs, ep); } usb_ep_set_maxpacket_limit(&dev->ep [0].ep, 64); usb_ep_set_maxpacket_limit(&dev->ep [5].ep, 64); @@ -1820,7 +2150,122 @@ static void usb_reinit (struct net2280 *dev) writel (EP_DONTUSE, &dev->dep [tmp].dep_cfg); } -static void ep0_start (struct net2280 *dev) +static void usb_reinit_338x(struct net2280 *dev) +{ + int init_dma; + int i; + u32 tmp, val; + u32 fsmvalue; + static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 }; + static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00, + 0x00, 0xC0, 0x00, 0xC0 }; + + /* use_dma changes are ignored till next device re-init */ + init_dma = use_dma; + + /* basic endpoint init */ + for (i = 0; i < dev->n_ep; i++) { + struct net2280_ep *ep = &dev->ep[i]; + + ep->ep.name = ep_name[i]; + ep->dev = dev; + ep->num = i; + + if (i > 0 && i <= 4 && init_dma) + ep->dma = &dev->dma[i - 1]; + + if (dev->enhanced_mode) { + ep->cfg = &dev->epregs[ne[i]]; + ep->regs = (struct net2280_ep_regs __iomem *) + (((void *)&dev->epregs[ne[i]]) + + ep_reg_addr[i]); + ep->fiforegs = &dev->fiforegs[i]; + } else { + ep->cfg = &dev->epregs[i]; + ep->regs = &dev->epregs[i]; + ep->fiforegs = &dev->fiforegs[i]; + } + + ep->fifo_size = (i != 0) ? 2048 : 512; + + ep_reset_338x(dev->regs, ep); + } + usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 512); + + dev->gadget.ep0 = &dev->ep[0].ep; + dev->ep[0].stopped = 0; + + /* Link layer set up */ + fsmvalue = get_idx_reg(dev->regs, SCRATCH) & + (0xf << DEFECT7374_FSM_FIELD); + + /* See if driver needs to set up for workaround: */ + if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) + INFO(dev, "%s: Defect 7374 FsmValue %08x\n", + __func__, fsmvalue); + else { + tmp = readl(&dev->usb_ext->usbctl2) & + ~((1 << U1_ENABLE) | (1 << U2_ENABLE) | (1 << LTM_ENABLE)); + writel(tmp, &dev->usb_ext->usbctl2); + } + + /* Hardware Defect and Workaround */ + val = readl(&dev->ll_lfps_regs->ll_lfps_5); + val &= ~(0xf << TIMER_LFPS_6US); + val |= 0x5 << TIMER_LFPS_6US; + writel(val, &dev->ll_lfps_regs->ll_lfps_5); + + val = readl(&dev->ll_lfps_regs->ll_lfps_6); + val &= ~(0xffff << TIMER_LFPS_80US); + val |= 0x0100 << TIMER_LFPS_80US; + writel(val, &dev->ll_lfps_regs->ll_lfps_6); + + /* + * AA_AB Errata. Issue 4. Workaround for SuperSpeed USB + * Hot Reset Exit Handshake may Fail in Specific Case using + * Default Register Settings. Workaround for Enumeration test. + */ + val = readl(&dev->ll_tsn_regs->ll_tsn_counters_2); + val &= ~(0x1f << HOT_TX_NORESET_TS2); + val |= 0x10 << HOT_TX_NORESET_TS2; + writel(val, &dev->ll_tsn_regs->ll_tsn_counters_2); + + val = readl(&dev->ll_tsn_regs->ll_tsn_counters_3); + val &= ~(0x1f << HOT_RX_RESET_TS2); + val |= 0x3 << HOT_RX_RESET_TS2; + writel(val, &dev->ll_tsn_regs->ll_tsn_counters_3); + + /* + * Set Recovery Idle to Recover bit: + * - On SS connections, setting Recovery Idle to Recover Fmw improves + * link robustness with various hosts and hubs. + * - 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 |= (1 << RECOVERY_IDLE_TO_RECOVER_FMW); + writel(val, &dev->ll_chicken_reg->ll_tsn_chicken_bit); + + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + + /* disable dedicated endpoints */ + writel(0x0D, &dev->dep[0].dep_cfg); + writel(0x0D, &dev->dep[1].dep_cfg); + writel(0x0E, &dev->dep[2].dep_cfg); + writel(0x0E, &dev->dep[3].dep_cfg); + writel(0x0F, &dev->dep[4].dep_cfg); + writel(0x0C, &dev->dep[5].dep_cfg); +} + +static void usb_reinit(struct net2280 *dev) +{ + if (dev->pdev->vendor == 0x17cc) + return usb_reinit_228x(dev); + return usb_reinit_338x(dev); +} + +static void ep0_start_228x(struct net2280 *dev) { writel ( (1 << CLEAR_EP_HIDE_STATUS_PHASE) | (1 << CLEAR_NAK_OUT_PACKETS) @@ -1863,6 +2308,61 @@ static void ep0_start (struct net2280 *dev) (void) readl (&dev->usb->usbctl); } +static void ep0_start_338x(struct net2280 *dev) +{ + u32 fsmvalue; + + fsmvalue = get_idx_reg(dev->regs, SCRATCH) & + (0xf << DEFECT7374_FSM_FIELD); + + if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) + INFO(dev, "%s: Defect 7374 FsmValue %08x\n", __func__, + fsmvalue); + else + writel((1 << CLEAR_NAK_OUT_PACKETS_MODE) | + (1 << SET_EP_HIDE_STATUS_PHASE), + &dev->epregs[0].ep_rsp); + + /* + * hardware optionally handles a bunch of standard requests + * that the API hides from drivers anyway. have it do so. + * endpoint status/features are handled in software, to + * help pass tests for some dubious behavior. + */ + writel((1 << SET_ISOCHRONOUS_DELAY) | + (1 << SET_SEL) | + (1 << SET_TEST_MODE) | + (1 << SET_ADDRESS) | + (1 << GET_INTERFACE_STATUS) | + (1 << GET_DEVICE_STATUS), + &dev->usb->stdrsp); + dev->wakeup_enable = 1; + writel((1 << USB_ROOT_PORT_WAKEUP_ENABLE) | + (dev->softconnect << USB_DETECT_ENABLE) | + (1 << DEVICE_REMOTE_WAKEUP_ENABLE), + &dev->usb->usbctl); + + /* enable irqs so we can see ep0 and general operation */ + writel((1 << SETUP_PACKET_INTERRUPT_ENABLE) | + (1 << ENDPOINT_0_INTERRUPT_ENABLE) + , &dev->regs->pciirqenb0); + writel((1 << PCI_INTERRUPT_ENABLE) | + (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) | + (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE) | + (1 << VBUS_INTERRUPT_ENABLE), + &dev->regs->pciirqenb1); + + /* don't leave any writes posted */ + (void)readl(&dev->usb->usbctl); +} + +static void ep0_start(struct net2280 *dev) +{ + if (dev->pdev->vendor == 0x17cc) + return ep0_start_228x(dev); + return ep0_start_338x(dev); +} + /* when a driver is successfully registered, it will receive * control requests including set_configuration(), which enables * non-control requests. then usb traffic follows until a @@ -1886,7 +2386,7 @@ static int net2280_start(struct usb_gadget *_gadget, dev = container_of (_gadget, struct net2280, gadget); - for (i = 0; i < 7; i++) + for (i = 0; i < dev->n_ep; i++) dev->ep [i].irqs = 0; /* hook up the driver ... */ @@ -1900,13 +2400,17 @@ static int net2280_start(struct usb_gadget *_gadget, if (retval) goto err_func; /* Enable force-full-speed testing mode, if desired */ - if (full_speed) + if (full_speed && dev->pdev->vendor == 0x17cc) writel(1 << FORCE_FULL_SPEED_MODE, &dev->usb->xcvrdiag); /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. */ net2280_led_active (dev, 1); + + if (dev->pdev->vendor == 0x10b5) + defect7374_enable_data_eps_zero(dev); + ep0_start (dev); DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n", @@ -1937,7 +2441,7 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) * and kill any outstanding requests. */ usb_reset (dev); - for (i = 0; i < 7; i++) + for (i = 0; i < dev->n_ep; i++) nuke (&dev->ep [i]); /* report disconnect; the driver is already quiesced */ @@ -1967,7 +2471,8 @@ static int net2280_stop(struct usb_gadget *_gadget, net2280_led_active (dev, 0); /* Disable full-speed test mode */ - writel(0, &dev->usb->xcvrdiag); + if (dev->pdev->vendor == 0x17cc) + writel(0, &dev->usb->xcvrdiag); device_remove_file (&dev->pdev->dev, &dev_attr_function); device_remove_file (&dev->pdev->dev, &dev_attr_queues); @@ -2219,6 +2724,350 @@ get_ep_by_addr (struct net2280 *dev, u16 wIndex) return NULL; } +static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r) +{ + u32 scratch, fsmvalue; + u32 ack_wait_timeout, state; + + /* Workaround for Defect 7374 (U1/U2 erroneously rejected): */ + scratch = get_idx_reg(dev->regs, SCRATCH); + fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD); + scratch &= ~(0xf << DEFECT7374_FSM_FIELD); + + if (!((fsmvalue == DEFECT7374_FSM_WAITING_FOR_CONTROL_READ) && + (r.bRequestType & USB_DIR_IN))) + return; + + /* This is the first Control Read for this connection: */ + if (!(readl(&dev->usb->usbstat) & (1 << SUPER_SPEED_MODE))) { + /* + * Connection is NOT SS: + * - Connection must be FS or HS. + * - This FSM state should allow workaround software to + * run after the next USB connection. + */ + scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ; + goto restore_data_eps; + } + + /* Connection is SS: */ + for (ack_wait_timeout = 0; + ack_wait_timeout < DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS; + ack_wait_timeout++) { + + state = readl(&dev->plregs->pl_ep_status_1) + & (0xff << STATE); + if ((state >= (ACK_GOOD_NORMAL << STATE)) && + (state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) { + scratch |= DEFECT7374_FSM_SS_CONTROL_READ; + break; + } + + /* + * We have not yet received host's Data Phase ACK + * - Wait and try again. + */ + udelay(DEFECT_7374_PROCESSOR_WAIT_TIME); + + continue; + } + + + if (ack_wait_timeout >= DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS) { + ERROR(dev, "FAIL: Defect 7374 workaround waited but failed " + "to detect SS host's data phase ACK."); + ERROR(dev, "PL_EP_STATUS_1(23:16):.Expected from 0x11 to 0x16" + "got 0x%2.2x.\n", state >> STATE); + } else { + WARNING(dev, "INFO: Defect 7374 workaround waited about\n" + "%duSec for Control Read Data Phase ACK\n", + DEFECT_7374_PROCESSOR_WAIT_TIME * ack_wait_timeout); + } + +restore_data_eps: + /* + * Restore data EPs to their pre-workaround settings (disabled, + * initialized, and other details). + */ + defect7374_disable_data_eps(dev); + + set_idx_reg(dev->regs, SCRATCH, scratch); + + return; +} + +static void ep_stall(struct net2280_ep *ep, int stall) +{ + struct net2280 *dev = ep->dev; + u32 val; + static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 }; + + if (stall) { + writel((1 << SET_ENDPOINT_HALT) | + /* (1 << SET_NAK_PACKETS) | */ + (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE), + &ep->regs->ep_rsp); + ep->is_halt = 1; + } else { + if (dev->gadget.speed == USB_SPEED_SUPER) { + /* + * Workaround for SS SeqNum not cleared via + * Endpoint Halt (Clear) bit. select endpoint + */ + val = readl(&dev->plregs->pl_ep_ctrl); + val = (val & ~0x1f) | ep_pl[ep->num]; + writel(val, &dev->plregs->pl_ep_ctrl); + + val |= (1 << SEQUENCE_NUMBER_RESET); + writel(val, &dev->plregs->pl_ep_ctrl); + } + val = readl(&ep->regs->ep_rsp); + val |= (1 << CLEAR_ENDPOINT_HALT) | + (1 << CLEAR_ENDPOINT_TOGGLE); + writel(val + /* | (1 << CLEAR_NAK_PACKETS)*/ + , &ep->regs->ep_rsp); + ep->is_halt = 0; + val = readl(&ep->regs->ep_rsp); + } +} + +static void ep_stdrsp(struct net2280_ep *ep, int value, int wedged) +{ + /* set/clear, then synch memory views with the device */ + if (value) { + ep->stopped = 1; + if (ep->num == 0) + ep->dev->protocol_stall = 1; + else { + if (ep->dma) + ep_stop_dma(ep); + ep_stall(ep, true); + } + + if (wedged) + ep->wedged = 1; + } else { + ep->stopped = 0; + ep->wedged = 0; + + ep_stall(ep, false); + + /* Flush the queue */ + if (!list_empty(&ep->queue)) { + struct net2280_request *req = + list_entry(ep->queue.next, struct net2280_request, + queue); + if (ep->dma) + resume_dma(ep); + else { + if (ep->is_in) + write_fifo(ep, &req->req); + else { + if (read_fifo(ep, req)) + done(ep, req, 0); + } + } + } + } +} + +static void handle_stat0_irqs_superspeed(struct net2280 *dev, + struct net2280_ep *ep, struct usb_ctrlrequest r) +{ + int tmp = 0; + +#define w_value le16_to_cpu(r.wValue) +#define w_index le16_to_cpu(r.wIndex) +#define w_length le16_to_cpu(r.wLength) + + switch (r.bRequest) { + struct net2280_ep *e; + u16 status; + + case USB_REQ_SET_CONFIGURATION: + dev->addressed_state = !w_value; + goto usb3_delegate; + + case USB_REQ_GET_STATUS: + switch (r.bRequestType) { + case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE): + status = dev->wakeup_enable ? 0x02 : 0x00; + if (dev->selfpowered) + status |= 1 << 0; + status |= (dev->u1_enable << 2 | dev->u2_enable << 3 | + dev->ltm_enable << 4); + writel(0, &dev->epregs[0].ep_irqenb); + set_fifo_bytecount(ep, sizeof(status)); + writel((__force u32) status, &dev->epregs[0].ep_data); + allow_status_338x(ep); + break; + + case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT): + e = get_ep_by_addr(dev, w_index); + if (!e) + goto do_stall3; + status = readl(&e->regs->ep_rsp) & + (1 << CLEAR_ENDPOINT_HALT); + writel(0, &dev->epregs[0].ep_irqenb); + set_fifo_bytecount(ep, sizeof(status)); + writel((__force u32) status, &dev->epregs[0].ep_data); + allow_status_338x(ep); + break; + + default: + goto usb3_delegate; + } + break; + + case USB_REQ_CLEAR_FEATURE: + switch (r.bRequestType) { + case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE): + if (!dev->addressed_state) { + switch (w_value) { + case USB_DEVICE_U1_ENABLE: + dev->u1_enable = 0; + writel(readl(&dev->usb_ext->usbctl2) & + ~(1 << U1_ENABLE), + &dev->usb_ext->usbctl2); + allow_status_338x(ep); + goto next_endpoints3; + + case USB_DEVICE_U2_ENABLE: + dev->u2_enable = 0; + writel(readl(&dev->usb_ext->usbctl2) & + ~(1 << U2_ENABLE), + &dev->usb_ext->usbctl2); + allow_status_338x(ep); + goto next_endpoints3; + + case USB_DEVICE_LTM_ENABLE: + dev->ltm_enable = 0; + writel(readl(&dev->usb_ext->usbctl2) & + ~(1 << LTM_ENABLE), + &dev->usb_ext->usbctl2); + allow_status_338x(ep); + goto next_endpoints3; + + default: + break; + } + } + if (w_value == USB_DEVICE_REMOTE_WAKEUP) { + dev->wakeup_enable = 0; + writel(readl(&dev->usb->usbctl) & + ~(1 << DEVICE_REMOTE_WAKEUP_ENABLE), + &dev->usb->usbctl); + allow_status_338x(ep); + break; + } + goto usb3_delegate; + + case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT): + e = get_ep_by_addr(dev, w_index); + if (!e) + goto do_stall3; + if (w_value != USB_ENDPOINT_HALT) + goto do_stall3; + VDEBUG(dev, "%s clear halt\n", e->ep.name); + ep_stall(e, false); + if (!list_empty(&e->queue) && e->td_dma) + restart_dma(e); + allow_status(ep); + ep->stopped = 1; + break; + + default: + goto usb3_delegate; + } + break; + case USB_REQ_SET_FEATURE: + switch (r.bRequestType) { + case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE): + if (!dev->addressed_state) { + switch (w_value) { + case USB_DEVICE_U1_ENABLE: + dev->u1_enable = 1; + writel(readl(&dev->usb_ext->usbctl2) | + (1 << U1_ENABLE), + &dev->usb_ext->usbctl2); + allow_status_338x(ep); + goto next_endpoints3; + + case USB_DEVICE_U2_ENABLE: + dev->u2_enable = 1; + writel(readl(&dev->usb_ext->usbctl2) | + (1 << U2_ENABLE), + &dev->usb_ext->usbctl2); + allow_status_338x(ep); + goto next_endpoints3; + + case USB_DEVICE_LTM_ENABLE: + dev->ltm_enable = 1; + writel(readl(&dev->usb_ext->usbctl2) | + (1 << LTM_ENABLE), + &dev->usb_ext->usbctl2); + allow_status_338x(ep); + goto next_endpoints3; + default: + break; + } + } + + if (w_value == USB_DEVICE_REMOTE_WAKEUP) { + dev->wakeup_enable = 1; + writel(readl(&dev->usb->usbctl) | + (1 << DEVICE_REMOTE_WAKEUP_ENABLE), + &dev->usb->usbctl); + allow_status_338x(ep); + break; + } + goto usb3_delegate; + + case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT): + e = get_ep_by_addr(dev, w_index); + if (!e || (w_value != USB_ENDPOINT_HALT)) + goto do_stall3; + ep_stdrsp(e, true, false); + allow_status_338x(ep); + break; + + default: + goto usb3_delegate; + } + + break; + default: + +usb3_delegate: + VDEBUG(dev, "setup %02x.%02x v%04x i%04x l%04x ep_cfg %08x\n", + r.bRequestType, r.bRequest, + w_value, w_index, w_length, + readl(&ep->cfg->ep_cfg)); + + ep->responded = 0; + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &r); + spin_lock(&dev->lock); + } +do_stall3: + if (tmp < 0) { + VDEBUG(dev, "req %02x.%02x protocol STALL; stat %d\n", + r.bRequestType, r.bRequest, tmp); + dev->protocol_stall = 1; + /* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */ + ep_stall(ep, true); + } + +next_endpoints3: + +#undef w_value +#undef w_index +#undef w_length + + return; +} + static void handle_stat0_irqs (struct net2280 *dev, u32 stat) { struct net2280_ep *ep; @@ -2240,10 +3089,20 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) struct net2280_request *req; if (dev->gadget.speed == USB_SPEED_UNKNOWN) { - if (readl (&dev->usb->usbstat) & (1 << HIGH_SPEED)) + u32 val = readl(&dev->usb->usbstat); + if (val & (1 << SUPER_SPEED)) { + dev->gadget.speed = USB_SPEED_SUPER; + usb_ep_set_maxpacket_limit(&dev->ep[0].ep, + EP0_SS_MAX_PACKET_SIZE); + } else if (val & (1 << HIGH_SPEED)) { dev->gadget.speed = USB_SPEED_HIGH; - else + usb_ep_set_maxpacket_limit(&dev->ep[0].ep, + EP0_HS_MAX_PACKET_SIZE); + } else { dev->gadget.speed = USB_SPEED_FULL; + usb_ep_set_maxpacket_limit(&dev->ep[0].ep, + EP0_HS_MAX_PACKET_SIZE); + } net2280_led_speed (dev, dev->gadget.speed); DEBUG(dev, "%s\n", usb_speed_string(dev->gadget.speed)); } @@ -2261,32 +3120,38 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) } ep->stopped = 0; dev->protocol_stall = 0; + if (dev->pdev->vendor == 0x10b5) + ep->is_halt = 0; + else{ + if (ep->dev->pdev->device == 0x2280) + tmp = (1 << FIFO_OVERFLOW) | + (1 << FIFO_UNDERFLOW); + else + tmp = 0; - if (ep->dev->pdev->device == 0x2280) - tmp = (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW); - else - tmp = 0; - - writel (tmp | (1 << TIMEOUT) - | (1 << USB_STALL_SENT) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_OUT_PING_NAK_SENT) - | (1 << USB_OUT_ACK_SENT) - | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT) - , &ep->regs->ep_stat); - u.raw [0] = readl (&dev->usb->setup0123); - u.raw [1] = readl (&dev->usb->setup4567); + writel(tmp | (1 << TIMEOUT) | + (1 << USB_STALL_SENT) | + (1 << USB_IN_NAK_SENT) | + (1 << USB_IN_ACK_RCVD) | + (1 << USB_OUT_PING_NAK_SENT) | + (1 << USB_OUT_ACK_SENT) | + (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | + (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | + (1 << DATA_PACKET_RECEIVED_INTERRUPT) | + (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) | + (1 << DATA_OUT_PING_TOKEN_INTERRUPT) | + (1 << DATA_IN_TOKEN_INTERRUPT) + , &ep->regs->ep_stat); + } + u.raw[0] = readl(&dev->usb->setup0123); + u.raw[1] = readl(&dev->usb->setup4567); cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [1]); + if (dev->pdev->vendor == 0x10b5) + defect7374_workaround(dev, u.r); + tmp = 0; #define w_value le16_to_cpu(u.r.wValue) @@ -2318,6 +3183,12 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) * everything else goes uplevel to the gadget code. */ ep->responded = 1; + + if (dev->gadget.speed == USB_SPEED_SUPER) { + handle_stat0_irqs_superspeed(dev, ep, u.r); + goto next_endpoints; + } + switch (u.r.bRequest) { case USB_REQ_GET_STATUS: { struct net2280_ep *e; @@ -2360,8 +3231,11 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) VDEBUG(dev, "%s wedged, halt not cleared\n", ep->ep.name); } else { - VDEBUG(dev, "%s clear halt\n", ep->ep.name); + VDEBUG(dev, "%s clear halt\n", e->ep.name); clear_halt(e); + if (ep->dev->pdev->vendor == 0x10b5 && + !list_empty(&e->queue) && e->td_dma) + restart_dma(e); } allow_status (ep); goto next_endpoints; @@ -2381,6 +3255,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) if (e->ep.name == ep0name) goto do_stall; set_halt (e); + if (dev->pdev->vendor == 0x10b5 && e->dma) + abort_dma(e); allow_status (ep); VDEBUG (dev, "%s set halt\n", ep->ep.name); goto next_endpoints; @@ -2392,7 +3268,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, w_value, w_index, w_length, - readl (&ep->regs->ep_cfg)); + readl(&ep->cfg->ep_cfg)); ep->responded = 0; spin_unlock (&dev->lock); tmp = dev->driver->setup (&dev->gadget, &u.r); @@ -2455,7 +3331,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) /* after disconnect there's nothing else to do! */ tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); - mask = (1 << HIGH_SPEED) | (1 << FULL_SPEED); + mask = (1 << SUPER_SPEED) | (1 << HIGH_SPEED) | (1 << FULL_SPEED); /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set. * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRUPT set and @@ -2546,12 +3422,19 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) tmp = readl (&dma->dmastat); writel (tmp, &dma->dmastat); + /* dma sync*/ + if (dev->pdev->vendor == 0x10b5) { + u32 r_dmacount = readl(&dma->dmacount); + if (!ep->is_in && (r_dmacount & 0x00FFFFFF) && + (tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))) + continue; + } + /* chaining should stop on abort, short OUT from fifo, * or (stat0 codepath) short OUT transfer. */ if (!use_dma_chaining) { - if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) - == 0) { + if (!(tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))) { DEBUG (ep->dev, "%s no xact done? %08x\n", ep->ep.name, tmp); continue; @@ -2625,7 +3508,8 @@ static irqreturn_t net2280_irq (int irq, void *_dev) struct net2280 *dev = _dev; /* shared interrupt, not ours */ - if (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED))) + if (dev->pdev->vendor == 0x17cc && + (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED)))) return IRQ_NONE; spin_lock (&dev->lock); @@ -2636,6 +3520,13 @@ static irqreturn_t net2280_irq (int irq, void *_dev) /* control requests and PIO */ handle_stat0_irqs (dev, readl (&dev->regs->irqstat0)); + if (dev->pdev->vendor == 0x10b5) { + /* re-enable interrupt to trigger any possible new interrupt */ + u32 pciirqenb1 = readl(&dev->regs->pciirqenb1); + writel(pciirqenb1 & 0x7FFFFFFF, &dev->regs->pciirqenb1); + writel(pciirqenb1, &dev->regs->pciirqenb1); + } + spin_unlock (&dev->lock); return IRQ_HANDLED; @@ -2674,6 +3565,8 @@ static void net2280_remove (struct pci_dev *pdev) } if (dev->got_irq) free_irq (pdev->irq, dev); + if (use_msi && dev->pdev->vendor == 0x10b5) + pci_disable_msi(pdev); if (dev->regs) iounmap (dev->regs); if (dev->region) @@ -2708,7 +3601,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - dev->gadget.max_speed = USB_SPEED_HIGH; + dev->gadget.max_speed = (dev->pdev->vendor == 0x10b5) ? + USB_SPEED_SUPER : USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ dev->gadget.name = driver_name; @@ -2750,8 +3644,39 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200); dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300); - /* put into initial config, link up all endpoints */ - writel (0, &dev->usb->usbctl); + if (dev->pdev->vendor == 0x10b5) { + u32 fsmvalue; + u32 usbstat; + dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *) + (base + 0x00b4); + dev->fiforegs = (struct usb338x_fifo_regs __iomem *) + (base + 0x0500); + dev->llregs = (struct usb338x_ll_regs __iomem *) + (base + 0x0700); + dev->ll_lfps_regs = (struct usb338x_ll_lfps_regs __iomem *) + (base + 0x0748); + dev->ll_tsn_regs = (struct usb338x_ll_tsn_regs __iomem *) + (base + 0x077c); + dev->ll_chicken_reg = (struct usb338x_ll_chi_regs __iomem *) + (base + 0x079c); + dev->plregs = (struct usb338x_pl_regs __iomem *) + (base + 0x0800); + usbstat = readl(&dev->usb->usbstat); + dev->enhanced_mode = (usbstat & (1 << 11)) ? 1 : 0; + dev->n_ep = (dev->enhanced_mode) ? 9 : 5; + /* put into initial config, link up all endpoints */ + fsmvalue = get_idx_reg(dev->regs, SCRATCH) & + (0xf << DEFECT7374_FSM_FIELD); + /* See if firmware needs to set up for workaround: */ + if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) + writel(0, &dev->usb->usbctl); + } else{ + dev->enhanced_mode = 0; + dev->n_ep = 7; + /* put into initial config, link up all endpoints */ + writel(0, &dev->usb->usbctl); + } + usb_reset (dev); usb_reinit (dev); @@ -2762,6 +3687,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) goto done; } + if (use_msi && dev->pdev->vendor == 0x10b5) + if (pci_enable_msi(pdev)) + ERROR(dev, "Failed to enable MSI mode\n"); + if (request_irq (pdev->irq, net2280_irq, IRQF_SHARED, driver_name, dev) != 0) { ERROR (dev, "request interrupt %d failed\n", pdev->irq); @@ -2797,7 +3726,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) } /* enable lower-overhead pci memory bursts during DMA */ - writel ( (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) + if (dev->pdev->vendor == 0x17cc) + writel((1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) // 256 write retries may not be enough... // | (1 << PCI_RETRY_ABORT_ENABLE) | (1 << DMA_READ_MULTIPLE_ENABLE) @@ -2814,10 +3744,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) INFO (dev, "%s\n", driver_desc); INFO (dev, "irq %d, pci mem %p, chip rev %04x\n", pdev->irq, base, dev->chiprev); - INFO (dev, "version: " DRIVER_VERSION "; dma %s\n", - use_dma - ? (use_dma_chaining ? "chaining" : "enabled") - : "disabled"); + INFO(dev, "version: " DRIVER_VERSION "; dma %s %s\n", + use_dma ? (use_dma_chaining ? "chaining" : "enabled") + : "disabled", + dev->enhanced_mode ? "enhanced mode" : "legacy mode"); retval = device_create_file (&pdev->dev, &dev_attr_registers); if (retval) goto done; @@ -2849,7 +3779,8 @@ static void net2280_shutdown (struct pci_dev *pdev) writel (0, &dev->usb->usbctl); /* Disable full-speed test mode */ - writel(0, &dev->usb->xcvrdiag); + if (dev->pdev->vendor == 0x17cc) + writel(0, &dev->usb->xcvrdiag); } @@ -2869,8 +3800,24 @@ static const struct pci_device_id pci_ids [] = { { .device = 0x2282, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - -}, { /* end: all zeroes */ } +}, + { + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x10b5, + .device = 0x3380, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x10b5, + .device = 0x3382, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, +{ /* end: all zeroes */ } }; MODULE_DEVICE_TABLE (pci, pci_ids); diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index a844be0d683a..a257516abbd6 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -6,6 +6,7 @@ /* * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) * Copyright (C) 2003 David Brownell + * Copyright (C) 2014 Ricardo Ribalda - Qtechnology/AS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,6 +15,7 @@ */ #include +#include /*-------------------------------------------------------------------------*/ @@ -59,13 +61,14 @@ set_idx_reg (struct net2280_regs __iomem *regs, u32 index, u32 value) #define CHIPREV_1 0x0100 #define CHIPREV_1A 0x0110 -#ifdef __KERNEL__ +/* DEFECT 7374 */ +#define DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS 200 +#define DEFECT_7374_PROCESSOR_WAIT_TIME 10 -/* ep a-f highspeed and fullspeed maxpacket, addresses - * computed from ep->num - */ -#define REG_EP_MAXPKT(dev,num) (((num) + 1) * 0x10 + \ - (((dev)->gadget.speed == USB_SPEED_HIGH) ? 0 : 1)) +/* ep0 max packet size */ +#define EP0_SS_MAX_PACKET_SIZE 0x200 +#define EP0_HS_MAX_PACKET_SIZE 0x40 +#ifdef __KERNEL__ /*-------------------------------------------------------------------------*/ @@ -85,12 +88,15 @@ struct net2280_dma { struct net2280_ep { struct usb_ep ep; + struct net2280_ep_regs __iomem *cfg; struct net2280_ep_regs __iomem *regs; struct net2280_dma_regs __iomem *dma; struct net2280_dma *dummy; + struct usb338x_fifo_regs __iomem *fiforegs; dma_addr_t td_dma; /* of dummy */ struct net2280 *dev; unsigned long irqs; + unsigned is_halt:1, dma_started:1; /* analogous to a host-side qh */ struct list_head queue; @@ -116,10 +122,19 @@ static inline void allow_status (struct net2280_ep *ep) ep->stopped = 1; } -/* count (<= 4) bytes in the next fifo write will be valid */ -static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count) +static void allow_status_338x(struct net2280_ep *ep) { - writeb (count, 2 + (u8 __iomem *) &ep->regs->ep_cfg); + /* + * Control Status Phase Handshake was set by the chip when the setup + * packet arrived. While set, the chip automatically NAKs the host's + * Status Phase tokens. + */ + writel(1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE, &ep->regs->ep_rsp); + + ep->stopped = 1; + + /* TD 9.9 Halt Endpoint test. TD 9.22 set feature test. */ + ep->responded = 0; } struct net2280_request { @@ -135,23 +150,38 @@ struct net2280 { /* each pci device provides one gadget, several endpoints */ struct usb_gadget gadget; spinlock_t lock; - struct net2280_ep ep [7]; + struct net2280_ep ep[9]; struct usb_gadget_driver *driver; unsigned enabled : 1, protocol_stall : 1, softconnect : 1, got_irq : 1, - region : 1; + region:1, + u1_enable:1, + u2_enable:1, + ltm_enable:1, + wakeup_enable:1, + selfpowered:1, + addressed_state:1; u16 chiprev; + int enhanced_mode; + int n_ep; /* pci state used to access those endpoints */ struct pci_dev *pdev; struct net2280_regs __iomem *regs; struct net2280_usb_regs __iomem *usb; + struct usb338x_usb_ext_regs __iomem *usb_ext; struct net2280_pci_regs __iomem *pci; struct net2280_dma_regs __iomem *dma; struct net2280_dep_regs __iomem *dep; struct net2280_ep_regs __iomem *epregs; + struct usb338x_fifo_regs __iomem *fiforegs; + struct usb338x_ll_regs __iomem *llregs; + struct usb338x_ll_lfps_regs __iomem *ll_lfps_regs; + struct usb338x_ll_tsn_regs __iomem *ll_tsn_regs; + struct usb338x_ll_chi_regs __iomem *ll_chicken_reg; + struct usb338x_pl_regs __iomem *plregs; struct pci_pool *requests; // statistics... @@ -179,6 +209,43 @@ static inline void clear_halt (struct net2280_ep *ep) , &ep->regs->ep_rsp); } +/* + * FSM value for Defect 7374 (U1U2 Test) is managed in + * chip's SCRATCH register: + */ +#define DEFECT7374_FSM_FIELD 28 + +/* Waiting for Control Read: + * - A transition to this state indicates a fresh USB connection, + * before the first Setup Packet. The connection speed is not + * known. Firmware is waiting for the first Control Read. + * - Starting state: This state can be thought of as the FSM's typical + * starting state. + * - Tip: Upon the first SS Control Read the FSM never + * returns to this state. + */ +#define DEFECT7374_FSM_WAITING_FOR_CONTROL_READ (1 << DEFECT7374_FSM_FIELD) + +/* Non-SS Control Read: + * - A transition to this state indicates detection of the first HS + * or FS Control Read. + * - Tip: Upon the first SS Control Read the FSM never + * returns to this state. + */ +#define DEFECT7374_FSM_NON_SS_CONTROL_READ (2 << DEFECT7374_FSM_FIELD) + +/* SS Control Read: + * - A transition to this state indicates detection of the + * first SS Control Read. + * - This state indicates workaround completion. Workarounds no longer + * need to be applied (as long as the chip remains powered up). + * - Tip: Once in this state the FSM state does not change (until + * the chip's power is lost and restored). + * - This can be thought of as the final state of the FSM; + * the FSM 'locks-up' in this state until the chip loses power. + */ +#define DEFECT7374_FSM_SS_CONTROL_READ (3 << DEFECT7374_FSM_FIELD) + #ifdef USE_RDK_LEDS static inline void net2280_led_init (struct net2280 *dev) @@ -198,6 +265,9 @@ void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed) { u32 val = readl (&dev->regs->gpioctl); switch (speed) { + case USB_SPEED_SUPER: /* green + red */ + val |= (1 << GPIO0_DATA) | (1 << GPIO1_DATA); + break; case USB_SPEED_HIGH: /* green */ val &= ~(1 << GPIO0_DATA); val |= (1 << GPIO1_DATA); @@ -271,6 +341,17 @@ static inline void net2280_led_shutdown (struct net2280 *dev) /*-------------------------------------------------------------------------*/ +static inline void set_fifo_bytecount(struct net2280_ep *ep, unsigned count) +{ + if (ep->dev->pdev->vendor == 0x17cc) + writeb(count, 2 + (u8 __iomem *) &ep->regs->ep_cfg); + else{ + u32 tmp = readl(&ep->cfg->ep_cfg) & + (~(0x07 << EP_FIFO_BYTE_COUNT)); + writel(tmp | (count << EP_FIFO_BYTE_COUNT), &ep->cfg->ep_cfg); + } +} + static inline void start_out_naking (struct net2280_ep *ep) { /* NOTE: hardware races lurk here, and PING protocol issues */ @@ -305,4 +386,22 @@ static inline void stop_out_naking (struct net2280_ep *ep) writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); } + +static inline void set_max_speed(struct net2280_ep *ep, u32 max) +{ + u32 reg; + static const u32 ep_enhanced[9] = { 0x10, 0x60, 0x30, 0x80, + 0x50, 0x20, 0x70, 0x40, 0x90 }; + + if (ep->dev->enhanced_mode) + reg = ep_enhanced[ep->num]; + else{ + reg = (ep->num + 1) * 0x10; + if (ep->dev->gadget.speed != USB_SPEED_HIGH) + reg += 1; + } + + set_idx_reg(ep->dev->regs, reg, max); +} + #endif /* __KERNEL__ */ diff --git a/include/linux/usb/usb338x.h b/include/linux/usb/usb338x.h new file mode 100644 index 000000000000..f92eb635b9d3 --- /dev/null +++ b/include/linux/usb/usb338x.h @@ -0,0 +1,199 @@ +/* + * USB 338x super/high/full speed USB device controller. + * Unlike many such controllers, this one talks PCI. + * + * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) + * Copyright (C) 2003 David Brownell + * Copyright (C) 2014 Ricardo Ribalda - Qtechnology/AS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __LINUX_USB_USB338X_H +#define __LINUX_USB_USB338X_H + +#include + +/* + * Extra defined bits for net2280 registers + */ +#define SCRATCH 0x0b + +#define DEFECT7374_FSM_FIELD 28 +#define SUPER_SPEED 8 +#define DMA_REQUEST_OUTSTANDING 5 +#define DMA_PAUSE_DONE_INTERRUPT 26 +#define SET_ISOCHRONOUS_DELAY 24 +#define SET_SEL 22 +#define SUPER_SPEED_MODE 8 + +/*ep_cfg*/ +#define MAX_BURST_SIZE 24 +#define EP_FIFO_BYTE_COUNT 16 +#define IN_ENDPOINT_ENABLE 14 +#define IN_ENDPOINT_TYPE 12 +#define OUT_ENDPOINT_ENABLE 10 +#define OUT_ENDPOINT_TYPE 8 + +struct usb338x_usb_ext_regs { + u32 usbclass; +#define DEVICE_PROTOCOL 16 +#define DEVICE_SUB_CLASS 8 +#define DEVICE_CLASS 0 + u32 ss_sel; +#define U2_SYSTEM_EXIT_LATENCY 8 +#define U1_SYSTEM_EXIT_LATENCY 0 + u32 ss_del; +#define U2_DEVICE_EXIT_LATENCY 8 +#define U1_DEVICE_EXIT_LATENCY 0 + u32 usb2lpm; +#define USB_L1_LPM_HIRD 2 +#define USB_L1_LPM_REMOTE_WAKE 1 +#define USB_L1_LPM_SUPPORT 0 + u32 usb3belt; +#define BELT_MULTIPLIER 10 +#define BEST_EFFORT_LATENCY_TOLERANCE 0 + u32 usbctl2; +#define LTM_ENABLE 7 +#define U2_ENABLE 6 +#define U1_ENABLE 5 +#define FUNCTION_SUSPEND 4 +#define USB3_CORE_ENABLE 3 +#define USB2_CORE_ENABLE 2 +#define SERIAL_NUMBER_STRING_ENABLE 0 + u32 in_timeout; +#define GPEP3_TIMEOUT 19 +#define GPEP2_TIMEOUT 18 +#define GPEP1_TIMEOUT 17 +#define GPEP0_TIMEOUT 16 +#define GPEP3_TIMEOUT_VALUE 13 +#define GPEP3_TIMEOUT_ENABLE 12 +#define GPEP2_TIMEOUT_VALUE 9 +#define GPEP2_TIMEOUT_ENABLE 8 +#define GPEP1_TIMEOUT_VALUE 5 +#define GPEP1_TIMEOUT_ENABLE 4 +#define GPEP0_TIMEOUT_VALUE 1 +#define GPEP0_TIMEOUT_ENABLE 0 + u32 isodelay; +#define ISOCHRONOUS_DELAY 0 +} __packed; + +struct usb338x_fifo_regs { + /* offset 0x0500, 0x0520, 0x0540, 0x0560, 0x0580 */ + u32 ep_fifo_size_base; +#define IN_FIFO_BASE_ADDRESS 22 +#define IN_FIFO_SIZE 16 +#define OUT_FIFO_BASE_ADDRESS 6 +#define OUT_FIFO_SIZE 0 + u32 ep_fifo_out_wrptr; + u32 ep_fifo_out_rdptr; + u32 ep_fifo_in_wrptr; + u32 ep_fifo_in_rdptr; + u32 unused[3]; +} __packed; + + +/* Link layer */ +struct usb338x_ll_regs { + /* offset 0x700 */ + u32 ll_ltssm_ctrl1; + u32 ll_ltssm_ctrl2; + u32 ll_ltssm_ctrl3; + u32 unused[2]; + u32 ll_general_ctrl0; + u32 ll_general_ctrl1; +#define PM_U3_AUTO_EXIT 29 +#define PM_U2_AUTO_EXIT 28 +#define PM_U1_AUTO_EXIT 27 +#define PM_FORCE_U2_ENTRY 26 +#define PM_FORCE_U1_ENTRY 25 +#define PM_LGO_COLLISION_SEND_LAU 24 +#define PM_DIR_LINK_REJECT 23 +#define PM_FORCE_LINK_ACCEPT 22 +#define PM_DIR_ENTRY_U3 20 +#define PM_DIR_ENTRY_U2 19 +#define PM_DIR_ENTRY_U1 18 +#define PM_U2_ENABLE 17 +#define PM_U1_ENABLE 16 +#define SKP_THRESHOLD_ADJUST_FMW 8 +#define RESEND_DPP_ON_LRTY_FMW 7 +#define DL_BIT_VALUE_FMW 6 +#define FORCE_DL_BIT 5 + u32 ll_general_ctrl2; +#define SELECT_INVERT_LANE_POLARITY 7 +#define FORCE_INVERT_LANE_POLARITY 6 + u32 ll_general_ctrl3; + u32 ll_general_ctrl4; + u32 ll_error_gen; +} __packed; + +struct usb338x_ll_lfps_regs { + /* offset 0x748 */ + u32 ll_lfps_5; +#define TIMER_LFPS_6US 16 + u32 ll_lfps_6; +#define TIMER_LFPS_80US 0 +} __packed; + +struct usb338x_ll_tsn_regs { + /* offset 0x77C */ + u32 ll_tsn_counters_2; +#define HOT_TX_NORESET_TS2 24 + u32 ll_tsn_counters_3; +#define HOT_RX_RESET_TS2 0 +} __packed; + +struct usb338x_ll_chi_regs { + /* offset 0x79C */ + u32 ll_tsn_chicken_bit; +#define RECOVERY_IDLE_TO_RECOVER_FMW 3 +} __packed; + +/* protocol layer */ +struct usb338x_pl_regs { + /* offset 0x800 */ + u32 pl_reg_1; + u32 pl_reg_2; + u32 pl_reg_3; + u32 pl_reg_4; + u32 pl_ep_ctrl; + /* Protocol Layer Endpoint Control*/ +#define PL_EP_CTRL 0x810 +#define ENDPOINT_SELECT 0 + /* [4:0] */ +#define EP_INITIALIZED 16 +#define SEQUENCE_NUMBER_RESET 17 +#define CLEAR_ACK_ERROR_CODE 20 + u32 pl_reg_6; + u32 pl_reg_7; + u32 pl_reg_8; + u32 pl_ep_status_1; + /* Protocol Layer Endpoint Status 1*/ +#define PL_EP_STATUS_1 0x820 +#define STATE 16 +#define ACK_GOOD_NORMAL 0x11 +#define ACK_GOOD_MORE_ACKS_TO_COME 0x16 + u32 pl_ep_status_2; + u32 pl_ep_status_3; + /* Protocol Layer Endpoint Status 3*/ +#define PL_EP_STATUS_3 0x828 +#define SEQUENCE_NUMBER 0 + u32 pl_ep_status_4; + /* Protocol Layer Endpoint Status 4*/ +#define PL_EP_STATUS_4 0x82c + u32 pl_ep_cfg_4; + /* Protocol Layer Endpoint Configuration 4*/ +#define PL_EP_CFG_4 0x830 +#define NON_CTRL_IN_TOLERATE_BAD_DIR 6 +} __packed; + +#endif /* __LINUX_USB_USB338X_H */ From c2db8a8a01978a1ffad735f31268a1c9c81b413e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:04 +0200 Subject: [PATCH 034/211] usb: gadget: net2280: Dont use magic numbers Instead of using magic numbers use #defines Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 68 +++++++++++++++++++----------------- drivers/usb/gadget/net2280.h | 1 + 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 8112d9140a90..ba1fdd8f675d 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -152,7 +152,7 @@ static inline void enable_pciirqenb(struct net2280_ep *ep) { u32 tmp = readl(&ep->dev->regs->pciirqenb0); - if (ep->dev->pdev->vendor == 0x17cc) + if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) tmp |= 1 << ep->num; else tmp |= 1 << ep_bit[ep->num]; @@ -182,7 +182,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) return -EDOM; - if (dev->pdev->vendor == 0x10b5) { + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { if ((desc->bEndpointAddress & 0x0f) >= 0x0c) return -EDOM; ep->is_in = !!usb_endpoint_dir_in(desc); @@ -192,7 +192,8 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* sanity check ep-e/ep-f since their fifos are small */ max = usb_endpoint_maxp (desc) & 0x1fff; - if (ep->num > 4 && max > 64 && (dev->pdev->vendor == 0x17cc)) + if (ep->num > 4 && max > 64 && + (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY)) return -ERANGE; spin_lock_irqsave (&dev->lock, flags); @@ -237,7 +238,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; /* Enable this endpoint */ - if (dev->pdev->vendor == 0x17cc) { + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) { tmp <<= ENDPOINT_TYPE; tmp |= desc->bEndpointAddress; /* default full fifo lines */ @@ -472,7 +473,7 @@ static int net2280_disable (struct usb_ep *_ep) spin_lock_irqsave (&ep->dev->lock, flags); nuke (ep); - if (ep->dev->pdev->vendor == 0x10b5) + if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) ep_reset_338x(ep->dev->regs, ep); else ep_reset_228x(ep->dev->regs, ep); @@ -799,7 +800,7 @@ static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) writel (readl (&dma->dmastat), &dma->dmastat); writel (td_dma, &dma->dmadesc); - if (ep->dev->pdev->vendor == 0x10b5) + if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) dmactl |= (0x01 << DMA_REQUEST_OUTSTANDING); writel (dmactl, &dma->dmactl); @@ -995,7 +996,7 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* DMA request while EP halted */ if (ep->dma && (readl(&ep->regs->ep_rsp) & (1 << CLEAR_ENDPOINT_HALT)) && - (dev->pdev->vendor == 0x10b5)) { + (dev->pdev->vendor == PCI_VENDOR_ID_PLX)) { int valid = 1; if (ep->is_in) { int expect; @@ -1126,7 +1127,7 @@ static void scan_dma_completions (struct net2280_ep *ep) } else if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { tmp = readl (&ep->regs->ep_stat); - if (ep->dev->pdev->vendor == 0x10b5) + if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) return dma_done(ep, req, tmp, 0); /* AVOID TROUBLE HERE by not issuing short reads from @@ -1234,7 +1235,7 @@ static void abort_dma_338x(struct net2280_ep *ep) static void abort_dma(struct net2280_ep *ep) { - if (ep->dev->pdev->vendor == 0x17cc) + if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) return abort_dma_228x(ep); return abort_dma_338x(ep); } @@ -1392,7 +1393,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) ep->wedged = 1; } else { clear_halt (ep); - if (ep->dev->pdev->vendor == 0x10b5 && + if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX && !list_empty(&ep->queue) && ep->td_dma) restart_dma(ep); ep->wedged = 0; @@ -2104,7 +2105,7 @@ static void usb_reset_338x(struct net2280 *dev) static void usb_reset(struct net2280 *dev) { - if (dev->pdev->vendor == 0x17cc) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) return usb_reset_228x(dev); return usb_reset_338x(dev); } @@ -2260,7 +2261,7 @@ static void usb_reinit_338x(struct net2280 *dev) static void usb_reinit(struct net2280 *dev) { - if (dev->pdev->vendor == 0x17cc) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) return usb_reinit_228x(dev); return usb_reinit_338x(dev); } @@ -2358,7 +2359,7 @@ static void ep0_start_338x(struct net2280 *dev) static void ep0_start(struct net2280 *dev) { - if (dev->pdev->vendor == 0x17cc) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) return ep0_start_228x(dev); return ep0_start_338x(dev); } @@ -2400,7 +2401,7 @@ static int net2280_start(struct usb_gadget *_gadget, if (retval) goto err_func; /* Enable force-full-speed testing mode, if desired */ - if (full_speed && dev->pdev->vendor == 0x17cc) + if (full_speed && dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) writel(1 << FORCE_FULL_SPEED_MODE, &dev->usb->xcvrdiag); /* ... then enable host detection and ep0; and we're ready @@ -2408,7 +2409,7 @@ static int net2280_start(struct usb_gadget *_gadget, */ net2280_led_active (dev, 1); - if (dev->pdev->vendor == 0x10b5) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) defect7374_enable_data_eps_zero(dev); ep0_start (dev); @@ -2471,7 +2472,7 @@ static int net2280_stop(struct usb_gadget *_gadget, net2280_led_active (dev, 0); /* Disable full-speed test mode */ - if (dev->pdev->vendor == 0x17cc) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) writel(0, &dev->usb->xcvrdiag); device_remove_file (&dev->pdev->dev, &dev_attr_function); @@ -3120,7 +3121,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) } ep->stopped = 0; dev->protocol_stall = 0; - if (dev->pdev->vendor == 0x10b5) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) ep->is_halt = 0; else{ if (ep->dev->pdev->device == 0x2280) @@ -3149,7 +3150,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [1]); - if (dev->pdev->vendor == 0x10b5) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) defect7374_workaround(dev, u.r); tmp = 0; @@ -3233,7 +3234,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) } else { VDEBUG(dev, "%s clear halt\n", e->ep.name); clear_halt(e); - if (ep->dev->pdev->vendor == 0x10b5 && + if (ep->dev->pdev->vendor == + PCI_VENDOR_ID_PLX && !list_empty(&e->queue) && e->td_dma) restart_dma(e); } @@ -3255,7 +3257,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) if (e->ep.name == ep0name) goto do_stall; set_halt (e); - if (dev->pdev->vendor == 0x10b5 && e->dma) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX && e->dma) abort_dma(e); allow_status (ep); VDEBUG (dev, "%s set halt\n", ep->ep.name); @@ -3423,7 +3425,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) writel (tmp, &dma->dmastat); /* dma sync*/ - if (dev->pdev->vendor == 0x10b5) { + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { u32 r_dmacount = readl(&dma->dmacount); if (!ep->is_in && (r_dmacount & 0x00FFFFFF) && (tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))) @@ -3508,7 +3510,7 @@ static irqreturn_t net2280_irq (int irq, void *_dev) struct net2280 *dev = _dev; /* shared interrupt, not ours */ - if (dev->pdev->vendor == 0x17cc && + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY && (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED)))) return IRQ_NONE; @@ -3520,7 +3522,7 @@ static irqreturn_t net2280_irq (int irq, void *_dev) /* control requests and PIO */ handle_stat0_irqs (dev, readl (&dev->regs->irqstat0)); - if (dev->pdev->vendor == 0x10b5) { + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { /* re-enable interrupt to trigger any possible new interrupt */ u32 pciirqenb1 = readl(&dev->regs->pciirqenb1); writel(pciirqenb1 & 0x7FFFFFFF, &dev->regs->pciirqenb1); @@ -3565,7 +3567,7 @@ static void net2280_remove (struct pci_dev *pdev) } if (dev->got_irq) free_irq (pdev->irq, dev); - if (use_msi && dev->pdev->vendor == 0x10b5) + if (use_msi && dev->pdev->vendor == PCI_VENDOR_ID_PLX) pci_disable_msi(pdev); if (dev->regs) iounmap (dev->regs); @@ -3601,7 +3603,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - dev->gadget.max_speed = (dev->pdev->vendor == 0x10b5) ? + dev->gadget.max_speed = (dev->pdev->vendor == PCI_VENDOR_ID_PLX) ? USB_SPEED_SUPER : USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ @@ -3644,7 +3646,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200); dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300); - if (dev->pdev->vendor == 0x10b5) { + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { u32 fsmvalue; u32 usbstat; dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *) @@ -3687,7 +3689,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) goto done; } - if (use_msi && dev->pdev->vendor == 0x10b5) + if (use_msi && dev->pdev->vendor == PCI_VENDOR_ID_PLX) if (pci_enable_msi(pdev)) ERROR(dev, "Failed to enable MSI mode\n"); @@ -3726,7 +3728,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) } /* enable lower-overhead pci memory bursts during DMA */ - if (dev->pdev->vendor == 0x17cc) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) writel((1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) // 256 write retries may not be enough... // | (1 << PCI_RETRY_ABORT_ENABLE) @@ -3779,7 +3781,7 @@ static void net2280_shutdown (struct pci_dev *pdev) writel (0, &dev->usb->usbctl); /* Disable full-speed test mode */ - if (dev->pdev->vendor == 0x17cc) + if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) writel(0, &dev->usb->xcvrdiag); } @@ -3789,14 +3791,14 @@ static void net2280_shutdown (struct pci_dev *pdev) static const struct pci_device_id pci_ids [] = { { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, - .vendor = 0x17cc, + .vendor = PCI_VENDOR_ID_PLX_LEGACY, .device = 0x2280, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, - .vendor = 0x17cc, + .vendor = PCI_VENDOR_ID_PLX_LEGACY, .device = 0x2282, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, @@ -3804,7 +3806,7 @@ static const struct pci_device_id pci_ids [] = { { { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, - .vendor = 0x10b5, + .vendor = PCI_VENDOR_ID_PLX, .device = 0x3380, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, @@ -3812,7 +3814,7 @@ static const struct pci_device_id pci_ids [] = { { { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, - .vendor = 0x10b5, + .vendor = PCI_VENDOR_ID_PLX, .device = 0x3382, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index a257516abbd6..30478c8ed878 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -43,6 +43,7 @@ set_idx_reg (struct net2280_regs __iomem *regs, u32 index, u32 value) #endif /* __KERNEL__ */ +#define PCI_VENDOR_ID_PLX_LEGACY 0x17cc #define REG_DIAG 0x0 #define RETRY_COUNTER 16 From 3e76fdcba6b2e30921d280704ea10764f150ec9c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:05 +0200 Subject: [PATCH 035/211] usb: gadget: net2280: Use BIT() macro Improves readability of the code Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 572 +++++++++++++++++------------------ drivers/usb/gadget/net2280.h | 65 ++-- 2 files changed, 318 insertions(+), 319 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index ba1fdd8f675d..5b9368d73b48 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -144,8 +144,8 @@ static char *type_string (u8 bmAttributes) #include "net2280.h" -#define valid_bit cpu_to_le32 (1 << VALID_BIT) -#define dma_done_ie cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE) +#define valid_bit cpu_to_le32(BIT(VALID_BIT)) +#define dma_done_ie cpu_to_le32(BIT(DMA_DONE_INTERRUPT_ENABLE)) /*-------------------------------------------------------------------------*/ static inline void enable_pciirqenb(struct net2280_ep *ep) @@ -153,9 +153,9 @@ static inline void enable_pciirqenb(struct net2280_ep *ep) u32 tmp = readl(&ep->dev->regs->pciirqenb0); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) - tmp |= 1 << ep->num; + tmp |= BIT(ep->num); else - tmp |= 1 << ep_bit[ep->num]; + tmp |= BIT(ep_bit[ep->num]); writel(tmp, &ep->dev->regs->pciirqenb0); return; @@ -218,14 +218,14 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } /* set type, direction, address; reset fifo counters */ - writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat); + writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat); tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); if (tmp == USB_ENDPOINT_XFER_INT) { /* erratum 0105 workaround prevents hs NYET */ if (dev->chiprev == 0100 && dev->gadget.speed == USB_SPEED_HIGH && !(desc->bEndpointAddress & USB_DIR_IN)) - writel ((1 << CLEAR_NAK_OUT_PACKETS_MODE), + writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); } else if (tmp == USB_ENDPOINT_XFER_BULK) { /* catch some particularly blatant driver bugs */ @@ -243,18 +243,18 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) tmp |= desc->bEndpointAddress; /* default full fifo lines */ tmp |= (4 << ENDPOINT_BYTE_COUNT); - tmp |= 1 << ENDPOINT_ENABLE; + tmp |= BIT(ENDPOINT_ENABLE); ep->is_in = (tmp & USB_DIR_IN) != 0; } else { /* In Legacy mode, only OUT endpoints are used */ if (dev->enhanced_mode && ep->is_in) { tmp <<= IN_ENDPOINT_TYPE; - tmp |= (1 << IN_ENDPOINT_ENABLE); + tmp |= BIT(IN_ENDPOINT_ENABLE); /* Not applicable to Legacy */ - tmp |= (1 << ENDPOINT_DIRECTION); + tmp |= BIT(ENDPOINT_DIRECTION); } else { tmp <<= OUT_ENDPOINT_TYPE; - tmp |= (1 << OUT_ENDPOINT_ENABLE); + tmp |= BIT(OUT_ENDPOINT_ENABLE); tmp |= (ep->is_in << ENDPOINT_DIRECTION); } @@ -267,13 +267,13 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* for OUT transfers, block the rx fifo until a read is posted */ if (!ep->is_in) - writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); else if (dev->pdev->device != 0x2280) { /* Added for 2282, Don't use nak packets on an in endpoint, * this was ignored on 2280 */ - writel ((1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); + writel(BIT(CLEAR_NAK_OUT_PACKETS) | + BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); } writel(tmp, &ep->cfg->ep_cfg); @@ -282,13 +282,13 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) if (!ep->dma) { /* pio, per-packet */ enable_pciirqenb(ep); - tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); + tmp = BIT(DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) | + BIT(DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); if (dev->pdev->device == 0x2280) tmp |= readl (&ep->regs->ep_irqenb); writel (tmp, &ep->regs->ep_irqenb); } else { /* dma, per-request */ - tmp = (1 << (8 + ep->num)); /* completion */ + tmp = BIT((8 + ep->num)); /* completion */ tmp |= readl (&dev->regs->pciirqenb1); writel (tmp, &dev->regs->pciirqenb1); @@ -297,7 +297,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) * NOTE erratum 0112 workaround #2 */ if ((desc->bEndpointAddress & USB_DIR_IN) == 0) { - tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE); + tmp = BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE); writel (tmp, &ep->regs->ep_irqenb); enable_pciirqenb(ep); @@ -348,17 +348,17 @@ static void ep_reset_228x(struct net2280_regs __iomem *regs, /* disable the dma, irqs, endpoint... */ if (ep->dma) { writel (0, &ep->dma->dmactl); - writel ( (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) - | (1 << DMA_TRANSACTION_DONE_INTERRUPT) - | (1 << DMA_ABORT) - , &ep->dma->dmastat); + writel(BIT(DMA_SCATTER_GATHER_DONE_INTERRUPT) | + BIT(DMA_TRANSACTION_DONE_INTERRUPT) | + BIT(DMA_ABORT), + &ep->dma->dmastat); tmp = readl (®s->pciirqenb0); - tmp &= ~(1 << ep->num); + tmp &= ~BIT(ep->num); writel (tmp, ®s->pciirqenb0); } else { tmp = readl (®s->pciirqenb1); - tmp &= ~(1 << (8 + ep->num)); /* completion */ + tmp &= ~BIT((8 + ep->num)); /* completion */ writel (tmp, ®s->pciirqenb1); } writel (0, &ep->regs->ep_irqenb); @@ -367,44 +367,44 @@ static void ep_reset_228x(struct net2280_regs __iomem *regs, * packets until the driver queues a read (+note erratum 0112) */ if (!ep->is_in || ep->dev->pdev->device == 0x2280) { - tmp = (1 << SET_NAK_OUT_PACKETS_MODE) - | (1 << SET_NAK_OUT_PACKETS) - | (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_INTERRUPT_MODE); + tmp = BIT(SET_NAK_OUT_PACKETS_MODE) | + BIT(SET_NAK_OUT_PACKETS) | + BIT(CLEAR_EP_HIDE_STATUS_PHASE) | + BIT(CLEAR_INTERRUPT_MODE); } else { /* added for 2282 */ - tmp = (1 << CLEAR_NAK_OUT_PACKETS_MODE) - | (1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_INTERRUPT_MODE); + tmp = BIT(CLEAR_NAK_OUT_PACKETS_MODE) | + BIT(CLEAR_NAK_OUT_PACKETS) | + BIT(CLEAR_EP_HIDE_STATUS_PHASE) | + BIT(CLEAR_INTERRUPT_MODE); } if (ep->num != 0) { - tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) - | (1 << CLEAR_ENDPOINT_HALT); + tmp |= BIT(CLEAR_ENDPOINT_TOGGLE) | + BIT(CLEAR_ENDPOINT_HALT); } writel (tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ if (ep->dev->pdev->device == 0x2280) - tmp = (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW); + tmp = BIT(FIFO_OVERFLOW) | + BIT(FIFO_UNDERFLOW); else tmp = 0; - writel (tmp | (1 << TIMEOUT) - | (1 << USB_STALL_SENT) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_OUT_PING_NAK_SENT) - | (1 << USB_OUT_ACK_SENT) - | (1 << FIFO_FLUSH) - | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT) + writel(tmp | BIT(TIMEOUT) | + BIT(USB_STALL_SENT) | + BIT(USB_IN_NAK_SENT) | + BIT(USB_IN_ACK_RCVD) | + BIT(USB_OUT_PING_NAK_SENT) | + BIT(USB_OUT_ACK_SENT) | + BIT(FIFO_FLUSH) | + BIT(SHORT_PACKET_OUT_DONE_INTERRUPT) | + BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT) | + BIT(DATA_PACKET_RECEIVED_INTERRUPT) | + BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | + BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | + BIT(DATA_IN_TOKEN_INTERRUPT) , &ep->regs->ep_stat); /* fifo size is handled separately */ @@ -424,11 +424,11 @@ static void ep_reset_338x(struct net2280_regs __iomem *regs, /* disable the dma, irqs, endpoint... */ if (ep->dma) { writel(0, &ep->dma->dmactl); - writel((1 << DMA_ABORT_DONE_INTERRUPT) | - (1 << DMA_PAUSE_DONE_INTERRUPT) | - (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) | - (1 << DMA_TRANSACTION_DONE_INTERRUPT) - /* | (1 << DMA_ABORT) */ + writel(BIT(DMA_ABORT_DONE_INTERRUPT) | + BIT(DMA_PAUSE_DONE_INTERRUPT) | + BIT(DMA_SCATTER_GATHER_DONE_INTERRUPT) | + BIT(DMA_TRANSACTION_DONE_INTERRUPT) + /* | BIT(DMA_ABORT) */ , &ep->dma->dmastat); dmastat = readl(&ep->dma->dmastat); @@ -439,24 +439,24 @@ static void ep_reset_338x(struct net2280_regs __iomem *regs, } tmp = readl(®s->pciirqenb0); - tmp &= ~(1 << ep_bit[ep->num]); + tmp &= ~BIT(ep_bit[ep->num]); writel(tmp, ®s->pciirqenb0); } else { if (ep->num < 5) { tmp = readl(®s->pciirqenb1); - tmp &= ~(1 << (8 + ep->num)); /* completion */ + tmp &= ~BIT((8 + ep->num)); /* completion */ writel(tmp, ®s->pciirqenb1); } } writel(0, &ep->regs->ep_irqenb); - writel((1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | - (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | - (1 << FIFO_OVERFLOW) | - (1 << DATA_PACKET_RECEIVED_INTERRUPT) | - (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) | - (1 << DATA_OUT_PING_TOKEN_INTERRUPT) | - (1 << DATA_IN_TOKEN_INTERRUPT), &ep->regs->ep_stat); + writel(BIT(SHORT_PACKET_OUT_DONE_INTERRUPT) | + BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT) | + BIT(FIFO_OVERFLOW) | + BIT(DATA_PACKET_RECEIVED_INTERRUPT) | + BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | + BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | + BIT(DATA_IN_TOKEN_INTERRUPT), &ep->regs->ep_stat); } static void nuke (struct net2280_ep *); @@ -621,20 +621,20 @@ static void out_flush (struct net2280_ep *ep) ASSERT_OUT_NAKING (ep); statp = &ep->regs->ep_stat; - writel ( (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) + writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | + BIT(DATA_PACKET_RECEIVED_INTERRUPT) , statp); - writel ((1 << FIFO_FLUSH), statp); + writel(BIT(FIFO_FLUSH), statp); mb (); tmp = readl (statp); - if (tmp & (1 << DATA_OUT_PING_TOKEN_INTERRUPT) + if (tmp & BIT(DATA_OUT_PING_TOKEN_INTERRUPT) /* high speed did bulk NYET; fifo isn't filling */ && ep->dev->gadget.speed == USB_SPEED_FULL) { unsigned usec; usec = 50; /* 64 byte bulk/interrupt */ - handshake (statp, (1 << USB_OUT_PING_NAK_SENT), - (1 << USB_OUT_PING_NAK_SENT), usec); + handshake(statp, BIT(USB_OUT_PING_NAK_SENT), + BIT(USB_OUT_PING_NAK_SENT), usec); /* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */ } } @@ -661,9 +661,9 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) && ep->dev->gadget.speed == USB_SPEED_FULL) { udelay (1); tmp = readl (&ep->regs->ep_stat); - if ((tmp & (1 << NAK_OUT_PACKETS))) + if ((tmp & BIT(NAK_OUT_PACKETS))) cleanup = 1; - else if ((tmp & (1 << FIFO_FULL))) { + else if ((tmp & BIT(FIFO_FULL))) { start_out_naking (ep); prevent = 1; } @@ -680,7 +680,7 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) tmp = readl (&ep->regs->ep_stat); count = readl (®s->ep_avail); /* handled that data already? */ - if (count == 0 && (tmp & (1 << NAK_OUT_PACKETS)) == 0) + if (count == 0 && (tmp & BIT(NAK_OUT_PACKETS)) == 0) return 0; } @@ -726,7 +726,7 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) if (cleanup) out_flush (ep); if (prevent) { - writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + writel(BIT(CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); (void) readl (&ep->regs->ep_rsp); } @@ -747,16 +747,16 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) * stop the fifo from filling but we can flush it. */ if (ep->is_in) - dmacount |= (1 << DMA_DIRECTION); + dmacount |= BIT(DMA_DIRECTION); if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280) - dmacount |= (1 << END_OF_CHAIN); + dmacount |= BIT(END_OF_CHAIN); req->valid = valid; if (valid) - dmacount |= (1 << VALID_BIT); + dmacount |= BIT(VALID_BIT); if (likely(!req->req.no_interrupt || !use_dma_chaining)) - dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE); + dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE); /* td->dmadesc = previously set by caller */ td->dmaaddr = cpu_to_le32 (req->req.dma); @@ -767,47 +767,47 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) } static const u32 dmactl_default = - (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) - | (1 << DMA_CLEAR_COUNT_ENABLE) + BIT(DMA_SCATTER_GATHER_DONE_INTERRUPT) | + BIT(DMA_CLEAR_COUNT_ENABLE) | /* erratum 0116 workaround part 1 (use POLLING) */ - | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE) - | (1 << DMA_VALID_BIT_POLLING_ENABLE) - | (1 << DMA_VALID_BIT_ENABLE) - | (1 << DMA_SCATTER_GATHER_ENABLE) + (POLL_100_USEC << DESCRIPTOR_POLLING_RATE) | + BIT(DMA_VALID_BIT_POLLING_ENABLE) | + BIT(DMA_VALID_BIT_ENABLE) | + BIT(DMA_SCATTER_GATHER_ENABLE) | /* erratum 0116 workaround part 2 (no AUTOSTART) */ - | (1 << DMA_ENABLE); + BIT(DMA_ENABLE); static inline void spin_stop_dma (struct net2280_dma_regs __iomem *dma) { - handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50); + handshake(&dma->dmactl, BIT(DMA_ENABLE), 0, 50); } static inline void stop_dma (struct net2280_dma_regs __iomem *dma) { - writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl); + writel(readl(&dma->dmactl) & ~BIT(DMA_ENABLE), &dma->dmactl); spin_stop_dma (dma); } static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) { struct net2280_dma_regs __iomem *dma = ep->dma; - unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION); + unsigned int tmp = BIT(VALID_BIT) | (ep->is_in << DMA_DIRECTION); if (ep->dev->pdev->device != 0x2280) - tmp |= (1 << END_OF_CHAIN); + tmp |= BIT(END_OF_CHAIN); writel (tmp, &dma->dmacount); writel (readl (&dma->dmastat), &dma->dmastat); writel (td_dma, &dma->dmadesc); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) - dmactl |= (0x01 << DMA_REQUEST_OUTSTANDING); + dmactl |= BIT(DMA_REQUEST_OUTSTANDING); writel (dmactl, &dma->dmactl); /* erratum 0116 workaround part 3: pci arbiter away from net2280 */ (void) readl (&ep->dev->pci->pcimstctl); - writel ((1 << DMA_START), &dma->dmastat); + writel(BIT(DMA_START), &dma->dmastat); if (!ep->is_in) stop_out_naking (ep); @@ -821,13 +821,13 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) /* FIXME can't use DMA for ZLPs */ /* on this path we "know" there's no dma active (yet) */ - WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE)); + WARN_ON(readl(&dma->dmactl) & BIT(DMA_ENABLE)); writel (0, &ep->dma->dmactl); /* previous OUT packet might have been short */ if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat)) - & (1 << NAK_OUT_PACKETS)) != 0) { - writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT), + & BIT(NAK_OUT_PACKETS)) != 0) { + writel(BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT), &ep->regs->ep_stat); tmp = readl (&ep->regs->ep_avail); @@ -840,13 +840,13 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) /* dma irq, faking scatterlist status */ req->td->dmacount = cpu_to_le32 (req->req.length - tmp); - writel ((1 << DMA_DONE_INTERRUPT_ENABLE) + writel(BIT(DMA_DONE_INTERRUPT_ENABLE) | tmp, &dma->dmacount); req->td->dmadesc = 0; req->valid = 1; - writel ((1 << DMA_ENABLE), &dma->dmactl); - writel ((1 << DMA_START), &dma->dmastat); + writel(BIT(DMA_ENABLE), &dma->dmactl); + writel(BIT(DMA_START), &dma->dmastat); return; } } @@ -860,7 +860,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) if (ep->is_in) { if (likely ((req->req.length % ep->ep.maxpacket) != 0 || req->req.zero)) { - tmp |= (1 << DMA_FIFO_VALIDATE); + tmp |= BIT(DMA_FIFO_VALIDATE); ep->in_fifo_validate = 1; } else ep->in_fifo_validate = 0; @@ -871,21 +871,21 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) fill_dma_desc (ep, req, 1); if (!use_dma_chaining) - req->td->dmacount |= cpu_to_le32 (1 << END_OF_CHAIN); + req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN)); start_queue (ep, tmp, req->td_dma); } static inline void resume_dma(struct net2280_ep *ep) { - writel(readl(&ep->dma->dmactl) | (1 << DMA_ENABLE), &ep->dma->dmactl); + writel(readl(&ep->dma->dmactl) | BIT(DMA_ENABLE), &ep->dma->dmactl); ep->dma_started = true; } static inline void ep_stop_dma(struct net2280_ep *ep) { - writel(readl(&ep->dma->dmactl) & ~(1 << DMA_ENABLE), &ep->dma->dmactl); + writel(readl(&ep->dma->dmactl) & ~BIT(DMA_ENABLE), &ep->dma->dmactl); spin_stop_dma(ep->dma); ep->dma_started = false; @@ -995,7 +995,7 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) if (list_empty (&ep->queue) && !ep->stopped) { /* DMA request while EP halted */ if (ep->dma && - (readl(&ep->regs->ep_rsp) & (1 << CLEAR_ENDPOINT_HALT)) && + (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) && (dev->pdev->vendor == PCI_VENDOR_ID_PLX)) { int valid = 1; if (ep->is_in) { @@ -1028,7 +1028,7 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* OUT FIFO might have packet(s) buffered */ s = readl (&ep->regs->ep_stat); - if ((s & (1 << FIFO_EMPTY)) == 0) { + if ((s & BIT(FIFO_EMPTY)) == 0) { /* note: _req->short_not_ok is * ignored here since PIO _always_ * stops queue advance here, and @@ -1046,8 +1046,8 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } /* don't NAK, let the fifo fill */ - if (req && (s & (1 << NAK_OUT_PACKETS))) - writel ((1 << CLEAR_NAK_OUT_PACKETS), + if (req && (s & BIT(NAK_OUT_PACKETS))) + writel(BIT(CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); } } @@ -1109,7 +1109,7 @@ static void scan_dma_completions (struct net2280_ep *ep) break; rmb (); tmp = le32_to_cpup (&req->td->dmacount); - if ((tmp & (1 << VALID_BIT)) != 0) + if ((tmp & BIT(VALID_BIT)) != 0) break; /* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short" @@ -1134,7 +1134,7 @@ static void scan_dma_completions (struct net2280_ep *ep) * your gadget driver. That helps avoids errata 0121, * 0122, and 0124; not all cases trigger the warning. */ - if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { + if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) { WARNING (ep->dev, "%s lost packet sync!\n", ep->ep.name); req->req.status = -EOVERFLOW; @@ -1179,7 +1179,7 @@ static void restart_dma (struct net2280_ep *ep) ep->in_fifo_validate = likely (req->req.zero || (req->req.length % ep->ep.maxpacket) != 0); if (ep->in_fifo_validate) - dmactl |= (1 << DMA_FIFO_VALIDATE); + dmactl |= BIT(DMA_FIFO_VALIDATE); list_for_each_entry (entry, &ep->queue, queue) { __le32 dmacount; @@ -1220,7 +1220,7 @@ static void abort_dma_228x(struct net2280_ep *ep) /* abort the current transfer */ if (likely (!list_empty (&ep->queue))) { /* FIXME work around errata 0121, 0122, 0124 */ - writel ((1 << DMA_ABORT), &ep->dma->dmastat); + writel(BIT(DMA_ABORT), &ep->dma->dmastat); spin_stop_dma (ep->dma); } else stop_dma (ep->dma); @@ -1229,7 +1229,7 @@ static void abort_dma_228x(struct net2280_ep *ep) static void abort_dma_338x(struct net2280_ep *ep) { - writel((1 << DMA_ABORT), &ep->dma->dmastat); + writel(BIT(DMA_ABORT), &ep->dma->dmastat); spin_stop_dma(ep->dma); } @@ -1431,7 +1431,7 @@ net2280_fifo_status (struct usb_ep *_ep) if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - avail = readl (&ep->regs->ep_avail) & ((1 << 12) - 1); + avail = readl(&ep->regs->ep_avail) & (BIT(12) - 1); if (avail > ep->fifo_size) return -EOVERFLOW; if (ep->is_in) @@ -1450,7 +1450,7 @@ net2280_fifo_flush (struct usb_ep *_ep) if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) return; - writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat); + writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat); (void) readl (&ep->regs->ep_rsp); } @@ -1499,8 +1499,8 @@ static int net2280_wakeup (struct usb_gadget *_gadget) spin_lock_irqsave (&dev->lock, flags); tmp = readl (&dev->usb->usbctl); - if (tmp & (1 << DEVICE_REMOTE_WAKEUP_ENABLE)) - writel (1 << GENERATE_RESUME, &dev->usb->usbstat); + if (tmp & BIT(DEVICE_REMOTE_WAKEUP_ENABLE)) + writel(BIT(GENERATE_RESUME), &dev->usb->usbstat); spin_unlock_irqrestore (&dev->lock, flags); /* pci writes may still be posted */ @@ -1520,10 +1520,10 @@ static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) spin_lock_irqsave (&dev->lock, flags); tmp = readl (&dev->usb->usbctl); if (value) { - tmp |= (1 << SELF_POWERED_STATUS); + tmp |= BIT(SELF_POWERED_STATUS); dev->selfpowered = 1; } else { - tmp &= ~(1 << SELF_POWERED_STATUS); + tmp &= ~BIT(SELF_POWERED_STATUS); dev->selfpowered = 0; } writel (tmp, &dev->usb->usbctl); @@ -1546,9 +1546,9 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) tmp = readl (&dev->usb->usbctl); dev->softconnect = (is_on != 0); if (is_on) - tmp |= (1 << USB_DETECT_ENABLE); + tmp |= BIT(USB_DETECT_ENABLE); else - tmp &= ~(1 << USB_DETECT_ENABLE); + tmp &= ~BIT(USB_DETECT_ENABLE); writel (tmp, &dev->usb->usbctl); spin_unlock_irqrestore (&dev->lock, flags); @@ -1636,8 +1636,8 @@ static ssize_t registers_show(struct device *_dev, /* USB Control Registers */ t1 = readl (&dev->usb->usbctl); t2 = readl (&dev->usb->usbstat); - if (t1 & (1 << VBUS_PIN)) { - if (t2 & (1 << HIGH_SPEED)) + if (t1 & BIT(VBUS_PIN)) { + if (t2 & BIT(HIGH_SPEED)) s = "high speed"; else if (dev->gadget.speed == USB_SPEED_UNKNOWN) s = "powered"; @@ -1672,21 +1672,21 @@ static ssize_t registers_show(struct device *_dev, "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" "irqenb %02x\n", ep->ep.name, t1, t2, - (t2 & (1 << CLEAR_NAK_OUT_PACKETS)) + (t2 & BIT(CLEAR_NAK_OUT_PACKETS)) ? "NAK " : "", - (t2 & (1 << CLEAR_EP_HIDE_STATUS_PHASE)) + (t2 & BIT(CLEAR_EP_HIDE_STATUS_PHASE)) ? "hide " : "", - (t2 & (1 << CLEAR_EP_FORCE_CRC_ERROR)) + (t2 & BIT(CLEAR_EP_FORCE_CRC_ERROR)) ? "CRC " : "", - (t2 & (1 << CLEAR_INTERRUPT_MODE)) + (t2 & BIT(CLEAR_INTERRUPT_MODE)) ? "interrupt " : "", - (t2 & (1<regs->ep_irqenb)); size -= t; @@ -1922,10 +1922,10 @@ static void defect7374_disable_data_eps(struct net2280 *dev) /* Change settings on some selected endpoints */ tmp_reg = readl(&dev->plregs->pl_ep_cfg_4); - tmp_reg &= ~(1 << NON_CTRL_IN_TOLERATE_BAD_DIR); + tmp_reg &= ~BIT(NON_CTRL_IN_TOLERATE_BAD_DIR); writel(tmp_reg, &dev->plregs->pl_ep_cfg_4); tmp_reg = readl(&dev->plregs->pl_ep_ctrl); - tmp_reg |= (1 << EP_INITIALIZED); + tmp_reg |= BIT(EP_INITIALIZED); writel(tmp_reg, &dev->plregs->pl_ep_ctrl); } } @@ -1947,17 +1947,17 @@ static void defect7374_enable_data_eps_zero(struct net2280 *dev) WARNING(dev, "It will operate on cold-reboot and SS connect"); /*GPEPs:*/ - tmp = ((0 << ENDPOINT_NUMBER) | (1 << ENDPOINT_DIRECTION) | + tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) | (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) | ((dev->enhanced_mode) ? - 1 << OUT_ENDPOINT_ENABLE : 1 << ENDPOINT_ENABLE) | - (1 << IN_ENDPOINT_ENABLE)); + BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) | + BIT(IN_ENDPOINT_ENABLE)); for (i = 1; i < 5; i++) writel(tmp, &dev->ep[i].cfg->ep_cfg); /* CSRIN, PCIIN, STATIN, RCIN*/ - tmp = ((0 << ENDPOINT_NUMBER) | (1 << ENDPOINT_ENABLE)); + tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE)); writel(tmp, &dev->dep[1].dep_cfg); writel(tmp, &dev->dep[3].dep_cfg); writel(tmp, &dev->dep[4].dep_cfg); @@ -1974,7 +1974,7 @@ static void defect7374_enable_data_eps_zero(struct net2280 *dev) if (ep_sel == 1) { tmp = (readl(&dev->plregs->pl_ep_ctrl) | - (1 << CLEAR_ACK_ERROR_CODE) | 0); + BIT(CLEAR_ACK_ERROR_CODE) | 0); writel(tmp, &dev->plregs->pl_ep_ctrl); continue; } @@ -1984,11 +1984,11 @@ static void defect7374_enable_data_eps_zero(struct net2280 *dev) continue; tmp = (readl(&dev->plregs->pl_ep_cfg_4) | - (1 << NON_CTRL_IN_TOLERATE_BAD_DIR) | 0); + BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0); writel(tmp, &dev->plregs->pl_ep_cfg_4); tmp = readl(&dev->plregs->pl_ep_ctrl) & - ~(1 << EP_INITIALIZED); + ~BIT(EP_INITIALIZED); writel(tmp, &dev->plregs->pl_ep_ctrl); } @@ -2036,14 +2036,14 @@ static void usb_reset_228x(struct net2280 *dev) } writel (~0, &dev->regs->irqstat0), - writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), + writel(~(u32)BIT(SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), /* reset, and enable pci */ - tmp = readl (&dev->regs->devinit) - | (1 << PCI_ENABLE) - | (1 << FIFO_SOFT_RESET) - | (1 << USB_SOFT_RESET) - | (1 << M8051_RESET); + tmp = readl(&dev->regs->devinit) | + BIT(PCI_ENABLE) | + BIT(FIFO_SOFT_RESET) | + BIT(USB_SOFT_RESET) | + BIT(M8051_RESET); writel (tmp, &dev->regs->devinit); /* standard fifo and endpoint allocations */ @@ -2087,10 +2087,10 @@ static void usb_reset_338x(struct net2280 *dev) if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) { /* reset, and enable pci */ tmp = readl(&dev->regs->devinit) | - (1 << PCI_ENABLE) | - (1 << FIFO_SOFT_RESET) | - (1 << USB_SOFT_RESET) | - (1 << M8051_RESET); + BIT(PCI_ENABLE) | + BIT(FIFO_SOFT_RESET) | + BIT(USB_SOFT_RESET) | + BIT(M8051_RESET); writel(tmp, &dev->regs->devinit); } @@ -2206,7 +2206,7 @@ static void usb_reinit_338x(struct net2280 *dev) __func__, fsmvalue); else { tmp = readl(&dev->usb_ext->usbctl2) & - ~((1 << U1_ENABLE) | (1 << U2_ENABLE) | (1 << LTM_ENABLE)); + ~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE)); writel(tmp, &dev->usb_ext->usbctl2); } @@ -2245,7 +2245,7 @@ static void usb_reinit_338x(struct net2280 *dev) * - Reference PLX TT-7372 */ val = readl(&dev->ll_chicken_reg->ll_tsn_chicken_bit); - val |= (1 << RECOVERY_IDLE_TO_RECOVER_FMW); + val |= BIT(RECOVERY_IDLE_TO_RECOVER_FMW); writel(val, &dev->ll_chicken_reg->ll_tsn_chicken_bit); INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); @@ -2268,9 +2268,9 @@ static void usb_reinit(struct net2280 *dev) static void ep0_start_228x(struct net2280 *dev) { - writel ( (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) + writel(BIT(CLEAR_EP_HIDE_STATUS_PHASE) | + BIT(CLEAR_NAK_OUT_PACKETS) | + BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) , &dev->epregs [0].ep_rsp); /* @@ -2279,31 +2279,31 @@ static void ep0_start_228x(struct net2280 *dev) * endpoint status/features are handled in software, to * help pass tests for some dubious behavior. */ - writel ( (1 << SET_TEST_MODE) - | (1 << SET_ADDRESS) - | (1 << DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP) - | (1 << GET_DEVICE_STATUS) - | (1 << GET_INTERFACE_STATUS) + writel(BIT(SET_TEST_MODE) | + BIT(SET_ADDRESS) | + BIT(DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP) | + BIT(GET_DEVICE_STATUS) | + BIT(GET_INTERFACE_STATUS) , &dev->usb->stdrsp); - writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE) - | (1 << SELF_POWERED_USB_DEVICE) - | (1 << REMOTE_WAKEUP_SUPPORT) - | (dev->softconnect << USB_DETECT_ENABLE) - | (1 << SELF_POWERED_STATUS) - , &dev->usb->usbctl); + writel(BIT(USB_ROOT_PORT_WAKEUP_ENABLE) | + BIT(SELF_POWERED_USB_DEVICE) | + BIT(REMOTE_WAKEUP_SUPPORT) | + (dev->softconnect << USB_DETECT_ENABLE) | + BIT(SELF_POWERED_STATUS), + &dev->usb->usbctl); /* enable irqs so we can see ep0 and general operation */ - writel ( (1 << SETUP_PACKET_INTERRUPT_ENABLE) - | (1 << ENDPOINT_0_INTERRUPT_ENABLE) - , &dev->regs->pciirqenb0); - writel ( (1 << PCI_INTERRUPT_ENABLE) - | (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE) - | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE) - | (1 << PCI_RETRY_ABORT_INTERRUPT_ENABLE) - | (1 << VBUS_INTERRUPT_ENABLE) - | (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) - | (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE) - , &dev->regs->pciirqenb1); + writel(BIT(SETUP_PACKET_INTERRUPT_ENABLE) | + BIT(ENDPOINT_0_INTERRUPT_ENABLE), + &dev->regs->pciirqenb0); + writel(BIT(PCI_INTERRUPT_ENABLE) | + BIT(PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE) | + BIT(PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE) | + BIT(PCI_RETRY_ABORT_INTERRUPT_ENABLE) | + BIT(VBUS_INTERRUPT_ENABLE) | + BIT(ROOT_PORT_RESET_INTERRUPT_ENABLE) | + BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE), + &dev->regs->pciirqenb1); /* don't leave any writes posted */ (void) readl (&dev->usb->usbctl); @@ -2320,8 +2320,8 @@ static void ep0_start_338x(struct net2280 *dev) INFO(dev, "%s: Defect 7374 FsmValue %08x\n", __func__, fsmvalue); else - writel((1 << CLEAR_NAK_OUT_PACKETS_MODE) | - (1 << SET_EP_HIDE_STATUS_PHASE), + writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) | + BIT(SET_EP_HIDE_STATUS_PHASE), &dev->epregs[0].ep_rsp); /* @@ -2330,27 +2330,27 @@ static void ep0_start_338x(struct net2280 *dev) * endpoint status/features are handled in software, to * help pass tests for some dubious behavior. */ - writel((1 << SET_ISOCHRONOUS_DELAY) | - (1 << SET_SEL) | - (1 << SET_TEST_MODE) | - (1 << SET_ADDRESS) | - (1 << GET_INTERFACE_STATUS) | - (1 << GET_DEVICE_STATUS), + writel(BIT(SET_ISOCHRONOUS_DELAY) | + BIT(SET_SEL) | + BIT(SET_TEST_MODE) | + BIT(SET_ADDRESS) | + BIT(GET_INTERFACE_STATUS) | + BIT(GET_DEVICE_STATUS), &dev->usb->stdrsp); dev->wakeup_enable = 1; - writel((1 << USB_ROOT_PORT_WAKEUP_ENABLE) | + writel(BIT(USB_ROOT_PORT_WAKEUP_ENABLE) | (dev->softconnect << USB_DETECT_ENABLE) | - (1 << DEVICE_REMOTE_WAKEUP_ENABLE), + BIT(DEVICE_REMOTE_WAKEUP_ENABLE), &dev->usb->usbctl); /* enable irqs so we can see ep0 and general operation */ - writel((1 << SETUP_PACKET_INTERRUPT_ENABLE) | - (1 << ENDPOINT_0_INTERRUPT_ENABLE) + writel(BIT(SETUP_PACKET_INTERRUPT_ENABLE) | + BIT(ENDPOINT_0_INTERRUPT_ENABLE) , &dev->regs->pciirqenb0); - writel((1 << PCI_INTERRUPT_ENABLE) | - (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) | - (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE) | - (1 << VBUS_INTERRUPT_ENABLE), + writel(BIT(PCI_INTERRUPT_ENABLE) | + BIT(ROOT_PORT_RESET_INTERRUPT_ENABLE) | + BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE) | + BIT(VBUS_INTERRUPT_ENABLE), &dev->regs->pciirqenb1); /* don't leave any writes posted */ @@ -2402,7 +2402,7 @@ static int net2280_start(struct usb_gadget *_gadget, /* Enable force-full-speed testing mode, if desired */ if (full_speed && dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) - writel(1 << FORCE_FULL_SPEED_MODE, &dev->usb->xcvrdiag); + writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag); /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. @@ -2511,7 +2511,7 @@ static void handle_ep_small (struct net2280_ep *ep) ep->ep.name, t, req ? &req->req : 0); #endif if (!ep->is_in || ep->dev->pdev->device == 0x2280) - writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); + writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat); else /* Added for 2282 */ writel (t, &ep->regs->ep_stat); @@ -2529,7 +2529,7 @@ static void handle_ep_small (struct net2280_ep *ep) if (unlikely (ep->num == 0)) { if (ep->is_in) { /* status; stop NAKing */ - if (t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) { + if (t & BIT(DATA_OUT_PING_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) { ep->stopped = 1; set_halt (ep); @@ -2538,7 +2538,7 @@ static void handle_ep_small (struct net2280_ep *ep) allow_status (ep); mode = 2; /* reply to extra IN data tokens with a zlp */ - } else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) { + } else if (t & BIT(DATA_IN_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) { ep->stopped = 1; set_halt (ep); @@ -2549,14 +2549,14 @@ static void handle_ep_small (struct net2280_ep *ep) } } else { /* status; stop NAKing */ - if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) { + if (t & BIT(DATA_IN_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) { ep->stopped = 1; set_halt (ep); } mode = 2; /* an extra OUT token is an error */ - } else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) + } else if (((t & BIT(DATA_OUT_PING_TOKEN_INTERRUPT)) && req && req->req.actual == req->req.length) || (ep->responded && !req)) { @@ -2575,7 +2575,7 @@ static void handle_ep_small (struct net2280_ep *ep) /* manual DMA queue advance after short OUT */ if (likely (ep->dma)) { - if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { + if (t & BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)) { u32 count; int stopped = ep->stopped; @@ -2601,7 +2601,7 @@ static void handle_ep_small (struct net2280_ep *ep) /* here either (M < N), a "real" short rx; * or (M == N) and the queue didn't empty */ - if (likely (t & (1 << FIFO_EMPTY))) { + if (likely(t & BIT(FIFO_EMPTY))) { count = readl (&ep->dma->dmacount); count &= DMA_BYTE_COUNT_MASK; if (readl (&ep->dma->dmadesc) @@ -2613,7 +2613,7 @@ static void handle_ep_small (struct net2280_ep *ep) } /* stop DMA, leave ep NAKing */ - writel ((1 << DMA_ABORT), &ep->dma->dmastat); + writel(BIT(DMA_ABORT), &ep->dma->dmastat); spin_stop_dma (ep->dma); if (likely (req)) { @@ -2643,12 +2643,12 @@ static void handle_ep_small (struct net2280_ep *ep) return; /* data packet(s) received (in the fifo, OUT) */ - } else if (t & (1 << DATA_PACKET_RECEIVED_INTERRUPT)) { + } else if (t & BIT(DATA_PACKET_RECEIVED_INTERRUPT)) { if (read_fifo (ep, req) && ep->num != 0) mode = 2; /* data packet(s) transmitted (IN) */ - } else if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) { + } else if (t & BIT(DATA_PACKET_TRANSMITTED_INTERRUPT)) { unsigned len; len = req->req.length - req->req.actual; @@ -2699,7 +2699,7 @@ static void handle_ep_small (struct net2280_ep *ep) if (req && !ep->stopped) { /* load IN fifo with next packet (may be zlp) */ - if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) + if (t & BIT(DATA_PACKET_TRANSMITTED_INTERRUPT)) write_fifo (ep, &req->req); } } @@ -2740,7 +2740,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r) return; /* This is the first Control Read for this connection: */ - if (!(readl(&dev->usb->usbstat) & (1 << SUPER_SPEED_MODE))) { + if (!(readl(&dev->usb->usbstat) & BIT(SUPER_SPEED_MODE))) { /* * Connection is NOT SS: * - Connection must be FS or HS. @@ -2804,9 +2804,9 @@ static void ep_stall(struct net2280_ep *ep, int stall) static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 }; if (stall) { - writel((1 << SET_ENDPOINT_HALT) | - /* (1 << SET_NAK_PACKETS) | */ - (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE), + writel(BIT(SET_ENDPOINT_HALT) | + /* BIT(SET_NAK_PACKETS) | */ + BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE), &ep->regs->ep_rsp); ep->is_halt = 1; } else { @@ -2819,14 +2819,14 @@ static void ep_stall(struct net2280_ep *ep, int stall) val = (val & ~0x1f) | ep_pl[ep->num]; writel(val, &dev->plregs->pl_ep_ctrl); - val |= (1 << SEQUENCE_NUMBER_RESET); + val |= BIT(SEQUENCE_NUMBER_RESET); writel(val, &dev->plregs->pl_ep_ctrl); } val = readl(&ep->regs->ep_rsp); - val |= (1 << CLEAR_ENDPOINT_HALT) | - (1 << CLEAR_ENDPOINT_TOGGLE); + val |= BIT(CLEAR_ENDPOINT_HALT) | + BIT(CLEAR_ENDPOINT_TOGGLE); writel(val - /* | (1 << CLEAR_NAK_PACKETS)*/ + /* | BIT(CLEAR_NAK_PACKETS)*/ , &ep->regs->ep_rsp); ep->is_halt = 0; val = readl(&ep->regs->ep_rsp); @@ -2895,7 +2895,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE): status = dev->wakeup_enable ? 0x02 : 0x00; if (dev->selfpowered) - status |= 1 << 0; + status |= BIT(0); status |= (dev->u1_enable << 2 | dev->u2_enable << 3 | dev->ltm_enable << 4); writel(0, &dev->epregs[0].ep_irqenb); @@ -2909,7 +2909,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, if (!e) goto do_stall3; status = readl(&e->regs->ep_rsp) & - (1 << CLEAR_ENDPOINT_HALT); + BIT(CLEAR_ENDPOINT_HALT); writel(0, &dev->epregs[0].ep_irqenb); set_fifo_bytecount(ep, sizeof(status)); writel((__force u32) status, &dev->epregs[0].ep_data); @@ -2929,7 +2929,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, case USB_DEVICE_U1_ENABLE: dev->u1_enable = 0; writel(readl(&dev->usb_ext->usbctl2) & - ~(1 << U1_ENABLE), + ~BIT(U1_ENABLE), &dev->usb_ext->usbctl2); allow_status_338x(ep); goto next_endpoints3; @@ -2937,7 +2937,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, case USB_DEVICE_U2_ENABLE: dev->u2_enable = 0; writel(readl(&dev->usb_ext->usbctl2) & - ~(1 << U2_ENABLE), + ~BIT(U2_ENABLE), &dev->usb_ext->usbctl2); allow_status_338x(ep); goto next_endpoints3; @@ -2945,7 +2945,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, case USB_DEVICE_LTM_ENABLE: dev->ltm_enable = 0; writel(readl(&dev->usb_ext->usbctl2) & - ~(1 << LTM_ENABLE), + ~BIT(LTM_ENABLE), &dev->usb_ext->usbctl2); allow_status_338x(ep); goto next_endpoints3; @@ -2957,7 +2957,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, if (w_value == USB_DEVICE_REMOTE_WAKEUP) { dev->wakeup_enable = 0; writel(readl(&dev->usb->usbctl) & - ~(1 << DEVICE_REMOTE_WAKEUP_ENABLE), + ~BIT(DEVICE_REMOTE_WAKEUP_ENABLE), &dev->usb->usbctl); allow_status_338x(ep); break; @@ -2990,7 +2990,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, case USB_DEVICE_U1_ENABLE: dev->u1_enable = 1; writel(readl(&dev->usb_ext->usbctl2) | - (1 << U1_ENABLE), + BIT(U1_ENABLE), &dev->usb_ext->usbctl2); allow_status_338x(ep); goto next_endpoints3; @@ -2998,7 +2998,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, case USB_DEVICE_U2_ENABLE: dev->u2_enable = 1; writel(readl(&dev->usb_ext->usbctl2) | - (1 << U2_ENABLE), + BIT(U2_ENABLE), &dev->usb_ext->usbctl2); allow_status_338x(ep); goto next_endpoints3; @@ -3006,7 +3006,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, case USB_DEVICE_LTM_ENABLE: dev->ltm_enable = 1; writel(readl(&dev->usb_ext->usbctl2) | - (1 << LTM_ENABLE), + BIT(LTM_ENABLE), &dev->usb_ext->usbctl2); allow_status_338x(ep); goto next_endpoints3; @@ -3018,7 +3018,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, if (w_value == USB_DEVICE_REMOTE_WAKEUP) { dev->wakeup_enable = 1; writel(readl(&dev->usb->usbctl) | - (1 << DEVICE_REMOTE_WAKEUP_ENABLE), + BIT(DEVICE_REMOTE_WAKEUP_ENABLE), &dev->usb->usbctl); allow_status_338x(ep); break; @@ -3075,13 +3075,13 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) u32 num, scratch; /* most of these don't need individual acks */ - stat &= ~(1 << INTA_ASSERTED); + stat &= ~BIT(INTA_ASSERTED); if (!stat) return; // DEBUG (dev, "irqstat0 %04x\n", stat); /* starting a control request? */ - if (unlikely (stat & (1 << SETUP_PACKET_INTERRUPT))) { + if (unlikely(stat & BIT(SETUP_PACKET_INTERRUPT))) { union { u32 raw [2]; struct usb_ctrlrequest r; @@ -3091,11 +3091,11 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) if (dev->gadget.speed == USB_SPEED_UNKNOWN) { u32 val = readl(&dev->usb->usbstat); - if (val & (1 << SUPER_SPEED)) { + if (val & BIT(SUPER_SPEED)) { dev->gadget.speed = USB_SPEED_SUPER; usb_ep_set_maxpacket_limit(&dev->ep[0].ep, EP0_SS_MAX_PACKET_SIZE); - } else if (val & (1 << HIGH_SPEED)) { + } else if (val & BIT(HIGH_SPEED)) { dev->gadget.speed = USB_SPEED_HIGH; usb_ep_set_maxpacket_limit(&dev->ep[0].ep, EP0_HS_MAX_PACKET_SIZE); @@ -3112,7 +3112,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) ep->irqs++; /* make sure any leftover request state is cleared */ - stat &= ~(1 << ENDPOINT_0_INTERRUPT); + stat &= ~BIT(ENDPOINT_0_INTERRUPT); while (!list_empty (&ep->queue)) { req = list_entry (ep->queue.next, struct net2280_request, queue); @@ -3125,23 +3125,23 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) ep->is_halt = 0; else{ if (ep->dev->pdev->device == 0x2280) - tmp = (1 << FIFO_OVERFLOW) | - (1 << FIFO_UNDERFLOW); + tmp = BIT(FIFO_OVERFLOW) | + BIT(FIFO_UNDERFLOW); else tmp = 0; - writel(tmp | (1 << TIMEOUT) | - (1 << USB_STALL_SENT) | - (1 << USB_IN_NAK_SENT) | - (1 << USB_IN_ACK_RCVD) | - (1 << USB_OUT_PING_NAK_SENT) | - (1 << USB_OUT_ACK_SENT) | - (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | - (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | - (1 << DATA_PACKET_RECEIVED_INTERRUPT) | - (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) | - (1 << DATA_OUT_PING_TOKEN_INTERRUPT) | - (1 << DATA_IN_TOKEN_INTERRUPT) + writel(tmp | BIT(TIMEOUT) | + BIT(USB_STALL_SENT) | + BIT(USB_IN_NAK_SENT) | + BIT(USB_IN_ACK_RCVD) | + BIT(USB_OUT_PING_NAK_SENT) | + BIT(USB_OUT_ACK_SENT) | + BIT(SHORT_PACKET_OUT_DONE_INTERRUPT) | + BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT) | + BIT(DATA_PACKET_RECEIVED_INTERRUPT) | + BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | + BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | + BIT(DATA_IN_TOKEN_INTERRUPT) , &ep->regs->ep_stat); } u.raw[0] = readl(&dev->usb->setup0123); @@ -3160,8 +3160,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) #define w_length le16_to_cpu(u.r.wLength) /* ack the irq */ - writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); - stat ^= (1 << SETUP_PACKET_INTERRUPT); + writel(BIT(SETUP_PACKET_INTERRUPT), &dev->regs->irqstat0); + stat ^= BIT(SETUP_PACKET_INTERRUPT); /* watch control traffic at the token level, and force * synchronization before letting the status stage happen. @@ -3170,14 +3170,14 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) */ ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; if (ep->is_in) { - scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT); + scratch = BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | + BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | + BIT(DATA_IN_TOKEN_INTERRUPT); stop_out_naking (ep); } else - scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT); + scratch = BIT(DATA_PACKET_RECEIVED_INTERRUPT) | + BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | + BIT(DATA_IN_TOKEN_INTERRUPT); writel (scratch, &dev->epregs [0].ep_irqenb); /* we made the hardware handle most lowlevel requests; @@ -3202,8 +3202,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) || w_length > 2) goto do_stall; - if (readl (&e->regs->ep_rsp) - & (1 << SET_ENDPOINT_HALT)) + if (readl(&e->regs->ep_rsp) & BIT(SET_ENDPOINT_HALT)) status = cpu_to_le32 (1); else status = cpu_to_le32 (0); @@ -3303,7 +3302,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) u32 t; /* do this endpoint's FIFO and queue need tending? */ - t = 1 << num; + t = BIT(num); if ((scratch & t) == 0) continue; scratch ^= t; @@ -3316,15 +3315,14 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) DEBUG (dev, "unhandled irqstat0 %08x\n", stat); } -#define DMA_INTERRUPTS ( \ - (1 << DMA_D_INTERRUPT) \ - | (1 << DMA_C_INTERRUPT) \ - | (1 << DMA_B_INTERRUPT) \ - | (1 << DMA_A_INTERRUPT)) +#define DMA_INTERRUPTS (BIT(DMA_D_INTERRUPT) | \ + BIT(DMA_C_INTERRUPT) | \ + BIT(DMA_B_INTERRUPT) | \ + BIT(DMA_A_INTERRUPT)) #define PCI_ERROR_INTERRUPTS ( \ - (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT) \ - | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT) \ - | (1 << PCI_RETRY_ABORT_INTERRUPT)) + BIT(PCI_MASTER_ABORT_RECEIVED_INTERRUPT) | \ + BIT(PCI_TARGET_ABORT_RECEIVED_INTERRUPT) | \ + BIT(PCI_RETRY_ABORT_INTERRUPT)) static void handle_stat1_irqs (struct net2280 *dev, u32 stat) { @@ -3332,8 +3330,8 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) u32 tmp, num, mask, scratch; /* after disconnect there's nothing else to do! */ - tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); - mask = (1 << SUPER_SPEED) | (1 << HIGH_SPEED) | (1 << FULL_SPEED); + tmp = BIT(VBUS_INTERRUPT) | BIT(ROOT_PORT_RESET_INTERRUPT); + mask = BIT(SUPER_SPEED) | BIT(HIGH_SPEED) | BIT(FULL_SPEED); /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set. * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRUPT set and @@ -3342,11 +3340,11 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) */ if (stat & tmp) { writel (tmp, &dev->regs->irqstat1); - if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) + if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) && ((readl (&dev->usb->usbstat) & mask) == 0)) || ((readl (&dev->usb->usbctl) - & (1 << VBUS_PIN)) == 0) + & BIT(VBUS_PIN)) == 0) ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) { DEBUG (dev, "disconnect %s\n", dev->driver->driver.name); @@ -3366,14 +3364,14 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) /* NOTE: chip stays in PCI D0 state for now, but it could * enter D1 to save more power */ - tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT); + tmp = BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT); if (stat & tmp) { writel (tmp, &dev->regs->irqstat1); - if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { + if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) dev->driver->suspend (&dev->gadget); if (!enable_suspend) - stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); + stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT); } else { if (dev->driver->resume) dev->driver->resume (&dev->gadget); @@ -3388,15 +3386,15 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) /* some status we can just ignore */ if (dev->pdev->device == 0x2280) - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << SUSPEND_REQUEST_INTERRUPT) - | (1 << RESUME_INTERRUPT) - | (1 << SOF_INTERRUPT)); + stat &= ~(BIT(CONTROL_STATUS_INTERRUPT) | + BIT(SUSPEND_REQUEST_INTERRUPT) | + BIT(RESUME_INTERRUPT) | + BIT(SOF_INTERRUPT)); else - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << RESUME_INTERRUPT) - | (1 << SOF_DOWN_INTERRUPT) - | (1 << SOF_INTERRUPT)); + stat &= ~(BIT(CONTROL_STATUS_INTERRUPT) | + BIT(RESUME_INTERRUPT) | + BIT(SOF_DOWN_INTERRUPT) | + BIT(SOF_INTERRUPT)); if (!stat) return; @@ -3409,7 +3407,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) for (num = 0; scratch; num++) { struct net2280_dma_regs __iomem *dma; - tmp = 1 << num; + tmp = BIT(num); if ((tmp & scratch) == 0) continue; scratch ^= tmp; @@ -3428,7 +3426,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { u32 r_dmacount = readl(&dma->dmacount); if (!ep->is_in && (r_dmacount & 0x00FFFFFF) && - (tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))) + (tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) continue; } @@ -3436,7 +3434,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) * or (stat0 codepath) short OUT transfer. */ if (!use_dma_chaining) { - if (!(tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))) { + if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) { DEBUG (ep->dev, "%s no xact done? %08x\n", ep->ep.name, tmp); continue; @@ -3462,8 +3460,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) stop_dma (ep->dma); } else { tmp = readl (&dma->dmactl); - if (!use_dma_chaining - || (tmp & (1 << DMA_ENABLE)) == 0) + if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0) restart_dma (ep); else if (ep->is_in && use_dma_chaining) { struct net2280_request *req; @@ -3477,9 +3474,8 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) req = list_entry (ep->queue.next, struct net2280_request, queue); dmacount = req->td->dmacount; - dmacount &= cpu_to_le32 ( - (1 << VALID_BIT) - | DMA_BYTE_COUNT_MASK); + dmacount &= cpu_to_le32(BIT(VALID_BIT) | + DMA_BYTE_COUNT_MASK); if (dmacount && (dmacount & valid_bit) == 0) restart_dma (ep); } @@ -3511,7 +3507,7 @@ static irqreturn_t net2280_irq (int irq, void *_dev) /* shared interrupt, not ours */ if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY && - (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED)))) + (!(readl(&dev->regs->irqstat0) & BIT(INTA_ASSERTED)))) return IRQ_NONE; spin_lock (&dev->lock); @@ -3664,7 +3660,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->plregs = (struct usb338x_pl_regs __iomem *) (base + 0x0800); usbstat = readl(&dev->usb->usbstat); - dev->enhanced_mode = (usbstat & (1 << 11)) ? 1 : 0; + dev->enhanced_mode = (usbstat & BIT(11)) ? 1 : 0; dev->n_ep = (dev->enhanced_mode) ? 9 : 5; /* put into initial config, link up all endpoints */ fsmvalue = get_idx_reg(dev->regs, SCRATCH) & @@ -3729,12 +3725,14 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) /* enable lower-overhead pci memory bursts during DMA */ if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) - writel((1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) - // 256 write retries may not be enough... - // | (1 << PCI_RETRY_ABORT_ENABLE) - | (1 << DMA_READ_MULTIPLE_ENABLE) - | (1 << DMA_READ_LINE_ENABLE) - , &dev->pci->pcimstctl); + writel(BIT(DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) | + /* + * 256 write retries may not be enough... + BIT(PCI_RETRY_ABORT_ENABLE) | + */ + BIT(DMA_READ_MULTIPLE_ENABLE) | + BIT(DMA_READ_LINE_ENABLE), + &dev->pci->pcimstctl); /* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */ pci_set_master (pdev); pci_try_set_mwi (pdev); diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index 30478c8ed878..e1c5d1a5a7d0 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -116,9 +116,9 @@ struct net2280_ep { static inline void allow_status (struct net2280_ep *ep) { /* ep0 only */ - writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - | (1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_NAK_OUT_PACKETS_MODE) + writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) | + BIT(CLEAR_NAK_OUT_PACKETS) | + BIT(CLEAR_NAK_OUT_PACKETS_MODE) , &ep->regs->ep_rsp); ep->stopped = 1; } @@ -130,7 +130,7 @@ static void allow_status_338x(struct net2280_ep *ep) * packet arrived. While set, the chip automatically NAKs the host's * Status Phase tokens. */ - writel(1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE, &ep->regs->ep_rsp); + writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE), &ep->regs->ep_rsp); ep->stopped = 1; @@ -191,23 +191,24 @@ struct net2280 { static inline void set_halt (struct net2280_ep *ep) { /* ep0 and bulk/intr endpoints */ - writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - /* set NAK_OUT for erratum 0114 */ - | ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) - | (1 << SET_ENDPOINT_HALT) - , &ep->regs->ep_rsp); + writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) | + /* set NAK_OUT for erratum 0114 */ + ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) | + BIT(SET_ENDPOINT_HALT), + &ep->regs->ep_rsp); } static inline void clear_halt (struct net2280_ep *ep) { /* ep0 and bulk/intr endpoints */ - writel ( (1 << CLEAR_ENDPOINT_HALT) - | (1 << CLEAR_ENDPOINT_TOGGLE) - /* unless the gadget driver left a short packet in the + writel(BIT(CLEAR_ENDPOINT_HALT) | + BIT(CLEAR_ENDPOINT_TOGGLE) | + /* + * unless the gadget driver left a short packet in the * fifo, this reverses the erratum 0114 workaround. */ - | ((ep->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS) - , &ep->regs->ep_rsp); + ((ep->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS), + &ep->regs->ep_rsp); } /* @@ -225,7 +226,7 @@ static inline void clear_halt (struct net2280_ep *ep) * - Tip: Upon the first SS Control Read the FSM never * returns to this state. */ -#define DEFECT7374_FSM_WAITING_FOR_CONTROL_READ (1 << DEFECT7374_FSM_FIELD) +#define DEFECT7374_FSM_WAITING_FOR_CONTROL_READ BIT(DEFECT7374_FSM_FIELD) /* Non-SS Control Read: * - A transition to this state indicates detection of the first HS @@ -252,12 +253,12 @@ static inline void clear_halt (struct net2280_ep *ep) static inline void net2280_led_init (struct net2280 *dev) { /* LED3 (green) is on during USB activity. note erratum 0113. */ - writel ((1 << GPIO3_LED_SELECT) - | (1 << GPIO3_OUTPUT_ENABLE) - | (1 << GPIO2_OUTPUT_ENABLE) - | (1 << GPIO1_OUTPUT_ENABLE) - | (1 << GPIO0_OUTPUT_ENABLE) - , &dev->regs->gpioctl); + writel(BIT(GPIO3_LED_SELECT) | + BIT(GPIO3_OUTPUT_ENABLE) | + BIT(GPIO2_OUTPUT_ENABLE) | + BIT(GPIO1_OUTPUT_ENABLE) | + BIT(GPIO0_OUTPUT_ENABLE), + &dev->regs->gpioctl); } /* indicate speed with bi-color LED 0/1 */ @@ -267,18 +268,18 @@ void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed) u32 val = readl (&dev->regs->gpioctl); switch (speed) { case USB_SPEED_SUPER: /* green + red */ - val |= (1 << GPIO0_DATA) | (1 << GPIO1_DATA); + val |= BIT(GPIO0_DATA) | BIT(GPIO1_DATA); break; case USB_SPEED_HIGH: /* green */ - val &= ~(1 << GPIO0_DATA); - val |= (1 << GPIO1_DATA); + val &= ~BIT(GPIO0_DATA); + val |= BIT(GPIO1_DATA); break; case USB_SPEED_FULL: /* red */ - val &= ~(1 << GPIO1_DATA); - val |= (1 << GPIO0_DATA); + val &= ~BIT(GPIO1_DATA); + val |= BIT(GPIO0_DATA); break; default: /* (off/black) */ - val &= ~((1 << GPIO1_DATA) | (1 << GPIO0_DATA)); + val &= ~(BIT(GPIO1_DATA) | BIT(GPIO0_DATA)); break; } writel (val, &dev->regs->gpioctl); @@ -356,7 +357,7 @@ static inline void set_fifo_bytecount(struct net2280_ep *ep, unsigned count) static inline void start_out_naking (struct net2280_ep *ep) { /* NOTE: hardware races lurk here, and PING protocol issues */ - writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); /* synch with device */ readl (&ep->regs->ep_rsp); } @@ -366,10 +367,10 @@ static inline void assert_out_naking (struct net2280_ep *ep, const char *where) { u32 tmp = readl (&ep->regs->ep_stat); - if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { + if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) { DEBUG (ep->dev, "%s %s %08x !NAK\n", ep->ep.name, where, tmp); - writel ((1 << SET_NAK_OUT_PACKETS), + writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); } } @@ -383,8 +384,8 @@ static inline void stop_out_naking (struct net2280_ep *ep) u32 tmp; tmp = readl (&ep->regs->ep_stat); - if ((tmp & (1 << NAK_OUT_PACKETS)) != 0) - writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + if ((tmp & BIT(NAK_OUT_PACKETS)) != 0) + writel(BIT(CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); } From 00d4db0e8539571382e9629c6bc5195263f6a960 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:06 +0200 Subject: [PATCH 036/211] usb: gadget: net2280: Use true/false instead of 1/0 For bool variables Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 5b9368d73b48..b43725a039c6 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -95,9 +95,9 @@ static const char *const ep_name [] = { * Some gadget drivers work better with the dma support here than others. * These two parameters let you use PIO or more aggressive DMA. */ -static bool use_dma = 1; -static bool use_dma_chaining = 0; -static bool use_msi = 1; +static bool use_dma = true; +static bool use_dma_chaining; +static bool use_msi = true; /* "modprobe net2280 use_dma=n" etc */ module_param (use_dma, bool, S_IRUGO); @@ -118,7 +118,7 @@ module_param (fifo_mode, ushort, 0644); * USB suspend requests will be ignored. This is acceptable for * self-powered devices */ -static bool enable_suspend = 0; +static bool enable_suspend; /* "modprobe net2280 enable_suspend=1" etc */ module_param (enable_suspend, bool, S_IRUGO); From 9a028e46fc0aeb0e5036ac1f4393653404242a1a Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:07 +0200 Subject: [PATCH 037/211] usb: gadget: net2280: Use module_pci_driver macro Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index b43725a039c6..bd851de7112b 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -3588,6 +3588,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) void __iomem *base = NULL; int retval, i; + if (!use_dma) + use_dma_chaining = 0; + /* alloc, and start init */ dev = kzalloc (sizeof *dev, GFP_KERNEL); if (dev == NULL){ @@ -3833,20 +3836,8 @@ static struct pci_driver net2280_pci_driver = { /* FIXME add power management support */ }; +module_pci_driver(net2280_pci_driver); + MODULE_DESCRIPTION (DRIVER_DESC); MODULE_AUTHOR ("David Brownell"); MODULE_LICENSE ("GPL"); - -static int __init init (void) -{ - if (!use_dma) - use_dma_chaining = 0; - return pci_register_driver (&net2280_pci_driver); -} -module_init (init); - -static void __exit cleanup (void) -{ - pci_unregister_driver (&net2280_pci_driver); -} -module_exit (cleanup); From a27f37a13cfbcfaeb987a910661a860f8d2f915e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:08 +0200 Subject: [PATCH 038/211] usb: gadget: net2280: Refactor queues_show Replace a long and ugly expresion with an already available function. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index bd851de7112b..c3205ec9560c 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1777,15 +1777,7 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr, "\n%s (ep%d%s-%s) max %04x %s fifo %d\n", ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK, (t & USB_DIR_IN) ? "in" : "out", - ({ char *val; - switch (d->bmAttributes & 0x03) { - case USB_ENDPOINT_XFER_BULK: - val = "bulk"; break; - case USB_ENDPOINT_XFER_INT: - val = "intr"; break; - default: - val = "iso"; break; - } val; }), + type_string(d->bmAttributes), usb_endpoint_maxp (d) & 0x1fff, ep->dma ? "dma" : "pio", ep->fifo_size ); From fae3c158800339765a2580ac5d6236ae116ec5cb Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:09 +0200 Subject: [PATCH 039/211] usb: gadget: net2280: Pass checkpacth.pl test Fix Code Style using checkpatch.pl criteria Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 1119 +++++++++++++++++----------------- drivers/usb/gadget/net2280.h | 90 +-- 2 files changed, 602 insertions(+), 607 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index c3205ec9560c..d1d4f4fc9da7 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -62,9 +62,9 @@ #include #include #include +#include #include -#include #include #include @@ -76,12 +76,12 @@ #define USE_RDK_LEDS /* GPIO pins control three LEDs */ -static const char driver_name [] = "net2280"; -static const char driver_desc [] = DRIVER_DESC; +static const char driver_name[] = "net2280"; +static const char driver_desc[] = DRIVER_DESC; static const u32 ep_bit[9] = { 0, 17, 2, 19, 4, 1, 18, 3, 20 }; -static const char ep0name [] = "ep0"; -static const char *const ep_name [] = { +static const char ep0name[] = "ep0"; +static const char *const ep_name[] = { ep0name, "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", "ep-g", "ep-h", @@ -100,15 +100,15 @@ static bool use_dma_chaining; static bool use_msi = true; /* "modprobe net2280 use_dma=n" etc */ -module_param (use_dma, bool, S_IRUGO); -module_param (use_dma_chaining, bool, S_IRUGO); +module_param(use_dma, bool, S_IRUGO); +module_param(use_dma_chaining, bool, S_IRUGO); module_param(use_msi, bool, S_IRUGO); /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable */ -static ushort fifo_mode = 0; +static ushort fifo_mode; /* "modprobe net2280 fifo_mode=1" etc */ module_param (fifo_mode, ushort, 0644); @@ -121,7 +121,7 @@ module_param (fifo_mode, ushort, 0644); static bool enable_suspend; /* "modprobe net2280 enable_suspend=1" etc */ -module_param (enable_suspend, bool, S_IRUGO); +module_param(enable_suspend, bool, S_IRUGO); /* force full-speed operation */ static bool full_speed; @@ -130,8 +130,7 @@ MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!"); #define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") -#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG) -static char *type_string (u8 bmAttributes) +static char *type_string(u8 bmAttributes) { switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_BULK: return "bulk"; @@ -140,7 +139,6 @@ static char *type_string (u8 bmAttributes) } return "control"; } -#endif #include "net2280.h" @@ -162,7 +160,7 @@ static inline void enable_pciirqenb(struct net2280_ep *ep) } static int -net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct net2280 *dev; struct net2280_ep *ep; @@ -170,7 +168,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) unsigned long flags; static const u32 ep_key[9] = { 1, 0, 1, 0, 1, 1, 0, 1, 0 }; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; @@ -191,12 +189,12 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } /* sanity check ep-e/ep-f since their fifos are small */ - max = usb_endpoint_maxp (desc) & 0x1fff; + max = usb_endpoint_maxp(desc) & 0x1fff; if (ep->num > 4 && max > 64 && (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY)) return -ERANGE; - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->lock, flags); _ep->maxpacket = max & 0x7ff; ep->desc = desc; @@ -212,7 +210,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) * use it instead of troublesome (non-bulk) multi-packet DMA. */ if (ep->dma && (max % 4) != 0 && use_dma_chaining) { - DEBUG (ep->dev, "%s, no dma for maxpacket %d\n", + DEBUG(ep->dev, "%s, no dma for maxpacket %d\n", ep->ep.name, ep->ep.maxpacket); ep->dma = NULL; } @@ -236,7 +234,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) return -ERANGE; } } - ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; + ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); /* Enable this endpoint */ if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) { tmp <<= ENDPOINT_TYPE; @@ -285,12 +283,12 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) tmp = BIT(DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) | BIT(DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); if (dev->pdev->device == 0x2280) - tmp |= readl (&ep->regs->ep_irqenb); - writel (tmp, &ep->regs->ep_irqenb); + tmp |= readl(&ep->regs->ep_irqenb); + writel(tmp, &ep->regs->ep_irqenb); } else { /* dma, per-request */ tmp = BIT((8 + ep->num)); /* completion */ - tmp |= readl (&dev->regs->pciirqenb1); - writel (tmp, &dev->regs->pciirqenb1); + tmp |= readl(&dev->regs->pciirqenb1); + writel(tmp, &dev->regs->pciirqenb1); /* for short OUT transfers, dma completions can't * advance the queue; do it pio-style, by hand. @@ -298,35 +296,35 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) */ if ((desc->bEndpointAddress & USB_DIR_IN) == 0) { tmp = BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE); - writel (tmp, &ep->regs->ep_irqenb); + writel(tmp, &ep->regs->ep_irqenb); enable_pciirqenb(ep); } } tmp = desc->bEndpointAddress; - DEBUG (dev, "enabled %s (ep%d%s-%s) %s max %04x\n", - _ep->name, tmp & 0x0f, DIR_STRING (tmp), - type_string (desc->bmAttributes), + DEBUG(dev, "enabled %s (ep%d%s-%s) %s max %04x\n", + _ep->name, tmp & 0x0f, DIR_STRING(tmp), + type_string(desc->bmAttributes), ep->dma ? "dma" : "pio", max); /* pci writes may still be posted */ - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->lock, flags); return 0; } -static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) +static int handshake(u32 __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; do { - result = readl (ptr); + result = readl(ptr); if (result == ~(u32)0) /* "device unplugged" */ return -ENODEV; result &= mask; if (result == done) return 0; - udelay (1); + udelay(1); usec--; } while (usec > 0); return -ETIMEDOUT; @@ -340,28 +338,28 @@ static void ep_reset_228x(struct net2280_regs __iomem *regs, u32 tmp; ep->desc = NULL; - INIT_LIST_HEAD (&ep->queue); + INIT_LIST_HEAD(&ep->queue); usb_ep_set_maxpacket_limit(&ep->ep, ~0); ep->ep.ops = &net2280_ep_ops; /* disable the dma, irqs, endpoint... */ if (ep->dma) { - writel (0, &ep->dma->dmactl); + writel(0, &ep->dma->dmactl); writel(BIT(DMA_SCATTER_GATHER_DONE_INTERRUPT) | BIT(DMA_TRANSACTION_DONE_INTERRUPT) | BIT(DMA_ABORT), &ep->dma->dmastat); - tmp = readl (®s->pciirqenb0); + tmp = readl(®s->pciirqenb0); tmp &= ~BIT(ep->num); - writel (tmp, ®s->pciirqenb0); + writel(tmp, ®s->pciirqenb0); } else { - tmp = readl (®s->pciirqenb1); + tmp = readl(®s->pciirqenb1); tmp &= ~BIT((8 + ep->num)); /* completion */ - writel (tmp, ®s->pciirqenb1); + writel(tmp, ®s->pciirqenb1); } - writel (0, &ep->regs->ep_irqenb); + writel(0, &ep->regs->ep_irqenb); /* init to our chosen defaults, notably so that we NAK OUT * packets until the driver queues a read (+note erratum 0112) @@ -383,7 +381,7 @@ static void ep_reset_228x(struct net2280_regs __iomem *regs, tmp |= BIT(CLEAR_ENDPOINT_TOGGLE) | BIT(CLEAR_ENDPOINT_HALT); } - writel (tmp, &ep->regs->ep_rsp); + writel(tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ if (ep->dev->pdev->device == 0x2280) @@ -459,64 +457,64 @@ static void ep_reset_338x(struct net2280_regs __iomem *regs, BIT(DATA_IN_TOKEN_INTERRUPT), &ep->regs->ep_stat); } -static void nuke (struct net2280_ep *); +static void nuke(struct net2280_ep *); -static int net2280_disable (struct usb_ep *_ep) +static int net2280_disable(struct usb_ep *_ep) { struct net2280_ep *ep; unsigned long flags; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || !ep->desc || _ep->name == ep0name) return -EINVAL; - spin_lock_irqsave (&ep->dev->lock, flags); - nuke (ep); + spin_lock_irqsave(&ep->dev->lock, flags); + nuke(ep); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) ep_reset_338x(ep->dev->regs, ep); else ep_reset_228x(ep->dev->regs, ep); - VDEBUG (ep->dev, "disabled %s %s\n", + VDEBUG(ep->dev, "disabled %s %s\n", ep->dma ? "dma" : "pio", _ep->name); /* synch memory views with the device */ (void)readl(&ep->cfg->ep_cfg); if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4) - ep->dma = &ep->dev->dma [ep->num - 1]; + ep->dma = &ep->dev->dma[ep->num - 1]; - spin_unlock_irqrestore (&ep->dev->lock, flags); + spin_unlock_irqrestore(&ep->dev->lock, flags); return 0; } /*-------------------------------------------------------------------------*/ -static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) +static struct usb_request +*net2280_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { struct net2280_ep *ep; struct net2280_request *req; if (!_ep) return NULL; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); req = kzalloc(sizeof(*req), gfp_flags); if (!req) return NULL; - INIT_LIST_HEAD (&req->queue); + INIT_LIST_HEAD(&req->queue); /* this dma descriptor may be swapped with the previous dummy */ if (ep->dma) { struct net2280_dma *td; - td = pci_pool_alloc (ep->dev->requests, gfp_flags, + td = pci_pool_alloc(ep->dev->requests, gfp_flags, &req->td_dma); if (!td) { - kfree (req); + kfree(req); return NULL; } td->dmacount = 0; /* not VALID */ @@ -526,21 +524,20 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) return &req->req; } -static void -net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) +static void net2280_free_request(struct usb_ep *_ep, struct usb_request *_req) { struct net2280_ep *ep; struct net2280_request *req; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || !_req) return; - req = container_of (_req, struct net2280_request, req); - WARN_ON (!list_empty (&req->queue)); + req = container_of(_req, struct net2280_request, req); + WARN_ON(!list_empty(&req->queue)); if (req->td) - pci_pool_free (ep->dev->requests, req->td, req->td_dma); - kfree (req); + pci_pool_free(ep->dev->requests, req->td, req->td_dma); + kfree(req); } /*-------------------------------------------------------------------------*/ @@ -552,8 +549,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) * at a time, but this code is simpler because it knows it only writes * one packet. ep-a..ep-d should use dma instead. */ -static void -write_fifo (struct net2280_ep *ep, struct usb_request *req) +static void write_fifo(struct net2280_ep *ep, struct usb_request *req) { struct net2280_ep_regs __iomem *regs = ep->regs; u8 *buf; @@ -564,7 +560,7 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) if (req) { buf = req->buf + req->actual; - prefetch (buf); + prefetch(buf); total = req->length - req->actual; } else { total = 0; @@ -576,7 +572,7 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) if (count > total) /* min() cannot be used on a bitfield */ count = total; - VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", + VDEBUG(ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", ep->ep.name, count, (count != ep->ep.maxpacket) ? " (short)" : "", req); @@ -585,9 +581,9 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) * should normally be full (4 bytes) and successive partial * lines are ok only in certain cases. */ - tmp = get_unaligned ((u32 *)buf); - cpu_to_le32s (&tmp); - writel (tmp, ®s->ep_data); + tmp = get_unaligned((u32 *)buf); + cpu_to_le32s(&tmp); + writel(tmp, ®s->ep_data); buf += 4; count -= 4; } @@ -597,10 +593,10 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) * when maxpacket is not a multiple of 4 bytes. */ if (count || total < ep->ep.maxpacket) { - tmp = count ? get_unaligned ((u32 *)buf) : count; - cpu_to_le32s (&tmp); - set_fifo_bytecount (ep, count & 0x03); - writel (tmp, ®s->ep_data); + tmp = count ? get_unaligned((u32 *)buf) : count; + cpu_to_le32s(&tmp); + set_fifo_bytecount(ep, count & 0x03); + writel(tmp, ®s->ep_data); } /* pci writes may still be posted */ @@ -613,20 +609,21 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req) * NOTE: also used in cases where that erratum doesn't apply: * where the host wrote "too much" data to us. */ -static void out_flush (struct net2280_ep *ep) +static void out_flush(struct net2280_ep *ep) { u32 __iomem *statp; u32 tmp; - ASSERT_OUT_NAKING (ep); + ASSERT_OUT_NAKING(ep); statp = &ep->regs->ep_stat; writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | BIT(DATA_PACKET_RECEIVED_INTERRUPT) , statp); writel(BIT(FIFO_FLUSH), statp); - mb (); - tmp = readl (statp); + /* Make sure that stap is written */ + mb(); + tmp = readl(statp); if (tmp & BIT(DATA_OUT_PING_TOKEN_INTERRUPT) /* high speed did bulk NYET; fifo isn't filling */ && ep->dev->gadget.speed == USB_SPEED_FULL) { @@ -646,8 +643,7 @@ static void out_flush (struct net2280_ep *ep) * for ep-a..ep-d this will read multiple packets out when they * have been accepted. */ -static int -read_fifo (struct net2280_ep *ep, struct net2280_request *req) +static int read_fifo(struct net2280_ep *ep, struct net2280_request *req) { struct net2280_ep_regs __iomem *regs = ep->regs; u8 *buf = req->req.buf + req->req.actual; @@ -659,12 +655,12 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) */ if (ep->dev->chiprev == 0x0100 && ep->dev->gadget.speed == USB_SPEED_FULL) { - udelay (1); - tmp = readl (&ep->regs->ep_stat); + udelay(1); + tmp = readl(&ep->regs->ep_stat); if ((tmp & BIT(NAK_OUT_PACKETS))) cleanup = 1; else if ((tmp & BIT(FIFO_FULL))) { - start_out_naking (ep); + start_out_naking(ep); prevent = 1; } /* else: hope we don't see the problem */ @@ -673,12 +669,12 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) /* never overflow the rx buffer. the fifo reads packets until * it sees a short one; we might not be ready for them all. */ - prefetchw (buf); - count = readl (®s->ep_avail); - if (unlikely (count == 0)) { - udelay (1); - tmp = readl (&ep->regs->ep_stat); - count = readl (®s->ep_avail); + prefetchw(buf); + count = readl(®s->ep_avail); + if (unlikely(count == 0)) { + udelay(1); + tmp = readl(&ep->regs->ep_stat); + count = readl(®s->ep_avail); /* handled that data already? */ if (count == 0 && (tmp & BIT(NAK_OUT_PACKETS)) == 0) return 0; @@ -688,7 +684,7 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) if (count > tmp) { /* as with DMA, data overflow gets flushed */ if ((tmp % ep->ep.maxpacket) != 0) { - ERROR (ep->dev, + ERROR(ep->dev, "%s out fifo %d bytes, expected %d\n", ep->ep.name, count, tmp); req->req.status = -EOVERFLOW; @@ -703,20 +699,20 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0); - VDEBUG (ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n", + VDEBUG(ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n", ep->ep.name, count, is_short ? " (short)" : "", cleanup ? " flush" : "", prevent ? " nak" : "", req, req->req.actual, req->req.length); while (count >= 4) { - tmp = readl (®s->ep_data); - cpu_to_le32s (&tmp); - put_unaligned (tmp, (u32 *)buf); + tmp = readl(®s->ep_data); + cpu_to_le32s(&tmp); + put_unaligned(tmp, (u32 *)buf); buf += 4; count -= 4; } if (count) { - tmp = readl (®s->ep_data); + tmp = readl(®s->ep_data); /* LE conversion is implicit here: */ do { *buf++ = (u8) tmp; @@ -724,10 +720,10 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) } while (--count); } if (cleanup) - out_flush (ep); + out_flush(ep); if (prevent) { writel(BIT(CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); - (void) readl (&ep->regs->ep_rsp); + (void) readl(&ep->regs->ep_rsp); } return is_short || ((req->req.actual == req->req.length) @@ -735,8 +731,8 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req) } /* fill out dma descriptor to match a given request */ -static void -fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) +static void fill_dma_desc(struct net2280_ep *ep, + struct net2280_request *req, int valid) { struct net2280_dma *td = req->td; u32 dmacount = req->req.length; @@ -762,7 +758,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) td->dmaaddr = cpu_to_le32 (req->req.dma); /* 2280 may be polling VALID_BIT through ep->dma->dmadesc */ - wmb (); + wmb(); td->dmacount = cpu_to_le32(dmacount); } @@ -777,18 +773,18 @@ static const u32 dmactl_default = /* erratum 0116 workaround part 2 (no AUTOSTART) */ BIT(DMA_ENABLE); -static inline void spin_stop_dma (struct net2280_dma_regs __iomem *dma) +static inline void spin_stop_dma(struct net2280_dma_regs __iomem *dma) { handshake(&dma->dmactl, BIT(DMA_ENABLE), 0, 50); } -static inline void stop_dma (struct net2280_dma_regs __iomem *dma) +static inline void stop_dma(struct net2280_dma_regs __iomem *dma) { writel(readl(&dma->dmactl) & ~BIT(DMA_ENABLE), &dma->dmactl); - spin_stop_dma (dma); + spin_stop_dma(dma); } -static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) +static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma) { struct net2280_dma_regs __iomem *dma = ep->dma; unsigned int tmp = BIT(VALID_BIT) | (ep->is_in << DMA_DIRECTION); @@ -796,24 +792,24 @@ static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) if (ep->dev->pdev->device != 0x2280) tmp |= BIT(END_OF_CHAIN); - writel (tmp, &dma->dmacount); - writel (readl (&dma->dmastat), &dma->dmastat); + writel(tmp, &dma->dmacount); + writel(readl(&dma->dmastat), &dma->dmastat); - writel (td_dma, &dma->dmadesc); + writel(td_dma, &dma->dmadesc); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) dmactl |= BIT(DMA_REQUEST_OUTSTANDING); - writel (dmactl, &dma->dmactl); + writel(dmactl, &dma->dmactl); /* erratum 0116 workaround part 3: pci arbiter away from net2280 */ - (void) readl (&ep->dev->pci->pcimstctl); + (void) readl(&ep->dev->pci->pcimstctl); writel(BIT(DMA_START), &dma->dmastat); if (!ep->is_in) - stop_out_naking (ep); + stop_out_naking(ep); } -static void start_dma (struct net2280_ep *ep, struct net2280_request *req) +static void start_dma(struct net2280_ep *ep, struct net2280_request *req) { u32 tmp; struct net2280_dma_regs __iomem *dma = ep->dma; @@ -822,24 +818,24 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) /* on this path we "know" there's no dma active (yet) */ WARN_ON(readl(&dma->dmactl) & BIT(DMA_ENABLE)); - writel (0, &ep->dma->dmactl); + writel(0, &ep->dma->dmactl); /* previous OUT packet might have been short */ - if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat)) - & BIT(NAK_OUT_PACKETS)) != 0) { + if (!ep->is_in && (readl(&ep->regs->ep_stat) & + BIT(NAK_OUT_PACKETS))) { writel(BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT), &ep->regs->ep_stat); - tmp = readl (&ep->regs->ep_avail); + tmp = readl(&ep->regs->ep_avail); if (tmp) { - writel (readl (&dma->dmastat), &dma->dmastat); + writel(readl(&dma->dmastat), &dma->dmastat); /* transfer all/some fifo data */ - writel (req->req.dma, &dma->dmaaddr); - tmp = min (tmp, req->req.length); + writel(req->req.dma, &dma->dmaaddr); + tmp = min(tmp, req->req.length); /* dma irq, faking scatterlist status */ - req->td->dmacount = cpu_to_le32 (req->req.length - tmp); + req->td->dmacount = cpu_to_le32(req->req.length - tmp); writel(BIT(DMA_DONE_INTERRUPT_ENABLE) | tmp, &dma->dmacount); req->td->dmadesc = 0; @@ -858,8 +854,8 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) * (zero length) unless the driver explicitly said to do that. */ if (ep->is_in) { - if (likely ((req->req.length % ep->ep.maxpacket) != 0 - || req->req.zero)) { + if (likely((req->req.length % ep->ep.maxpacket) || + req->req.zero)){ tmp |= BIT(DMA_FIFO_VALIDATE); ep->in_fifo_validate = 1; } else @@ -868,12 +864,12 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) /* init req->td, pointing to the current dummy */ req->td->dmadesc = cpu_to_le32 (ep->td_dma); - fill_dma_desc (ep, req, 1); + fill_dma_desc(ep, req, 1); if (!use_dma_chaining) req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN)); - start_queue (ep, tmp, req->td_dma); + start_queue(ep, tmp, req->td_dma); } static inline void resume_dma(struct net2280_ep *ep) @@ -892,7 +888,7 @@ static inline void ep_stop_dma(struct net2280_ep *ep) } static inline void -queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid) +queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid) { struct net2280_dma *end; dma_addr_t tmp; @@ -908,16 +904,16 @@ queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid) end->dmadesc = cpu_to_le32 (ep->td_dma); - fill_dma_desc (ep, req, valid); + fill_dma_desc(ep, req, valid); } static void -done (struct net2280_ep *ep, struct net2280_request *req, int status) +done(struct net2280_ep *ep, struct net2280_request *req, int status) { struct net2280 *dev; unsigned stopped = ep->stopped; - list_del_init (&req->queue); + list_del_init(&req->queue); if (req->req.status == -EINPROGRESS) req->req.status = status; @@ -929,22 +925,22 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status) usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in); if (status && status != -ESHUTDOWN) - VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n", + VDEBUG(dev, "complete %s req %p stat %d len %u/%u\n", ep->ep.name, &req->req, status, req->req.actual, req->req.length); /* don't modify queue heads during completion callback */ ep->stopped = 1; - spin_unlock (&dev->lock); - req->req.complete (&ep->ep, &req->req); - spin_lock (&dev->lock); + spin_unlock(&dev->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&dev->lock); ep->stopped = stopped; } /*-------------------------------------------------------------------------*/ static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct net2280_request *req; struct net2280_ep *ep; @@ -954,13 +950,13 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* we always require a cpu-view buffer, so that we can * always use pio (as fallback or whatever). */ - req = container_of (_req, struct net2280_request, req); - if (!_req || !_req->complete || !_req->buf - || !list_empty (&req->queue)) + req = container_of(_req, struct net2280_request, req); + if (!_req || !_req->complete || !_req->buf || + !list_empty(&req->queue)) return -EINVAL; if (_req->length > (~0 & DMA_BYTE_COUNT_MASK)) return -EDOM; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || (!ep->desc && ep->num != 0)) return -EINVAL; dev = ep->dev; @@ -982,17 +978,17 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } #if 0 - VDEBUG (dev, "%s queue req %p, len %d buf %p\n", + VDEBUG(dev, "%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, _req->buf); #endif - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->lock, flags); _req->status = -EINPROGRESS; _req->actual = 0; /* kickstart this i/o queue? */ - if (list_empty (&ep->queue) && !ep->stopped) { + if (list_empty(&ep->queue) && !ep->stopped) { /* DMA request while EP halted */ if (ep->dma && (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) && @@ -1010,24 +1006,24 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } /* use DMA if the endpoint supports it, else pio */ else if (ep->dma) - start_dma (ep, req); + start_dma(ep, req); else { /* maybe there's no control data, just status ack */ if (ep->num == 0 && _req->length == 0) { - allow_status (ep); - done (ep, req, 0); - VDEBUG (dev, "%s status ack\n", ep->ep.name); + allow_status(ep); + done(ep, req, 0); + VDEBUG(dev, "%s status ack\n", ep->ep.name); goto done; } /* PIO ... stuff the fifo, or unblock it. */ if (ep->is_in) - write_fifo (ep, _req); - else if (list_empty (&ep->queue)) { + write_fifo(ep, _req); + else if (list_empty(&ep->queue)) { u32 s; /* OUT FIFO might have packet(s) buffered */ - s = readl (&ep->regs->ep_stat); + s = readl(&ep->regs->ep_stat); if ((s & BIT(FIFO_EMPTY)) == 0) { /* note: _req->short_not_ok is * ignored here since PIO _always_ @@ -1035,14 +1031,18 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) * _req->status doesn't change for * short reads (only _req->actual) */ - if (read_fifo (ep, req)) { - done (ep, req, 0); - if (ep->num == 0) - allow_status (ep); + if (read_fifo(ep, req) && + ep->num == 0) { + done(ep, req, 0); + allow_status(ep); /* don't queue it */ req = NULL; + } else if (read_fifo(ep, req) && + ep->num != 0) { + done(ep, req, 0); + req = NULL; } else - s = readl (&ep->regs->ep_stat); + s = readl(&ep->regs->ep_stat); } /* don't NAK, let the fifo fill */ @@ -1061,54 +1061,50 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* preventing magic zlps is per-engine state, not * per-transfer; irq logic must recover hiccups. */ - expect = likely (req->req.zero - || (req->req.length % ep->ep.maxpacket) != 0); + expect = likely(req->req.zero || + (req->req.length % ep->ep.maxpacket)); if (expect != ep->in_fifo_validate) valid = 0; } - queue_dma (ep, req, valid); + queue_dma(ep, req, valid); } /* else the irq handler advances the queue. */ ep->responded = 1; if (req) - list_add_tail (&req->queue, &ep->queue); + list_add_tail(&req->queue, &ep->queue); done: - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->lock, flags); /* pci writes may still be posted */ return 0; } static inline void -dma_done ( - struct net2280_ep *ep, - struct net2280_request *req, - u32 dmacount, - int status -) +dma_done(struct net2280_ep *ep, struct net2280_request *req, u32 dmacount, + int status) { req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount); - done (ep, req, status); + done(ep, req, status); } -static void restart_dma (struct net2280_ep *ep); +static void restart_dma(struct net2280_ep *ep); -static void scan_dma_completions (struct net2280_ep *ep) +static void scan_dma_completions(struct net2280_ep *ep) { /* only look at descriptors that were "naturally" retired, * so fifo and list head state won't matter */ - while (!list_empty (&ep->queue)) { + while (!list_empty(&ep->queue)) { struct net2280_request *req; u32 tmp; - req = list_entry (ep->queue.next, + req = list_entry(ep->queue.next, struct net2280_request, queue); if (!req->valid) break; - rmb (); - tmp = le32_to_cpup (&req->td->dmacount); + rmb(); + tmp = le32_to_cpup(&req->td->dmacount); if ((tmp & BIT(VALID_BIT)) != 0) break; @@ -1116,17 +1112,17 @@ static void scan_dma_completions (struct net2280_ep *ep) * cases where DMA must be aborted; this code handles * all non-abort DMA completions. */ - if (unlikely (req->td->dmadesc == 0)) { + if (unlikely(req->td->dmadesc == 0)) { /* paranoia */ - tmp = readl (&ep->dma->dmacount); + tmp = readl(&ep->dma->dmacount); if (tmp & DMA_BYTE_COUNT_MASK) break; /* single transfer mode */ - dma_done (ep, req, tmp, 0); + dma_done(ep, req, tmp, 0); break; } else if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { - tmp = readl (&ep->regs->ep_stat); + tmp = readl(&ep->regs->ep_stat); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) return dma_done(ep, req, tmp, 0); @@ -1135,33 +1131,37 @@ static void scan_dma_completions (struct net2280_ep *ep) * 0122, and 0124; not all cases trigger the warning. */ if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) { - WARNING (ep->dev, "%s lost packet sync!\n", + WARNING(ep->dev, "%s lost packet sync!\n", ep->ep.name); req->req.status = -EOVERFLOW; - } else if ((tmp = readl (&ep->regs->ep_avail)) != 0) { - /* fifo gets flushed later */ - ep->out_overflow = 1; - DEBUG (ep->dev, "%s dma, discard %d len %d\n", + } else { + tmp = readl(&ep->regs->ep_avail); + if (tmp) { + /* fifo gets flushed later */ + ep->out_overflow = 1; + DEBUG(ep->dev, + "%s dma, discard %d len %d\n", ep->ep.name, tmp, req->req.length); - req->req.status = -EOVERFLOW; + req->req.status = -EOVERFLOW; + } } } - dma_done (ep, req, tmp, 0); + dma_done(ep, req, tmp, 0); } } -static void restart_dma (struct net2280_ep *ep) +static void restart_dma(struct net2280_ep *ep) { struct net2280_request *req; u32 dmactl = dmactl_default; if (ep->stopped) return; - req = list_entry (ep->queue.next, struct net2280_request, queue); + req = list_entry(ep->queue.next, struct net2280_request, queue); if (!use_dma_chaining) { - start_dma (ep, req); + start_dma(ep, req); return; } @@ -1175,21 +1175,20 @@ static void restart_dma (struct net2280_ep *ep) struct net2280_request *entry, *prev = NULL; int reqmode, done = 0; - DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); - ep->in_fifo_validate = likely (req->req.zero - || (req->req.length % ep->ep.maxpacket) != 0); + DEBUG(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); + ep->in_fifo_validate = likely(req->req.zero || + (req->req.length % ep->ep.maxpacket) != 0); if (ep->in_fifo_validate) dmactl |= BIT(DMA_FIFO_VALIDATE); - list_for_each_entry (entry, &ep->queue, queue) { + list_for_each_entry(entry, &ep->queue, queue) { __le32 dmacount; if (entry == req) continue; dmacount = entry->td->dmacount; if (!done) { - reqmode = likely (entry->req.zero - || (entry->req.length - % ep->ep.maxpacket) != 0); + reqmode = likely(entry->req.zero || + (entry->req.length % ep->ep.maxpacket)); if (reqmode == ep->in_fifo_validate) { entry->valid = 1; dmacount |= valid_bit; @@ -1211,20 +1210,20 @@ static void restart_dma (struct net2280_ep *ep) } } - writel (0, &ep->dma->dmactl); - start_queue (ep, dmactl, req->td_dma); + writel(0, &ep->dma->dmactl); + start_queue(ep, dmactl, req->td_dma); } static void abort_dma_228x(struct net2280_ep *ep) { /* abort the current transfer */ - if (likely (!list_empty (&ep->queue))) { + if (likely(!list_empty(&ep->queue))) { /* FIXME work around errata 0121, 0122, 0124 */ writel(BIT(DMA_ABORT), &ep->dma->dmastat); - spin_stop_dma (ep->dma); + spin_stop_dma(ep->dma); } else - stop_dma (ep->dma); - scan_dma_completions (ep); + stop_dma(ep->dma); + scan_dma_completions(ep); } static void abort_dma_338x(struct net2280_ep *ep) @@ -1241,24 +1240,24 @@ static void abort_dma(struct net2280_ep *ep) } /* dequeue ALL requests */ -static void nuke (struct net2280_ep *ep) +static void nuke(struct net2280_ep *ep) { struct net2280_request *req; /* called with spinlock held */ ep->stopped = 1; if (ep->dma) - abort_dma (ep); - while (!list_empty (&ep->queue)) { - req = list_entry (ep->queue.next, + abort_dma(ep); + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct net2280_request, queue); - done (ep, req, -ESHUTDOWN); + done(ep, req, -ESHUTDOWN); } } /* dequeue JUST ONE request */ -static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) +static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) { struct net2280_ep *ep; struct net2280_request *req; @@ -1266,65 +1265,65 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) u32 dmactl; int stopped; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || (!ep->desc && ep->num != 0) || !_req) return -EINVAL; - spin_lock_irqsave (&ep->dev->lock, flags); + spin_lock_irqsave(&ep->dev->lock, flags); stopped = ep->stopped; /* quiesce dma while we patch the queue */ dmactl = 0; ep->stopped = 1; if (ep->dma) { - dmactl = readl (&ep->dma->dmactl); + dmactl = readl(&ep->dma->dmactl); /* WARNING erratum 0127 may kick in ... */ - stop_dma (ep->dma); - scan_dma_completions (ep); + stop_dma(ep->dma); + scan_dma_completions(ep); } /* make sure it's still queued on this endpoint */ - list_for_each_entry (req, &ep->queue, queue) { + list_for_each_entry(req, &ep->queue, queue) { if (&req->req == _req) break; } if (&req->req != _req) { - spin_unlock_irqrestore (&ep->dev->lock, flags); + spin_unlock_irqrestore(&ep->dev->lock, flags); return -EINVAL; } /* queue head may be partially complete. */ if (ep->queue.next == &req->queue) { if (ep->dma) { - DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name); + DEBUG(ep->dev, "unlink (%s) dma\n", _ep->name); _req->status = -ECONNRESET; - abort_dma (ep); - if (likely (ep->queue.next == &req->queue)) { - // NOTE: misreports single-transfer mode + abort_dma(ep); + if (likely(ep->queue.next == &req->queue)) { + /* NOTE: misreports single-transfer mode*/ req->td->dmacount = 0; /* invalidate */ - dma_done (ep, req, - readl (&ep->dma->dmacount), + dma_done(ep, req, + readl(&ep->dma->dmacount), -ECONNRESET); } } else { - DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name); - done (ep, req, -ECONNRESET); + DEBUG(ep->dev, "unlink (%s) pio\n", _ep->name); + done(ep, req, -ECONNRESET); } req = NULL; /* patch up hardware chaining data */ } else if (ep->dma && use_dma_chaining) { if (req->queue.prev == ep->queue.next) { - writel (le32_to_cpu (req->td->dmadesc), + writel(le32_to_cpu(req->td->dmadesc), &ep->dma->dmadesc); if (req->td->dmacount & dma_done_ie) - writel (readl (&ep->dma->dmacount) + writel(readl(&ep->dma->dmacount) | le32_to_cpu(dma_done_ie), &ep->dma->dmacount); } else { struct net2280_request *prev; - prev = list_entry (req->queue.prev, + prev = list_entry(req->queue.prev, struct net2280_request, queue); prev->td->dmadesc = req->td->dmadesc; if (req->td->dmacount & dma_done_ie) @@ -1333,30 +1332,30 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) } if (req) - done (ep, req, -ECONNRESET); + done(ep, req, -ECONNRESET); ep->stopped = stopped; if (ep->dma) { /* turn off dma on inactive queues */ - if (list_empty (&ep->queue)) - stop_dma (ep->dma); + if (list_empty(&ep->queue)) + stop_dma(ep->dma); else if (!ep->stopped) { /* resume current request, or start new one */ if (req) - writel (dmactl, &ep->dma->dmactl); + writel(dmactl, &ep->dma->dmactl); else - start_dma (ep, list_entry (ep->queue.next, + start_dma(ep, list_entry(ep->queue.next, struct net2280_request, queue)); } } - spin_unlock_irqrestore (&ep->dev->lock, flags); + spin_unlock_irqrestore(&ep->dev->lock, flags); return 0; } /*-------------------------------------------------------------------------*/ -static int net2280_fifo_status (struct usb_ep *_ep); +static int net2280_fifo_status(struct usb_ep *_ep); static int net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) @@ -1365,7 +1364,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) unsigned long flags; int retval = 0; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || (!ep->desc && ep->num != 0)) return -EINVAL; if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) @@ -1374,13 +1373,13 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) == USB_ENDPOINT_XFER_ISOC) return -EINVAL; - spin_lock_irqsave (&ep->dev->lock, flags); - if (!list_empty (&ep->queue)) + spin_lock_irqsave(&ep->dev->lock, flags); + if (!list_empty(&ep->queue)) retval = -EAGAIN; - else if (ep->is_in && value && net2280_fifo_status (_ep) != 0) + else if (ep->is_in && value && net2280_fifo_status(_ep) != 0) retval = -EAGAIN; else { - VDEBUG (ep->dev, "%s %s %s\n", _ep->name, + VDEBUG(ep->dev, "%s %s %s\n", _ep->name, value ? "set" : "clear", wedged ? "wedge" : "halt"); /* set/clear, then synch memory views with the device */ @@ -1388,44 +1387,41 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) if (ep->num == 0) ep->dev->protocol_stall = 1; else - set_halt (ep); + set_halt(ep); if (wedged) ep->wedged = 1; } else { - clear_halt (ep); + clear_halt(ep); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX && !list_empty(&ep->queue) && ep->td_dma) restart_dma(ep); ep->wedged = 0; } - (void) readl (&ep->regs->ep_rsp); + (void) readl(&ep->regs->ep_rsp); } - spin_unlock_irqrestore (&ep->dev->lock, flags); + spin_unlock_irqrestore(&ep->dev->lock, flags); return retval; } -static int -net2280_set_halt(struct usb_ep *_ep, int value) +static int net2280_set_halt(struct usb_ep *_ep, int value) { return net2280_set_halt_and_wedge(_ep, value, 0); } -static int -net2280_set_wedge(struct usb_ep *_ep) +static int net2280_set_wedge(struct usb_ep *_ep) { if (!_ep || _ep->name == ep0name) return -EINVAL; return net2280_set_halt_and_wedge(_ep, 1, 1); } -static int -net2280_fifo_status (struct usb_ep *_ep) +static int net2280_fifo_status(struct usb_ep *_ep) { struct net2280_ep *ep; u32 avail; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || (!ep->desc && ep->num != 0)) return -ENODEV; if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) @@ -1439,19 +1435,18 @@ net2280_fifo_status (struct usb_ep *_ep) return avail; } -static void -net2280_fifo_flush (struct usb_ep *_ep) +static void net2280_fifo_flush(struct usb_ep *_ep) { struct net2280_ep *ep; - ep = container_of (_ep, struct net2280_ep, ep); + ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || (!ep->desc && ep->num != 0)) return; if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) return; writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat); - (void) readl (&ep->regs->ep_rsp); + (void) readl(&ep->regs->ep_rsp); } static const struct usb_ep_ops net2280_ep_ops = { @@ -1472,7 +1467,7 @@ static const struct usb_ep_ops net2280_ep_ops = { /*-------------------------------------------------------------------------*/ -static int net2280_get_frame (struct usb_gadget *_gadget) +static int net2280_get_frame(struct usb_gadget *_gadget) { struct net2280 *dev; unsigned long flags; @@ -1480,14 +1475,14 @@ static int net2280_get_frame (struct usb_gadget *_gadget) if (!_gadget) return -ENODEV; - dev = container_of (_gadget, struct net2280, gadget); - spin_lock_irqsave (&dev->lock, flags); - retval = get_idx_reg (dev->regs, REG_FRAME) & 0x03ff; - spin_unlock_irqrestore (&dev->lock, flags); + dev = container_of(_gadget, struct net2280, gadget); + spin_lock_irqsave(&dev->lock, flags); + retval = get_idx_reg(dev->regs, REG_FRAME) & 0x03ff; + spin_unlock_irqrestore(&dev->lock, flags); return retval; } -static int net2280_wakeup (struct usb_gadget *_gadget) +static int net2280_wakeup(struct usb_gadget *_gadget) { struct net2280 *dev; u32 tmp; @@ -1495,19 +1490,19 @@ static int net2280_wakeup (struct usb_gadget *_gadget) if (!_gadget) return 0; - dev = container_of (_gadget, struct net2280, gadget); + dev = container_of(_gadget, struct net2280, gadget); - spin_lock_irqsave (&dev->lock, flags); - tmp = readl (&dev->usb->usbctl); + spin_lock_irqsave(&dev->lock, flags); + tmp = readl(&dev->usb->usbctl); if (tmp & BIT(DEVICE_REMOTE_WAKEUP_ENABLE)) writel(BIT(GENERATE_RESUME), &dev->usb->usbstat); - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->lock, flags); /* pci writes may still be posted */ return 0; } -static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) +static int net2280_set_selfpowered(struct usb_gadget *_gadget, int value) { struct net2280 *dev; u32 tmp; @@ -1515,10 +1510,10 @@ static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) if (!_gadget) return 0; - dev = container_of (_gadget, struct net2280, gadget); + dev = container_of(_gadget, struct net2280, gadget); - spin_lock_irqsave (&dev->lock, flags); - tmp = readl (&dev->usb->usbctl); + spin_lock_irqsave(&dev->lock, flags); + tmp = readl(&dev->usb->usbctl); if (value) { tmp |= BIT(SELF_POWERED_STATUS); dev->selfpowered = 1; @@ -1526,8 +1521,8 @@ static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) tmp &= ~BIT(SELF_POWERED_STATUS); dev->selfpowered = 0; } - writel (tmp, &dev->usb->usbctl); - spin_unlock_irqrestore (&dev->lock, flags); + writel(tmp, &dev->usb->usbctl); + spin_unlock_irqrestore(&dev->lock, flags); return 0; } @@ -1540,17 +1535,17 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) if (!_gadget) return -ENODEV; - dev = container_of (_gadget, struct net2280, gadget); + dev = container_of(_gadget, struct net2280, gadget); - spin_lock_irqsave (&dev->lock, flags); - tmp = readl (&dev->usb->usbctl); + spin_lock_irqsave(&dev->lock, flags); + tmp = readl(&dev->usb->usbctl); dev->softconnect = (is_on != 0); if (is_on) tmp |= BIT(USB_DETECT_ENABLE); else tmp &= ~BIT(USB_DETECT_ENABLE); - writel (tmp, &dev->usb->usbctl); - spin_unlock_irqrestore (&dev->lock, flags); + writel(tmp, &dev->usb->usbctl); + spin_unlock_irqrestore(&dev->lock, flags); return 0; } @@ -1582,13 +1577,12 @@ static const struct usb_gadget_ops net2280_ops = { static ssize_t function_show(struct device *_dev, struct device_attribute *attr, char *buf) { - struct net2280 *dev = dev_get_drvdata (_dev); + struct net2280 *dev = dev_get_drvdata(_dev); - if (!dev->driver - || !dev->driver->function - || strlen (dev->driver->function) > PAGE_SIZE) + if (!dev->driver || !dev->driver->function || + strlen(dev->driver->function) > PAGE_SIZE) return 0; - return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function); + return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); } static DEVICE_ATTR_RO(function); @@ -1603,10 +1597,10 @@ static ssize_t registers_show(struct device *_dev, u32 t1, t2; const char *s; - dev = dev_get_drvdata (_dev); + dev = dev_get_drvdata(_dev); next = buf; size = PAGE_SIZE; - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->lock, flags); if (dev->driver) s = dev->driver->driver.name; @@ -1614,7 +1608,7 @@ static ssize_t registers_show(struct device *_dev, s = "(none)"; /* Main Control Registers */ - t = scnprintf (next, size, "%s version " DRIVER_VERSION + t = scnprintf(next, size, "%s version " DRIVER_VERSION ", chiprev %04x, dma %s\n\n" "devinit %03x fifoctl %08x gadget '%s'\n" "pci irqenb0 %02x irqenb1 %08x " @@ -1623,19 +1617,19 @@ static ssize_t registers_show(struct device *_dev, use_dma ? (use_dma_chaining ? "chaining" : "enabled") : "disabled", - readl (&dev->regs->devinit), - readl (&dev->regs->fifoctl), + readl(&dev->regs->devinit), + readl(&dev->regs->fifoctl), s, - readl (&dev->regs->pciirqenb0), - readl (&dev->regs->pciirqenb1), - readl (&dev->regs->irqstat0), - readl (&dev->regs->irqstat1)); + readl(&dev->regs->pciirqenb0), + readl(&dev->regs->pciirqenb1), + readl(&dev->regs->irqstat0), + readl(&dev->regs->irqstat1)); size -= t; next += t; /* USB Control Registers */ - t1 = readl (&dev->usb->usbctl); - t2 = readl (&dev->usb->usbstat); + t1 = readl(&dev->usb->usbctl); + t2 = readl(&dev->usb->usbstat); if (t1 & BIT(VBUS_PIN)) { if (t2 & BIT(HIGH_SPEED)) s = "high speed"; @@ -1646,11 +1640,11 @@ static ssize_t registers_show(struct device *_dev, /* full speed bit (6) not working?? */ } else s = "not attached"; - t = scnprintf (next, size, + t = scnprintf(next, size, "stdrsp %08x usbctl %08x usbstat %08x " "addr 0x%02x (%s)\n", - readl (&dev->usb->stdrsp), t1, t2, - readl (&dev->usb->ouraddr), s); + readl(&dev->usb->stdrsp), t1, t2, + readl(&dev->usb->ouraddr), s); size -= t; next += t; @@ -1662,13 +1656,13 @@ static ssize_t registers_show(struct device *_dev, for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep; - ep = &dev->ep [i]; + ep = &dev->ep[i]; if (i && !ep->desc) continue; t1 = readl(&ep->cfg->ep_cfg); - t2 = readl (&ep->regs->ep_rsp) & 0xff; - t = scnprintf (next, size, + t2 = readl(&ep->regs->ep_rsp) & 0xff; + t = scnprintf(next, size, "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" "irqenb %02x\n", ep->ep.name, t1, t2, @@ -1688,17 +1682,17 @@ static ssize_t registers_show(struct device *_dev, ? "DATA1 " : "DATA0 ", (t2 & BIT(CLEAR_ENDPOINT_HALT)) ? "HALT " : "", - readl (&ep->regs->ep_irqenb)); + readl(&ep->regs->ep_irqenb)); size -= t; next += t; - t = scnprintf (next, size, + t = scnprintf(next, size, "\tstat %08x avail %04x " "(ep%d%s-%s)%s\n", - readl (&ep->regs->ep_stat), - readl (&ep->regs->ep_avail), - t1 & 0x0f, DIR_STRING (t1), - type_string (t1 >> 8), + readl(&ep->regs->ep_stat), + readl(&ep->regs->ep_avail), + t1 & 0x0f, DIR_STRING(t1), + type_string(t1 >> 8), ep->stopped ? "*" : ""); size -= t; next += t; @@ -1706,42 +1700,41 @@ static ssize_t registers_show(struct device *_dev, if (!ep->dma) continue; - t = scnprintf (next, size, + t = scnprintf(next, size, " dma\tctl %08x stat %08x count %08x\n" "\taddr %08x desc %08x\n", - readl (&ep->dma->dmactl), - readl (&ep->dma->dmastat), - readl (&ep->dma->dmacount), - readl (&ep->dma->dmaaddr), - readl (&ep->dma->dmadesc)); + readl(&ep->dma->dmactl), + readl(&ep->dma->dmastat), + readl(&ep->dma->dmacount), + readl(&ep->dma->dmaaddr), + readl(&ep->dma->dmadesc)); size -= t; next += t; } - /* Indexed Registers */ - // none yet + /* Indexed Registers (none yet) */ /* Statistics */ - t = scnprintf (next, size, "\nirqs: "); + t = scnprintf(next, size, "\nirqs: "); size -= t; next += t; for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep; - ep = &dev->ep [i]; + ep = &dev->ep[i]; if (i && !ep->irqs) continue; - t = scnprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs); + t = scnprintf(next, size, " %s/%lu", ep->ep.name, ep->irqs); size -= t; next += t; } - t = scnprintf (next, size, "\n"); + t = scnprintf(next, size, "\n"); size -= t; next += t; - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->lock, flags); return PAGE_SIZE - size; } @@ -1756,13 +1749,13 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr, unsigned long flags; int i; - dev = dev_get_drvdata (_dev); + dev = dev_get_drvdata(_dev); next = buf; size = PAGE_SIZE; - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->lock, flags); for (i = 0; i < dev->n_ep; i++) { - struct net2280_ep *ep = &dev->ep [i]; + struct net2280_ep *ep = &dev->ep[i]; struct net2280_request *req; int t; @@ -1773,40 +1766,40 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr, if (!d) continue; t = d->bEndpointAddress; - t = scnprintf (next, size, + t = scnprintf(next, size, "\n%s (ep%d%s-%s) max %04x %s fifo %d\n", ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK, (t & USB_DIR_IN) ? "in" : "out", type_string(d->bmAttributes), - usb_endpoint_maxp (d) & 0x1fff, + usb_endpoint_maxp(d) & 0x1fff, ep->dma ? "dma" : "pio", ep->fifo_size ); } else /* ep0 should only have one transfer queued */ - t = scnprintf (next, size, "ep0 max 64 pio %s\n", + t = scnprintf(next, size, "ep0 max 64 pio %s\n", ep->is_in ? "in" : "out"); if (t <= 0 || t > size) goto done; size -= t; next += t; - if (list_empty (&ep->queue)) { - t = scnprintf (next, size, "\t(nothing queued)\n"); + if (list_empty(&ep->queue)) { + t = scnprintf(next, size, "\t(nothing queued)\n"); if (t <= 0 || t > size) goto done; size -= t; next += t; continue; } - list_for_each_entry (req, &ep->queue, queue) { - if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc)) - t = scnprintf (next, size, + list_for_each_entry(req, &ep->queue, queue) { + if (ep->dma && req->td_dma == readl(&ep->dma->dmadesc)) + t = scnprintf(next, size, "\treq %p len %d/%d " "buf %p (dmacount %08x)\n", &req->req, req->req.actual, req->req.length, req->req.buf, - readl (&ep->dma->dmacount)); + readl(&ep->dma->dmacount)); else - t = scnprintf (next, size, + t = scnprintf(next, size, "\treq %p len %d/%d buf %p\n", &req->req, req->req.actual, req->req.length, req->req.buf); @@ -1819,12 +1812,12 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr, struct net2280_dma *td; td = req->td; - t = scnprintf (next, size, "\t td %08x " + t = scnprintf(next, size, "\t td %08x " " count %08x buf %08x desc %08x\n", (u32) req->td_dma, - le32_to_cpu (td->dmacount), - le32_to_cpu (td->dmaaddr), - le32_to_cpu (td->dmadesc)); + le32_to_cpu(td->dmacount), + le32_to_cpu(td->dmaaddr), + le32_to_cpu(td->dmadesc)); if (t <= 0 || t > size) goto done; size -= t; @@ -1834,7 +1827,7 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr, } done: - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->lock, flags); return PAGE_SIZE - size; } static DEVICE_ATTR_RO(queues); @@ -1842,8 +1835,8 @@ static DEVICE_ATTR_RO(queues); #else -#define device_create_file(a,b) (0) -#define device_remove_file(a,b) do { } while (0) +#define device_create_file(a, b) (0) +#define device_remove_file(a, b) do { } while (0) #endif @@ -1853,33 +1846,33 @@ static DEVICE_ATTR_RO(queues); * to/from another device fifo instead of to/from memory. */ -static void set_fifo_mode (struct net2280 *dev, int mode) +static void set_fifo_mode(struct net2280 *dev, int mode) { /* keeping high bits preserves BAR2 */ - writel ((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl); + writel((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl); /* always ep-{a,b,e,f} ... maybe not ep-c or ep-d */ - INIT_LIST_HEAD (&dev->gadget.ep_list); - list_add_tail (&dev->ep [1].ep.ep_list, &dev->gadget.ep_list); - list_add_tail (&dev->ep [2].ep.ep_list, &dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep_list); + list_add_tail(&dev->ep[1].ep.ep_list, &dev->gadget.ep_list); + list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); switch (mode) { case 0: - list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); - list_add_tail (&dev->ep [4].ep.ep_list, &dev->gadget.ep_list); - dev->ep [1].fifo_size = dev->ep [2].fifo_size = 1024; + list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list); + list_add_tail(&dev->ep[4].ep.ep_list, &dev->gadget.ep_list); + dev->ep[1].fifo_size = dev->ep[2].fifo_size = 1024; break; case 1: - dev->ep [1].fifo_size = dev->ep [2].fifo_size = 2048; + dev->ep[1].fifo_size = dev->ep[2].fifo_size = 2048; break; case 2: - list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); - dev->ep [1].fifo_size = 2048; - dev->ep [2].fifo_size = 1024; + list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list); + dev->ep[1].fifo_size = 2048; + dev->ep[2].fifo_size = 1024; break; } /* fifo sizes for ep0, ep-c, ep-d, ep-e, and ep-f never change */ - list_add_tail (&dev->ep [5].ep.ep_list, &dev->gadget.ep_list); - list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); + list_add_tail(&dev->ep[5].ep.ep_list, &dev->gadget.ep_list); + list_add_tail(&dev->ep[6].ep.ep_list, &dev->gadget.ep_list); } static void defect7374_disable_data_eps(struct net2280 *dev) @@ -2011,14 +2004,14 @@ static void usb_reset_228x(struct net2280 *dev) u32 tmp; dev->gadget.speed = USB_SPEED_UNKNOWN; - (void) readl (&dev->usb->usbctl); + (void) readl(&dev->usb->usbctl); - net2280_led_init (dev); + net2280_led_init(dev); /* disable automatic responses, and irqs */ - writel (0, &dev->usb->stdrsp); - writel (0, &dev->regs->pciirqenb0); - writel (0, &dev->regs->pciirqenb1); + writel(0, &dev->usb->stdrsp); + writel(0, &dev->regs->pciirqenb0); + writel(0, &dev->regs->pciirqenb1); /* clear old dma and irq state */ for (tmp = 0; tmp < 4; tmp++) { @@ -2027,7 +2020,7 @@ static void usb_reset_228x(struct net2280 *dev) abort_dma(ep); } - writel (~0, &dev->regs->irqstat0), + writel(~0, &dev->regs->irqstat0), writel(~(u32)BIT(SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), /* reset, and enable pci */ @@ -2036,10 +2029,10 @@ static void usb_reset_228x(struct net2280 *dev) BIT(FIFO_SOFT_RESET) | BIT(USB_SOFT_RESET) | BIT(M8051_RESET); - writel (tmp, &dev->regs->devinit); + writel(tmp, &dev->regs->devinit); /* standard fifo and endpoint allocations */ - set_fifo_mode (dev, (fifo_mode <= 2) ? fifo_mode : 0); + set_fifo_mode(dev, (fifo_mode <= 2) ? fifo_mode : 0); } static void usb_reset_338x(struct net2280 *dev) @@ -2112,35 +2105,35 @@ static void usb_reinit_228x(struct net2280 *dev) /* basic endpoint init */ for (tmp = 0; tmp < 7; tmp++) { - struct net2280_ep *ep = &dev->ep [tmp]; + struct net2280_ep *ep = &dev->ep[tmp]; - ep->ep.name = ep_name [tmp]; + ep->ep.name = ep_name[tmp]; ep->dev = dev; ep->num = tmp; if (tmp > 0 && tmp <= 4) { ep->fifo_size = 1024; if (init_dma) - ep->dma = &dev->dma [tmp - 1]; + ep->dma = &dev->dma[tmp - 1]; } else ep->fifo_size = 64; - ep->regs = &dev->epregs [tmp]; + ep->regs = &dev->epregs[tmp]; ep->cfg = &dev->epregs[tmp]; ep_reset_228x(dev->regs, ep); } - usb_ep_set_maxpacket_limit(&dev->ep [0].ep, 64); - usb_ep_set_maxpacket_limit(&dev->ep [5].ep, 64); - usb_ep_set_maxpacket_limit(&dev->ep [6].ep, 64); + usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64); + usb_ep_set_maxpacket_limit(&dev->ep[5].ep, 64); + usb_ep_set_maxpacket_limit(&dev->ep[6].ep, 64); - dev->gadget.ep0 = &dev->ep [0].ep; - dev->ep [0].stopped = 0; - INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); + dev->gadget.ep0 = &dev->ep[0].ep; + dev->ep[0].stopped = 0; + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); /* we want to prevent lowlevel/insecure access from the USB host, * but erratum 0119 means this enable bit is ignored */ for (tmp = 0; tmp < 5; tmp++) - writel (EP_DONTUSE, &dev->dep [tmp].dep_cfg); + writel(EP_DONTUSE, &dev->dep[tmp].dep_cfg); } static void usb_reinit_338x(struct net2280 *dev) @@ -2263,7 +2256,7 @@ static void ep0_start_228x(struct net2280 *dev) writel(BIT(CLEAR_EP_HIDE_STATUS_PHASE) | BIT(CLEAR_NAK_OUT_PACKETS) | BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - , &dev->epregs [0].ep_rsp); + , &dev->epregs[0].ep_rsp); /* * hardware optionally handles a bunch of standard requests @@ -2298,7 +2291,7 @@ static void ep0_start_228x(struct net2280 *dev) &dev->regs->pciirqenb1); /* don't leave any writes posted */ - (void) readl (&dev->usb->usbctl); + (void) readl(&dev->usb->usbctl); } static void ep0_start_338x(struct net2280 *dev) @@ -2377,20 +2370,22 @@ static int net2280_start(struct usb_gadget *_gadget, || !driver->setup) return -EINVAL; - dev = container_of (_gadget, struct net2280, gadget); + dev = container_of(_gadget, struct net2280, gadget); for (i = 0; i < dev->n_ep; i++) - dev->ep [i].irqs = 0; + dev->ep[i].irqs = 0; /* hook up the driver ... */ dev->softconnect = 1; driver->driver.bus = NULL; dev->driver = driver; - retval = device_create_file (&dev->pdev->dev, &dev_attr_function); - if (retval) goto err_unbind; - retval = device_create_file (&dev->pdev->dev, &dev_attr_queues); - if (retval) goto err_func; + retval = device_create_file(&dev->pdev->dev, &dev_attr_function); + if (retval) + goto err_unbind; + retval = device_create_file(&dev->pdev->dev, &dev_attr_queues); + if (retval) + goto err_func; /* Enable force-full-speed testing mode, if desired */ if (full_speed && dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) @@ -2399,30 +2394,29 @@ static int net2280_start(struct usb_gadget *_gadget, /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. */ - net2280_led_active (dev, 1); + net2280_led_active(dev, 1); if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) defect7374_enable_data_eps_zero(dev); - ep0_start (dev); + ep0_start(dev); - DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n", + DEBUG(dev, "%s ready, usbctl %08x stdrsp %08x\n", driver->driver.name, - readl (&dev->usb->usbctl), - readl (&dev->usb->stdrsp)); + readl(&dev->usb->usbctl), + readl(&dev->usb->stdrsp)); /* pci writes may still be posted */ return 0; err_func: - device_remove_file (&dev->pdev->dev, &dev_attr_function); + device_remove_file(&dev->pdev->dev, &dev_attr_function); err_unbind: dev->driver = NULL; return retval; } -static void -stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) +static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver) { int i; @@ -2433,9 +2427,9 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) /* stop hardware; prevent new request submissions; * and kill any outstanding requests. */ - usb_reset (dev); + usb_reset(dev); for (i = 0; i < dev->n_ep; i++) - nuke (&dev->ep [i]); + nuke(&dev->ep[i]); /* report disconnect; the driver is already quiesced */ if (driver) { @@ -2444,7 +2438,7 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) spin_lock(&dev->lock); } - usb_reinit (dev); + usb_reinit(dev); } static int net2280_stop(struct usb_gadget *_gadget, @@ -2453,22 +2447,22 @@ static int net2280_stop(struct usb_gadget *_gadget, struct net2280 *dev; unsigned long flags; - dev = container_of (_gadget, struct net2280, gadget); + dev = container_of(_gadget, struct net2280, gadget); - spin_lock_irqsave (&dev->lock, flags); - stop_activity (dev, driver); - spin_unlock_irqrestore (&dev->lock, flags); + spin_lock_irqsave(&dev->lock, flags); + stop_activity(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); dev->driver = NULL; - net2280_led_active (dev, 0); + net2280_led_active(dev, 0); /* Disable full-speed test mode */ if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) writel(0, &dev->usb->xcvrdiag); - device_remove_file (&dev->pdev->dev, &dev_attr_function); - device_remove_file (&dev->pdev->dev, &dev_attr_queues); + device_remove_file(&dev->pdev->dev, &dev_attr_function); + device_remove_file(&dev->pdev->dev, &dev_attr_queues); DEBUG(dev, "unregistered driver '%s'\n", driver ? driver->driver.name : ""); @@ -2482,31 +2476,31 @@ static int net2280_stop(struct usb_gadget *_gadget, * also works for dma-capable endpoints, in pio mode or just * to manually advance the queue after short OUT transfers. */ -static void handle_ep_small (struct net2280_ep *ep) +static void handle_ep_small(struct net2280_ep *ep) { struct net2280_request *req; u32 t; /* 0 error, 1 mid-data, 2 done */ int mode = 1; - if (!list_empty (&ep->queue)) - req = list_entry (ep->queue.next, + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, struct net2280_request, queue); else req = NULL; /* ack all, and handle what we care about */ - t = readl (&ep->regs->ep_stat); + t = readl(&ep->regs->ep_stat); ep->irqs++; #if 0 - VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n", + VDEBUG(ep->dev, "%s ack ep_stat %08x, req %p\n", ep->ep.name, t, req ? &req->req : 0); #endif if (!ep->is_in || ep->dev->pdev->device == 0x2280) writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat); else /* Added for 2282 */ - writel (t, &ep->regs->ep_stat); + writel(t, &ep->regs->ep_stat); /* for ep0, monitor token irqs to catch data stage length errors * and to synchronize on status. @@ -2518,33 +2512,33 @@ static void handle_ep_small (struct net2280_ep *ep) * control requests could be slightly faster without token synch for * status, but status can jam up that way. */ - if (unlikely (ep->num == 0)) { + if (unlikely(ep->num == 0)) { if (ep->is_in) { /* status; stop NAKing */ if (t & BIT(DATA_OUT_PING_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) { ep->stopped = 1; - set_halt (ep); + set_halt(ep); } if (!req) - allow_status (ep); + allow_status(ep); mode = 2; /* reply to extra IN data tokens with a zlp */ } else if (t & BIT(DATA_IN_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) { ep->stopped = 1; - set_halt (ep); + set_halt(ep); mode = 2; } else if (ep->responded && !req && !ep->stopped) - write_fifo (ep, NULL); + write_fifo(ep, NULL); } } else { /* status; stop NAKing */ if (t & BIT(DATA_IN_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) { ep->stopped = 1; - set_halt (ep); + set_halt(ep); } mode = 2; /* an extra OUT token is an error */ @@ -2553,20 +2547,20 @@ static void handle_ep_small (struct net2280_ep *ep) && req->req.actual == req->req.length) || (ep->responded && !req)) { ep->dev->protocol_stall = 1; - set_halt (ep); + set_halt(ep); ep->stopped = 1; if (req) - done (ep, req, -EOVERFLOW); + done(ep, req, -EOVERFLOW); req = NULL; } } } - if (unlikely (!req)) + if (unlikely(!req)) return; /* manual DMA queue advance after short OUT */ - if (likely (ep->dma)) { + if (likely(ep->dma)) { if (t & BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)) { u32 count; int stopped = ep->stopped; @@ -2576,27 +2570,27 @@ static void handle_ep_small (struct net2280_ep *ep) * iff (M < N) we won't ever see a DMA interrupt. */ ep->stopped = 1; - for (count = 0; ; t = readl (&ep->regs->ep_stat)) { + for (count = 0; ; t = readl(&ep->regs->ep_stat)) { /* any preceding dma transfers must finish. * dma handles (M >= N), may empty the queue */ - scan_dma_completions (ep); - if (unlikely (list_empty (&ep->queue) + scan_dma_completions(ep); + if (unlikely(list_empty(&ep->queue) || ep->out_overflow)) { req = NULL; break; } - req = list_entry (ep->queue.next, + req = list_entry(ep->queue.next, struct net2280_request, queue); /* here either (M < N), a "real" short rx; * or (M == N) and the queue didn't empty */ if (likely(t & BIT(FIFO_EMPTY))) { - count = readl (&ep->dma->dmacount); + count = readl(&ep->dma->dmacount); count &= DMA_BYTE_COUNT_MASK; - if (readl (&ep->dma->dmadesc) + if (readl(&ep->dma->dmadesc) != req->td_dma) req = NULL; break; @@ -2606,37 +2600,37 @@ static void handle_ep_small (struct net2280_ep *ep) /* stop DMA, leave ep NAKing */ writel(BIT(DMA_ABORT), &ep->dma->dmastat); - spin_stop_dma (ep->dma); + spin_stop_dma(ep->dma); - if (likely (req)) { + if (likely(req)) { req->td->dmacount = 0; - t = readl (&ep->regs->ep_avail); - dma_done (ep, req, count, + t = readl(&ep->regs->ep_avail); + dma_done(ep, req, count, (ep->out_overflow || t) ? -EOVERFLOW : 0); } /* also flush to prevent erratum 0106 trouble */ - if (unlikely (ep->out_overflow + if (unlikely(ep->out_overflow || (ep->dev->chiprev == 0x0100 && ep->dev->gadget.speed == USB_SPEED_FULL))) { - out_flush (ep); + out_flush(ep); ep->out_overflow = 0; } /* (re)start dma if needed, stop NAKing */ ep->stopped = stopped; - if (!list_empty (&ep->queue)) - restart_dma (ep); + if (!list_empty(&ep->queue)) + restart_dma(ep); } else - DEBUG (ep->dev, "%s dma ep_stat %08x ??\n", + DEBUG(ep->dev, "%s dma ep_stat %08x ??\n", ep->ep.name, t); return; /* data packet(s) received (in the fifo, OUT) */ } else if (t & BIT(DATA_PACKET_RECEIVED_INTERRUPT)) { - if (read_fifo (ep, req) && ep->num != 0) + if (read_fifo(ep, req) && ep->num != 0) mode = 2; /* data packet(s) transmitted (IN) */ @@ -2649,12 +2643,10 @@ static void handle_ep_small (struct net2280_ep *ep) req->req.actual += len; /* if we wrote it all, we're usually done */ - if (req->req.actual == req->req.length) { - if (ep->num == 0) { - /* send zlps until the status stage */ - } else if (!req->req.zero || len != ep->ep.maxpacket) + /* send zlps until the status stage */ + if ((req->req.actual == req->req.length) && + (!req->req.zero || len != ep->ep.maxpacket) && ep->num) mode = 2; - } /* there was nothing to do ... */ } else if (mode == 1) @@ -2663,7 +2655,7 @@ static void handle_ep_small (struct net2280_ep *ep) /* done */ if (mode == 2) { /* stream endpoints often resubmit/unlink in completion */ - done (ep, req, 0); + done(ep, req, 0); /* maybe advance queue to next request */ if (ep->num == 0) { @@ -2672,16 +2664,16 @@ static void handle_ep_small (struct net2280_ep *ep) * them control that, the api doesn't (yet) allow it. */ if (!ep->stopped) - allow_status (ep); + allow_status(ep); req = NULL; } else { - if (!list_empty (&ep->queue) && !ep->stopped) - req = list_entry (ep->queue.next, + if (!list_empty(&ep->queue) && !ep->stopped) + req = list_entry(ep->queue.next, struct net2280_request, queue); else req = NULL; if (req && !ep->is_in) - stop_out_naking (ep); + stop_out_naking(ep); } } @@ -2692,18 +2684,17 @@ static void handle_ep_small (struct net2280_ep *ep) /* load IN fifo with next packet (may be zlp) */ if (t & BIT(DATA_PACKET_TRANSMITTED_INTERRUPT)) - write_fifo (ep, &req->req); + write_fifo(ep, &req->req); } } -static struct net2280_ep * -get_ep_by_addr (struct net2280 *dev, u16 wIndex) +static struct net2280_ep *get_ep_by_addr(struct net2280 *dev, u16 wIndex) { struct net2280_ep *ep; if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return &dev->ep [0]; - list_for_each_entry (ep, &dev->gadget.ep_list, ep.ep_list) { + return &dev->ep[0]; + list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { u8 bEndpointAddress; if (!ep->desc) @@ -3061,7 +3052,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, return; } -static void handle_stat0_irqs (struct net2280 *dev, u32 stat) +static void handle_stat0_irqs(struct net2280 *dev, u32 stat) { struct net2280_ep *ep; u32 num, scratch; @@ -3070,12 +3061,12 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) stat &= ~BIT(INTA_ASSERTED); if (!stat) return; - // DEBUG (dev, "irqstat0 %04x\n", stat); + /* DEBUG(dev, "irqstat0 %04x\n", stat); */ /* starting a control request? */ if (unlikely(stat & BIT(SETUP_PACKET_INTERRUPT))) { union { - u32 raw [2]; + u32 raw[2]; struct usb_ctrlrequest r; } u; int tmp; @@ -3096,19 +3087,20 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) usb_ep_set_maxpacket_limit(&dev->ep[0].ep, EP0_HS_MAX_PACKET_SIZE); } - net2280_led_speed (dev, dev->gadget.speed); - DEBUG(dev, "%s\n", usb_speed_string(dev->gadget.speed)); + net2280_led_speed(dev, dev->gadget.speed); + DEBUG(dev, "%s\n", + usb_speed_string(dev->gadget.speed)); } - ep = &dev->ep [0]; + ep = &dev->ep[0]; ep->irqs++; /* make sure any leftover request state is cleared */ stat &= ~BIT(ENDPOINT_0_INTERRUPT); - while (!list_empty (&ep->queue)) { - req = list_entry (ep->queue.next, + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct net2280_request, queue); - done (ep, req, (req->req.actual == req->req.length) + done(ep, req, (req->req.actual == req->req.length) ? 0 : -EPROTO); } ep->stopped = 0; @@ -3139,8 +3131,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) u.raw[0] = readl(&dev->usb->setup0123); u.raw[1] = readl(&dev->usb->setup4567); - cpu_to_le32s (&u.raw [0]); - cpu_to_le32s (&u.raw [1]); + cpu_to_le32s(&u.raw[0]); + cpu_to_le32s(&u.raw[1]); if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) defect7374_workaround(dev, u.r); @@ -3165,12 +3157,12 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) scratch = BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | BIT(DATA_IN_TOKEN_INTERRUPT); - stop_out_naking (ep); + stop_out_naking(ep); } else scratch = BIT(DATA_PACKET_RECEIVED_INTERRUPT) | BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | BIT(DATA_IN_TOKEN_INTERRUPT); - writel (scratch, &dev->epregs [0].ep_irqenb); + writel(scratch, &dev->epregs[0].ep_irqenb); /* we made the hardware handle most lowlevel requests; * everything else goes uplevel to the gadget code. @@ -3190,21 +3182,21 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device and interface status */ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) goto delegate; - if ((e = get_ep_by_addr (dev, w_index)) == NULL - || w_length > 2) + e = get_ep_by_addr(dev, w_index); + if (!e || w_length > 2) goto do_stall; if (readl(&e->regs->ep_rsp) & BIT(SET_ENDPOINT_HALT)) - status = cpu_to_le32 (1); + status = cpu_to_le32(1); else - status = cpu_to_le32 (0); + status = cpu_to_le32(0); /* don't bother with a request object! */ - writel (0, &dev->epregs [0].ep_irqenb); - set_fifo_bytecount (ep, w_length); - writel ((__force u32)status, &dev->epregs [0].ep_data); - allow_status (ep); - VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status); + writel(0, &dev->epregs[0].ep_irqenb); + set_fifo_bytecount(ep, w_length); + writel((__force u32)status, &dev->epregs[0].ep_data); + allow_status(ep); + VDEBUG(dev, "%s stat %02x\n", ep->ep.name, status); goto next_endpoints; } break; @@ -3217,7 +3209,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, w_index)) == NULL) + e = get_ep_by_addr(dev, w_index); + if (!e) goto do_stall; if (e->wedged) { VDEBUG(dev, "%s wedged, halt not cleared\n", @@ -3230,7 +3223,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) !list_empty(&e->queue) && e->td_dma) restart_dma(e); } - allow_status (ep); + allow_status(ep); goto next_endpoints; } break; @@ -3243,35 +3236,36 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, w_index)) == NULL) + e = get_ep_by_addr(dev, w_index); + if (!e) goto do_stall; if (e->ep.name == ep0name) goto do_stall; - set_halt (e); + set_halt(e); if (dev->pdev->vendor == PCI_VENDOR_ID_PLX && e->dma) abort_dma(e); - allow_status (ep); - VDEBUG (dev, "%s set halt\n", ep->ep.name); + allow_status(ep); + VDEBUG(dev, "%s set halt\n", ep->ep.name); goto next_endpoints; } break; default: delegate: - VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x " + VDEBUG(dev, "setup %02x.%02x v%04x i%04x l%04x " "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, w_value, w_index, w_length, readl(&ep->cfg->ep_cfg)); ep->responded = 0; - spin_unlock (&dev->lock); - tmp = dev->driver->setup (&dev->gadget, &u.r); - spin_lock (&dev->lock); + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &u.r); + spin_lock(&dev->lock); } /* stall ep0 on error */ if (tmp < 0) { do_stall: - VDEBUG (dev, "req %02x.%02x protocol STALL; stat %d\n", + VDEBUG(dev, "req %02x.%02x protocol STALL; stat %d\n", u.r.bRequestType, u.r.bRequest, tmp); dev->protocol_stall = 1; } @@ -3299,12 +3293,12 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) continue; scratch ^= t; - ep = &dev->ep [num]; - handle_ep_small (ep); + ep = &dev->ep[num]; + handle_ep_small(ep); } if (stat) - DEBUG (dev, "unhandled irqstat0 %08x\n", stat); + DEBUG(dev, "unhandled irqstat0 %08x\n", stat); } #define DMA_INTERRUPTS (BIT(DMA_D_INTERRUPT) | \ @@ -3316,7 +3310,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) BIT(PCI_TARGET_ABORT_RECEIVED_INTERRUPT) | \ BIT(PCI_RETRY_ABORT_INTERRUPT)) -static void handle_stat1_irqs (struct net2280 *dev, u32 stat) +static void handle_stat1_irqs(struct net2280 *dev, u32 stat) { struct net2280_ep *ep; u32 tmp, num, mask, scratch; @@ -3331,17 +3325,17 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) * only indicates a change in the reset state). */ if (stat & tmp) { - writel (tmp, &dev->regs->irqstat1); + writel(tmp, &dev->regs->irqstat1); if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) - && ((readl (&dev->usb->usbstat) & mask) + && ((readl(&dev->usb->usbstat) & mask) == 0)) - || ((readl (&dev->usb->usbctl) + || ((readl(&dev->usb->usbctl) & BIT(VBUS_PIN)) == 0) - ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) { - DEBUG (dev, "disconnect %s\n", + ) && (dev->gadget.speed != USB_SPEED_UNKNOWN)) { + DEBUG(dev, "disconnect %s\n", dev->driver->driver.name); - stop_activity (dev, dev->driver); - ep0_start (dev); + stop_activity(dev, dev->driver); + ep0_start(dev); return; } stat &= ~tmp; @@ -3358,15 +3352,15 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) */ tmp = BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT); if (stat & tmp) { - writel (tmp, &dev->regs->irqstat1); + writel(tmp, &dev->regs->irqstat1); if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) - dev->driver->suspend (&dev->gadget); + dev->driver->suspend(&dev->gadget); if (!enable_suspend) stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT); } else { if (dev->driver->resume) - dev->driver->resume (&dev->gadget); + dev->driver->resume(&dev->gadget); /* at high speed, note erratum 0133 */ } stat &= ~tmp; @@ -3374,7 +3368,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) /* clear any other status/irqs */ if (stat) - writel (stat, &dev->regs->irqstat1); + writel(stat, &dev->regs->irqstat1); /* some status we can just ignore */ if (dev->pdev->device == 0x2280) @@ -3390,7 +3384,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) if (!stat) return; - // DEBUG (dev, "irqstat1 %08x\n", stat); + /* DEBUG(dev, "irqstat1 %08x\n", stat);*/ /* DMA status, for ep-{a,b,c,d} */ scratch = stat & DMA_INTERRUPTS; @@ -3404,15 +3398,15 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) continue; scratch ^= tmp; - ep = &dev->ep [num + 1]; + ep = &dev->ep[num + 1]; dma = ep->dma; if (!dma) continue; /* clear ep's dma status */ - tmp = readl (&dma->dmastat); - writel (tmp, &dma->dmastat); + tmp = readl(&dma->dmastat); + writel(tmp, &dma->dmastat); /* dma sync*/ if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { @@ -3427,11 +3421,11 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) */ if (!use_dma_chaining) { if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) { - DEBUG (ep->dev, "%s no xact done? %08x\n", + DEBUG(ep->dev, "%s no xact done? %08x\n", ep->ep.name, tmp); continue; } - stop_dma (ep->dma); + stop_dma(ep->dma); } /* OUT transfers terminate when the data from the @@ -3444,16 +3438,16 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) * long time ... we ignore that for now, accounting * precisely (like PIO does) needs per-packet irqs */ - scan_dma_completions (ep); + scan_dma_completions(ep); /* disable dma on inactive queues; else maybe restart */ - if (list_empty (&ep->queue)) { + if (list_empty(&ep->queue)) { if (use_dma_chaining) - stop_dma (ep->dma); + stop_dma(ep->dma); } else { - tmp = readl (&dma->dmactl); + tmp = readl(&dma->dmactl); if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0) - restart_dma (ep); + restart_dma(ep); else if (ep->is_in && use_dma_chaining) { struct net2280_request *req; __le32 dmacount; @@ -3463,13 +3457,13 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) * used to trigger changing DMA_FIFO_VALIDATE * (affects automagic zlp writes). */ - req = list_entry (ep->queue.next, + req = list_entry(ep->queue.next, struct net2280_request, queue); dmacount = req->td->dmacount; dmacount &= cpu_to_le32(BIT(VALID_BIT) | DMA_BYTE_COUNT_MASK); if (dmacount && (dmacount & valid_bit) == 0) - restart_dma (ep); + restart_dma(ep); } } ep->irqs++; @@ -3479,21 +3473,21 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) * if they appear very often, here's where to try recovering. */ if (stat & PCI_ERROR_INTERRUPTS) { - ERROR (dev, "pci dma error; stat %08x\n", stat); + ERROR(dev, "pci dma error; stat %08x\n", stat); stat &= ~PCI_ERROR_INTERRUPTS; /* these are fatal errors, but "maybe" they won't * happen again ... */ - stop_activity (dev, dev->driver); - ep0_start (dev); + stop_activity(dev, dev->driver); + ep0_start(dev); stat = 0; } if (stat) - DEBUG (dev, "unhandled irqstat1 %08x\n", stat); + DEBUG(dev, "unhandled irqstat1 %08x\n", stat); } -static irqreturn_t net2280_irq (int irq, void *_dev) +static irqreturn_t net2280_irq(int irq, void *_dev) { struct net2280 *dev = _dev; @@ -3502,13 +3496,13 @@ static irqreturn_t net2280_irq (int irq, void *_dev) (!(readl(&dev->regs->irqstat0) & BIT(INTA_ASSERTED)))) return IRQ_NONE; - spin_lock (&dev->lock); + spin_lock(&dev->lock); /* handle disconnect, dma, and more */ - handle_stat1_irqs (dev, readl (&dev->regs->irqstat1)); + handle_stat1_irqs(dev, readl(&dev->regs->irqstat1)); /* control requests and PIO */ - handle_stat0_irqs (dev, readl (&dev->regs->irqstat0)); + handle_stat0_irqs(dev, readl(&dev->regs->irqstat0)); if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { /* re-enable interrupt to trigger any possible new interrupt */ @@ -3517,54 +3511,54 @@ static irqreturn_t net2280_irq (int irq, void *_dev) writel(pciirqenb1, &dev->regs->pciirqenb1); } - spin_unlock (&dev->lock); + spin_unlock(&dev->lock); return IRQ_HANDLED; } /*-------------------------------------------------------------------------*/ -static void gadget_release (struct device *_dev) +static void gadget_release(struct device *_dev) { - struct net2280 *dev = dev_get_drvdata (_dev); + struct net2280 *dev = dev_get_drvdata(_dev); - kfree (dev); + kfree(dev); } /* tear down the binding between this driver and the pci device */ -static void net2280_remove (struct pci_dev *pdev) +static void net2280_remove(struct pci_dev *pdev) { - struct net2280 *dev = pci_get_drvdata (pdev); + struct net2280 *dev = pci_get_drvdata(pdev); usb_del_gadget_udc(&dev->gadget); BUG_ON(dev->driver); /* then clean up the resources we allocated during probe() */ - net2280_led_shutdown (dev); + net2280_led_shutdown(dev); if (dev->requests) { int i; for (i = 1; i < 5; i++) { - if (!dev->ep [i].dummy) + if (!dev->ep[i].dummy) continue; - pci_pool_free (dev->requests, dev->ep [i].dummy, - dev->ep [i].td_dma); + pci_pool_free(dev->requests, dev->ep[i].dummy, + dev->ep[i].td_dma); } - pci_pool_destroy (dev->requests); + pci_pool_destroy(dev->requests); } if (dev->got_irq) - free_irq (pdev->irq, dev); + free_irq(pdev->irq, dev); if (use_msi && dev->pdev->vendor == PCI_VENDOR_ID_PLX) pci_disable_msi(pdev); if (dev->regs) - iounmap (dev->regs); + iounmap(dev->regs); if (dev->region) - release_mem_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); if (dev->enabled) - pci_disable_device (pdev); - device_remove_file (&pdev->dev, &dev_attr_registers); + pci_disable_device(pdev); + device_remove_file(&pdev->dev, &dev_attr_registers); INFO (dev, "unbind\n"); } @@ -3573,7 +3567,7 @@ static void net2280_remove (struct pci_dev *pdev) * don't respond over USB until a gadget driver binds to us. */ -static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) +static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net2280 *dev; unsigned long resource, len; @@ -3584,14 +3578,14 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) use_dma_chaining = 0; /* alloc, and start init */ - dev = kzalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL){ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { retval = -ENOMEM; goto done; } - pci_set_drvdata (pdev, dev); - spin_lock_init (&dev->lock); + pci_set_drvdata(pdev, dev); + spin_lock_init(&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; dev->gadget.max_speed = (dev->pdev->vendor == PCI_VENDOR_ID_PLX) ? @@ -3601,8 +3595,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->gadget.name = driver_name; /* now all the pci goodies ... */ - if (pci_enable_device (pdev) < 0) { - retval = -ENODEV; + if (pci_enable_device(pdev) < 0) { + retval = -ENODEV; goto done; } dev->enabled = 1; @@ -3611,10 +3605,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) * BAR 1 is 8051 memory; unused here (note erratum 0103) * BAR 2 is fifo memory; unused here */ - resource = pci_resource_start (pdev, 0); - len = pci_resource_len (pdev, 0); - if (!request_mem_region (resource, len, driver_name)) { - DEBUG (dev, "controller already in use\n"); + resource = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + if (!request_mem_region(resource, len, driver_name)) { + DEBUG(dev, "controller already in use\n"); retval = -EBUSY; goto done; } @@ -3624,9 +3618,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) * 8051 code into the chip, e.g. to turn on PCI PM. */ - base = ioremap_nocache (resource, len); + base = ioremap_nocache(resource, len); if (base == NULL) { - DEBUG (dev, "can't map memory\n"); + DEBUG(dev, "can't map memory\n"); retval = -EFAULT; goto done; } @@ -3655,7 +3649,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->plregs = (struct usb338x_pl_regs __iomem *) (base + 0x0800); usbstat = readl(&dev->usb->usbstat); - dev->enhanced_mode = (usbstat & BIT(11)) ? 1 : 0; + dev->enhanced_mode = !!(usbstat & BIT(11)); dev->n_ep = (dev->enhanced_mode) ? 9 : 5; /* put into initial config, link up all endpoints */ fsmvalue = get_idx_reg(dev->regs, SCRATCH) & @@ -3670,12 +3664,12 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) writel(0, &dev->usb->usbctl); } - usb_reset (dev); - usb_reinit (dev); + usb_reset(dev); + usb_reinit(dev); /* irq setup after old hardware is cleaned up */ if (!pdev->irq) { - ERROR (dev, "No IRQ. Check PCI setup!\n"); + ERROR(dev, "No IRQ. Check PCI setup!\n"); retval = -ENODEV; goto done; } @@ -3684,9 +3678,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) if (pci_enable_msi(pdev)) ERROR(dev, "Failed to enable MSI mode\n"); - if (request_irq (pdev->irq, net2280_irq, IRQF_SHARED, driver_name, dev) - != 0) { - ERROR (dev, "request interrupt %d failed\n", pdev->irq); + if (request_irq(pdev->irq, net2280_irq, IRQF_SHARED, + driver_name, dev)) { + ERROR(dev, "request interrupt %d failed\n", pdev->irq); retval = -EBUSY; goto done; } @@ -3694,28 +3688,28 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) /* DMA setup */ /* NOTE: we know only the 32 LSBs of dma addresses may be nonzero */ - dev->requests = pci_pool_create ("requests", pdev, - sizeof (struct net2280_dma), + dev->requests = pci_pool_create("requests", pdev, + sizeof(struct net2280_dma), 0 /* no alignment requirements */, 0 /* or page-crossing issues */); if (!dev->requests) { - DEBUG (dev, "can't get request pool\n"); + DEBUG(dev, "can't get request pool\n"); retval = -ENOMEM; goto done; } for (i = 1; i < 5; i++) { struct net2280_dma *td; - td = pci_pool_alloc (dev->requests, GFP_KERNEL, - &dev->ep [i].td_dma); + td = pci_pool_alloc(dev->requests, GFP_KERNEL, + &dev->ep[i].td_dma); if (!td) { - DEBUG (dev, "can't get dummy %d\n", i); + DEBUG(dev, "can't get dummy %d\n", i); retval = -ENOMEM; goto done; } td->dmacount = 0; /* not VALID */ td->dmadesc = td->dmaaddr; - dev->ep [i].dummy = td; + dev->ep[i].dummy = td; } /* enable lower-overhead pci memory bursts during DMA */ @@ -3729,22 +3723,23 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) BIT(DMA_READ_LINE_ENABLE), &dev->pci->pcimstctl); /* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */ - pci_set_master (pdev); - pci_try_set_mwi (pdev); + pci_set_master(pdev); + pci_try_set_mwi(pdev); /* ... also flushes any posted pci writes */ - dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff; + dev->chiprev = get_idx_reg(dev->regs, REG_CHIPREV) & 0xffff; /* done */ - INFO (dev, "%s\n", driver_desc); - INFO (dev, "irq %d, pci mem %p, chip rev %04x\n", + INFO(dev, "%s\n", driver_desc); + INFO(dev, "irq %d, pci mem %p, chip rev %04x\n", pdev->irq, base, dev->chiprev); INFO(dev, "version: " DRIVER_VERSION "; dma %s %s\n", use_dma ? (use_dma_chaining ? "chaining" : "enabled") : "disabled", dev->enhanced_mode ? "enhanced mode" : "legacy mode"); - retval = device_create_file (&pdev->dev, &dev_attr_registers); - if (retval) goto done; + retval = device_create_file(&pdev->dev, &dev_attr_registers); + if (retval) + goto done; retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, gadget_release); @@ -3754,7 +3749,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) done: if (dev) - net2280_remove (pdev); + net2280_remove(pdev); return retval; } @@ -3762,16 +3757,16 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) * generating IRQs across the upcoming reboot. */ -static void net2280_shutdown (struct pci_dev *pdev) +static void net2280_shutdown(struct pci_dev *pdev) { - struct net2280 *dev = pci_get_drvdata (pdev); + struct net2280 *dev = pci_get_drvdata(pdev); /* disable IRQs */ - writel (0, &dev->regs->pciirqenb0); - writel (0, &dev->regs->pciirqenb1); + writel(0, &dev->regs->pciirqenb0); + writel(0, &dev->regs->pciirqenb1); /* disable the pullup so the host will think we're gone */ - writel (0, &dev->usb->usbctl); + writel(0, &dev->usb->usbctl); /* Disable full-speed test mode */ if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) @@ -3781,7 +3776,7 @@ static void net2280_shutdown (struct pci_dev *pdev) /*-------------------------------------------------------------------------*/ -static const struct pci_device_id pci_ids [] = { { +static const struct pci_device_id pci_ids[] = { { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, .vendor = PCI_VENDOR_ID_PLX_LEGACY, @@ -3814,7 +3809,7 @@ static const struct pci_device_id pci_ids [] = { { }, { /* end: all zeroes */ } }; -MODULE_DEVICE_TABLE (pci, pci_ids); +MODULE_DEVICE_TABLE(pci, pci_ids); /* pci driver glue; this is a "new style" PCI driver module */ static struct pci_driver net2280_pci_driver = { @@ -3830,6 +3825,6 @@ static struct pci_driver net2280_pci_driver = { module_pci_driver(net2280_pci_driver); -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index e1c5d1a5a7d0..f019d6c74fc3 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -25,19 +25,18 @@ * caller must own the device lock. */ -static inline u32 -get_idx_reg (struct net2280_regs __iomem *regs, u32 index) +static inline u32 get_idx_reg(struct net2280_regs __iomem *regs, u32 index) { - writel (index, ®s->idxaddr); + writel(index, ®s->idxaddr); /* NOTE: synchs device/cpu memory views */ - return readl (®s->idxdata); + return readl(®s->idxdata); } static inline void -set_idx_reg (struct net2280_regs __iomem *regs, u32 index, u32 value) +set_idx_reg(struct net2280_regs __iomem *regs, u32 index, u32 value) { - writel (index, ®s->idxaddr); - writel (value, ®s->idxdata); + writel(index, ®s->idxaddr); + writel(value, ®s->idxdata); /* posted, may not be visible yet */ } @@ -81,7 +80,7 @@ struct net2280_dma { __le32 dmaaddr; /* the buffer */ __le32 dmadesc; /* next dma descriptor */ __le32 _reserved; -} __attribute__ ((aligned (16))); +} __aligned(16); /*-------------------------------------------------------------------------*/ @@ -113,7 +112,7 @@ struct net2280_ep { responded : 1; }; -static inline void allow_status (struct net2280_ep *ep) +static inline void allow_status(struct net2280_ep *ep) { /* ep0 only */ writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) | @@ -152,7 +151,7 @@ struct net2280 { struct usb_gadget gadget; spinlock_t lock; struct net2280_ep ep[9]; - struct usb_gadget_driver *driver; + struct usb_gadget_driver *driver; unsigned enabled : 1, protocol_stall : 1, softconnect : 1, @@ -185,10 +184,10 @@ struct net2280 { struct usb338x_pl_regs __iomem *plregs; struct pci_pool *requests; - // statistics... + /* statistics...*/ }; -static inline void set_halt (struct net2280_ep *ep) +static inline void set_halt(struct net2280_ep *ep) { /* ep0 and bulk/intr endpoints */ writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) | @@ -198,7 +197,7 @@ static inline void set_halt (struct net2280_ep *ep) &ep->regs->ep_rsp); } -static inline void clear_halt (struct net2280_ep *ep) +static inline void clear_halt(struct net2280_ep *ep) { /* ep0 and bulk/intr endpoints */ writel(BIT(CLEAR_ENDPOINT_HALT) | @@ -250,7 +249,7 @@ static inline void clear_halt (struct net2280_ep *ep) #ifdef USE_RDK_LEDS -static inline void net2280_led_init (struct net2280 *dev) +static inline void net2280_led_init(struct net2280 *dev) { /* LED3 (green) is on during USB activity. note erratum 0113. */ writel(BIT(GPIO3_LED_SELECT) | @@ -263,9 +262,9 @@ static inline void net2280_led_init (struct net2280 *dev) /* indicate speed with bi-color LED 0/1 */ static inline -void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed) +void net2280_led_speed(struct net2280 *dev, enum usb_device_speed speed) { - u32 val = readl (&dev->regs->gpioctl); + u32 val = readl(&dev->regs->gpioctl); switch (speed) { case USB_SPEED_SUPER: /* green + red */ val |= BIT(GPIO0_DATA) | BIT(GPIO1_DATA); @@ -282,25 +281,26 @@ void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed) val &= ~(BIT(GPIO1_DATA) | BIT(GPIO0_DATA)); break; } - writel (val, &dev->regs->gpioctl); + writel(val, &dev->regs->gpioctl); } /* indicate power with LED 2 */ -static inline void net2280_led_active (struct net2280 *dev, int is_active) +static inline void net2280_led_active(struct net2280 *dev, int is_active) { - u32 val = readl (&dev->regs->gpioctl); + u32 val = readl(&dev->regs->gpioctl); - // FIXME this LED never seems to turn on. + /* FIXME this LED never seems to turn on.*/ if (is_active) val |= GPIO2_DATA; else val &= ~GPIO2_DATA; - writel (val, &dev->regs->gpioctl); + writel(val, &dev->regs->gpioctl); } -static inline void net2280_led_shutdown (struct net2280 *dev) + +static inline void net2280_led_shutdown(struct net2280 *dev) { /* turn off all four GPIO*_DATA bits */ - writel (readl (&dev->regs->gpioctl) & ~0x0f, + writel(readl(&dev->regs->gpioctl) & ~0x0f, &dev->regs->gpioctl); } @@ -314,32 +314,32 @@ static inline void net2280_led_shutdown (struct net2280 *dev) /*-------------------------------------------------------------------------*/ -#define xprintk(dev,level,fmt,args...) \ - printk(level "%s %s: " fmt , driver_name , \ - pci_name(dev->pdev) , ## args) +#define xprintk(dev, level, fmt, args...) \ + printk(level "%s %s: " fmt, driver_name, \ + pci_name(dev->pdev), ## args) #ifdef DEBUG #undef DEBUG -#define DEBUG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) +#define DEBUG(dev, fmt, args...) \ + xprintk(dev, KERN_DEBUG, fmt, ## args) #else -#define DEBUG(dev,fmt,args...) \ +#define DEBUG(dev, fmt, args...) \ do { } while (0) -#endif /* DEBUG */ +#endif /* DEBUG*/ #ifdef VERBOSE #define VDEBUG DEBUG #else -#define VDEBUG(dev,fmt,args...) \ +#define VDEBUG(dev, fmt, args...) \ do { } while (0) #endif /* VERBOSE */ -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARNING(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define ERROR(dev, fmt, args...) \ + xprintk(dev, KERN_ERR, fmt, ## args) +#define WARNING(dev, fmt, args...) \ + xprintk(dev, KERN_WARNING, fmt, ## args) +#define INFO(dev, fmt, args...) \ + xprintk(dev, KERN_INFO, fmt, ## args) /*-------------------------------------------------------------------------*/ @@ -354,36 +354,36 @@ static inline void set_fifo_bytecount(struct net2280_ep *ep, unsigned count) } } -static inline void start_out_naking (struct net2280_ep *ep) +static inline void start_out_naking(struct net2280_ep *ep) { /* NOTE: hardware races lurk here, and PING protocol issues */ writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); /* synch with device */ - readl (&ep->regs->ep_rsp); + readl(&ep->regs->ep_rsp); } #ifdef DEBUG -static inline void assert_out_naking (struct net2280_ep *ep, const char *where) +static inline void assert_out_naking(struct net2280_ep *ep, const char *where) { - u32 tmp = readl (&ep->regs->ep_stat); + u32 tmp = readl(&ep->regs->ep_stat); if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) { - DEBUG (ep->dev, "%s %s %08x !NAK\n", + DEBUG(ep->dev, "%s %s %08x !NAK\n", ep->ep.name, where, tmp); writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); } } -#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep,__func__) +#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__) #else #define ASSERT_OUT_NAKING(ep) do {} while (0) #endif -static inline void stop_out_naking (struct net2280_ep *ep) +static inline void stop_out_naking(struct net2280_ep *ep) { u32 tmp; - tmp = readl (&ep->regs->ep_stat); + tmp = readl(&ep->regs->ep_stat); if ((tmp & BIT(NAK_OUT_PACKETS)) != 0) writel(BIT(CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); } From ae8e530a7e5d87592cb23996bee7fd6f1eb202ed Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:10 +0200 Subject: [PATCH 040/211] usb: gadget: net2280: Code Cleanup - Move logical continuations to end of line - Improve spacing Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 155 +++++++++++++++++------------------ drivers/usb/gadget/net2280.h | 4 +- 2 files changed, 78 insertions(+), 81 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d1d4f4fc9da7..d506c83d204a 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -100,9 +100,9 @@ static bool use_dma_chaining; static bool use_msi = true; /* "modprobe net2280 use_dma=n" etc */ -module_param(use_dma, bool, S_IRUGO); -module_param(use_dma_chaining, bool, S_IRUGO); -module_param(use_msi, bool, S_IRUGO); +module_param(use_dma, bool, 0444); +module_param(use_dma_chaining, bool, 0444); +module_param(use_msi, bool, 0444); /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable @@ -111,7 +111,7 @@ module_param(use_msi, bool, S_IRUGO); static ushort fifo_mode; /* "modprobe net2280 fifo_mode=1" etc */ -module_param (fifo_mode, ushort, 0644); +module_param(fifo_mode, ushort, 0644); /* enable_suspend -- When enabled, the driver will respond to * USB suspend requests by powering down the NET2280. Otherwise, @@ -121,7 +121,7 @@ module_param (fifo_mode, ushort, 0644); static bool enable_suspend; /* "modprobe net2280 enable_suspend=1" etc */ -module_param(enable_suspend, bool, S_IRUGO); +module_param(enable_suspend, bool, 0444); /* force full-speed operation */ static bool full_speed; @@ -169,8 +169,8 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) static const u32 ep_key[9] = { 1, 0, 1, 0, 1, 1, 0, 1, 0 }; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) + if (!_ep || !desc || ep->desc || _ep->name == ep0name || + desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; dev = ep->dev; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) @@ -220,9 +220,9 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); if (tmp == USB_ENDPOINT_XFER_INT) { /* erratum 0105 workaround prevents hs NYET */ - if (dev->chiprev == 0100 - && dev->gadget.speed == USB_SPEED_HIGH - && !(desc->bEndpointAddress & USB_DIR_IN)) + if (dev->chiprev == 0100 && + dev->gadget.speed == USB_SPEED_HIGH && + !(desc->bEndpointAddress & USB_DIR_IN)) writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); } else if (tmp == USB_ENDPOINT_XFER_BULK) { @@ -402,8 +402,8 @@ static void ep_reset_228x(struct net2280_regs __iomem *regs, BIT(DATA_PACKET_RECEIVED_INTERRUPT) | BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | - BIT(DATA_IN_TOKEN_INTERRUPT) - , &ep->regs->ep_stat); + BIT(DATA_IN_TOKEN_INTERRUPT), + &ep->regs->ep_stat); /* fifo size is handled separately */ } @@ -425,9 +425,9 @@ static void ep_reset_338x(struct net2280_regs __iomem *regs, writel(BIT(DMA_ABORT_DONE_INTERRUPT) | BIT(DMA_PAUSE_DONE_INTERRUPT) | BIT(DMA_SCATTER_GATHER_DONE_INTERRUPT) | - BIT(DMA_TRANSACTION_DONE_INTERRUPT) - /* | BIT(DMA_ABORT) */ - , &ep->dma->dmastat); + BIT(DMA_TRANSACTION_DONE_INTERRUPT), + /* | BIT(DMA_ABORT), */ + &ep->dma->dmastat); dmastat = readl(&ep->dma->dmastat); if (dmastat == 0x5002) { @@ -618,15 +618,15 @@ static void out_flush(struct net2280_ep *ep) statp = &ep->regs->ep_stat; writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | - BIT(DATA_PACKET_RECEIVED_INTERRUPT) - , statp); + BIT(DATA_PACKET_RECEIVED_INTERRUPT), + statp); writel(BIT(FIFO_FLUSH), statp); /* Make sure that stap is written */ mb(); tmp = readl(statp); - if (tmp & BIT(DATA_OUT_PING_TOKEN_INTERRUPT) + if (tmp & BIT(DATA_OUT_PING_TOKEN_INTERRUPT) && /* high speed did bulk NYET; fifo isn't filling */ - && ep->dev->gadget.speed == USB_SPEED_FULL) { + ep->dev->gadget.speed == USB_SPEED_FULL) { unsigned usec; usec = 50; /* 64 byte bulk/interrupt */ @@ -653,8 +653,8 @@ static int read_fifo(struct net2280_ep *ep, struct net2280_request *req) /* erratum 0106 ... packets coming in during fifo reads might * be incompletely rejected. not all cases have workarounds. */ - if (ep->dev->chiprev == 0x0100 - && ep->dev->gadget.speed == USB_SPEED_FULL) { + if (ep->dev->chiprev == 0x0100 && + ep->dev->gadget.speed == USB_SPEED_FULL) { udelay(1); tmp = readl(&ep->regs->ep_stat); if ((tmp & BIT(NAK_OUT_PACKETS))) @@ -726,8 +726,8 @@ static int read_fifo(struct net2280_ep *ep, struct net2280_request *req) (void) readl(&ep->regs->ep_rsp); } - return is_short || ((req->req.actual == req->req.length) - && !req->req.zero); + return is_short || ((req->req.actual == req->req.length) && + !req->req.zero); } /* fill out dma descriptor to match a given request */ @@ -744,8 +744,8 @@ static void fill_dma_desc(struct net2280_ep *ep, */ if (ep->is_in) dmacount |= BIT(DMA_DIRECTION); - if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) - || ep->dev->pdev->device != 0x2280) + if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || + ep->dev->pdev->device != 0x2280) dmacount |= BIT(END_OF_CHAIN); req->valid = valid; @@ -836,8 +836,8 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req) /* dma irq, faking scatterlist status */ req->td->dmacount = cpu_to_le32(req->req.length - tmp); - writel(BIT(DMA_DONE_INTERRUPT_ENABLE) - | tmp, &dma->dmacount); + writel(BIT(DMA_DONE_INTERRUPT_ENABLE) | tmp, + &dma->dmacount); req->td->dmadesc = 0; req->valid = 1; @@ -1120,8 +1120,8 @@ static void scan_dma_completions(struct net2280_ep *ep) /* single transfer mode */ dma_done(ep, req, tmp, 0); break; - } else if (!ep->is_in - && (req->req.length % ep->ep.maxpacket) != 0) { + } else if (!ep->is_in && + (req->req.length % ep->ep.maxpacket) != 0) { tmp = readl(&ep->regs->ep_stat); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) return dma_done(ep, req, tmp, 0); @@ -1317,8 +1317,8 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) writel(le32_to_cpu(req->td->dmadesc), &ep->dma->dmadesc); if (req->td->dmacount & dma_done_ie) - writel(readl(&ep->dma->dmacount) - | le32_to_cpu(dma_done_ie), + writel(readl(&ep->dma->dmacount) | + le32_to_cpu(dma_done_ie), &ep->dma->dmacount); } else { struct net2280_request *prev; @@ -2255,8 +2255,8 @@ static void ep0_start_228x(struct net2280 *dev) { writel(BIT(CLEAR_EP_HIDE_STATUS_PHASE) | BIT(CLEAR_NAK_OUT_PACKETS) | - BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - , &dev->epregs[0].ep_rsp); + BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE), + &dev->epregs[0].ep_rsp); /* * hardware optionally handles a bunch of standard requests @@ -2268,8 +2268,8 @@ static void ep0_start_228x(struct net2280 *dev) BIT(SET_ADDRESS) | BIT(DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP) | BIT(GET_DEVICE_STATUS) | - BIT(GET_INTERFACE_STATUS) - , &dev->usb->stdrsp); + BIT(GET_INTERFACE_STATUS), + &dev->usb->stdrsp); writel(BIT(USB_ROOT_PORT_WAKEUP_ENABLE) | BIT(SELF_POWERED_USB_DEVICE) | BIT(REMOTE_WAKEUP_SUPPORT) | @@ -2330,8 +2330,8 @@ static void ep0_start_338x(struct net2280 *dev) /* enable irqs so we can see ep0 and general operation */ writel(BIT(SETUP_PACKET_INTERRUPT_ENABLE) | - BIT(ENDPOINT_0_INTERRUPT_ENABLE) - , &dev->regs->pciirqenb0); + BIT(ENDPOINT_0_INTERRUPT_ENABLE), + &dev->regs->pciirqenb0); writel(BIT(PCI_INTERRUPT_ENABLE) | BIT(ROOT_PORT_RESET_INTERRUPT_ENABLE) | BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE) | @@ -2366,8 +2366,8 @@ static int net2280_start(struct usb_gadget *_gadget, * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) * "must not be used in normal operation" */ - if (!driver || driver->max_speed < USB_SPEED_HIGH - || !driver->setup) + if (!driver || driver->max_speed < USB_SPEED_HIGH || + !driver->setup) return -EINVAL; dev = container_of(_gadget, struct net2280, gadget); @@ -2542,10 +2542,10 @@ static void handle_ep_small(struct net2280_ep *ep) } mode = 2; /* an extra OUT token is an error */ - } else if (((t & BIT(DATA_OUT_PING_TOKEN_INTERRUPT)) - && req - && req->req.actual == req->req.length) - || (ep->responded && !req)) { + } else if (((t & BIT(DATA_OUT_PING_TOKEN_INTERRUPT)) && + req && + req->req.actual == req->req.length) || + (ep->responded && !req)) { ep->dev->protocol_stall = 1; set_halt(ep); ep->stopped = 1; @@ -2576,8 +2576,8 @@ static void handle_ep_small(struct net2280_ep *ep) * dma handles (M >= N), may empty the queue */ scan_dma_completions(ep); - if (unlikely(list_empty(&ep->queue) - || ep->out_overflow)) { + if (unlikely(list_empty(&ep->queue) || + ep->out_overflow)) { req = NULL; break; } @@ -2611,10 +2611,10 @@ static void handle_ep_small(struct net2280_ep *ep) } /* also flush to prevent erratum 0106 trouble */ - if (unlikely(ep->out_overflow - || (ep->dev->chiprev == 0x0100 - && ep->dev->gadget.speed - == USB_SPEED_FULL))) { + if (unlikely(ep->out_overflow || + (ep->dev->chiprev == 0x0100 && + ep->dev->gadget.speed + == USB_SPEED_FULL))) { out_flush(ep); ep->out_overflow = 0; } @@ -2808,9 +2808,9 @@ static void ep_stall(struct net2280_ep *ep, int stall) val = readl(&ep->regs->ep_rsp); val |= BIT(CLEAR_ENDPOINT_HALT) | BIT(CLEAR_ENDPOINT_TOGGLE); - writel(val - /* | BIT(CLEAR_NAK_PACKETS)*/ - , &ep->regs->ep_rsp); + writel(val, + /* | BIT(CLEAR_NAK_PACKETS),*/ + &ep->regs->ep_rsp); ep->is_halt = 0; val = readl(&ep->regs->ep_rsp); } @@ -3125,8 +3125,8 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) BIT(DATA_PACKET_RECEIVED_INTERRUPT) | BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | - BIT(DATA_IN_TOKEN_INTERRUPT) - , &ep->regs->ep_stat); + BIT(DATA_IN_TOKEN_INTERRUPT), + &ep->regs->ep_stat); } u.raw[0] = readl(&dev->usb->setup0123); u.raw[1] = readl(&dev->usb->setup4567); @@ -3206,8 +3206,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (w_value != USB_ENDPOINT_HALT - || w_length != 0) + if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; e = get_ep_by_addr(dev, w_index); if (!e) @@ -3233,8 +3232,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (w_value != USB_ENDPOINT_HALT - || w_length != 0) + if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; e = get_ep_by_addr(dev, w_index); if (!e) @@ -3326,12 +3324,11 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) */ if (stat & tmp) { writel(tmp, &dev->regs->irqstat1); - if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) - && ((readl(&dev->usb->usbstat) & mask) - == 0)) - || ((readl(&dev->usb->usbctl) - & BIT(VBUS_PIN)) == 0) - ) && (dev->gadget.speed != USB_SPEED_UNKNOWN)) { + if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) && + (readl(&dev->usb->usbstat) & mask)) || + ((readl(&dev->usb->usbctl) & + BIT(VBUS_PIN)) == 0)) && + (dev->gadget.speed != USB_SPEED_UNKNOWN)) { DEBUG(dev, "disconnect %s\n", dev->driver->driver.name); stop_activity(dev, dev->driver); @@ -3560,7 +3557,7 @@ static void net2280_remove(struct pci_dev *pdev) pci_disable_device(pdev); device_remove_file(&pdev->dev, &dev_attr_registers); - INFO (dev, "unbind\n"); + INFO(dev, "unbind\n"); } /* wrap this driver around the specified device, but @@ -3783,29 +3780,29 @@ static const struct pci_device_id pci_ids[] = { { .device = 0x2280, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, -}, { + }, { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, .vendor = PCI_VENDOR_ID_PLX_LEGACY, .device = 0x2282, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, -}, + }, { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_PLX, - .device = 0x3380, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_PLX, + .device = 0x3380, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_PLX, - .device = 0x3382, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_PLX, + .device = 0x3382, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index f019d6c74fc3..77c39d9f6d8a 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -117,8 +117,8 @@ static inline void allow_status(struct net2280_ep *ep) /* ep0 only */ writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) | BIT(CLEAR_NAK_OUT_PACKETS) | - BIT(CLEAR_NAK_OUT_PACKETS_MODE) - , &ep->regs->ep_rsp); + BIT(CLEAR_NAK_OUT_PACKETS_MODE), + &ep->regs->ep_rsp); ep->stopped = 1; } From e56e69cc0ff4905914695f20c927aa71597be94c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:11 +0200 Subject: [PATCH 041/211] usb: gadget: net2280: Use pr_* function Driver was using custom functions WARNING, ERROR, DEBUG, instead of pr_err, pr_dgb... New ep_* macros have been created that use standard pr_* functions. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 121 +++++++++++++++++------------------ drivers/usb/gadget/net2280.h | 36 ++++------- 2 files changed, 71 insertions(+), 86 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d506c83d204a..9ced9ff901e9 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -42,9 +42,6 @@ * (at your option) any later version. */ -#undef DEBUG /* messages on error and most fault paths */ -#undef VERBOSE /* extra debug messages (success too) */ - #include #include #include @@ -210,7 +207,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) * use it instead of troublesome (non-bulk) multi-packet DMA. */ if (ep->dma && (max % 4) != 0 && use_dma_chaining) { - DEBUG(ep->dev, "%s, no dma for maxpacket %d\n", + ep_dbg(ep->dev, "%s, no dma for maxpacket %d\n", ep->ep.name, ep->ep.maxpacket); ep->dma = NULL; } @@ -303,7 +300,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } tmp = desc->bEndpointAddress; - DEBUG(dev, "enabled %s (ep%d%s-%s) %s max %04x\n", + ep_dbg(dev, "enabled %s (ep%d%s-%s) %s max %04x\n", _ep->name, tmp & 0x0f, DIR_STRING(tmp), type_string(desc->bmAttributes), ep->dma ? "dma" : "pio", max); @@ -431,7 +428,7 @@ static void ep_reset_338x(struct net2280_regs __iomem *regs, dmastat = readl(&ep->dma->dmastat); if (dmastat == 0x5002) { - WARNING(ep->dev, "The dmastat return = %x!!\n", + ep_warn(ep->dev, "The dmastat return = %x!!\n", dmastat); writel(0x5a, &ep->dma->dmastat); } @@ -476,7 +473,7 @@ static int net2280_disable(struct usb_ep *_ep) else ep_reset_228x(ep->dev->regs, ep); - VDEBUG(ep->dev, "disabled %s %s\n", + ep_vdbg(ep->dev, "disabled %s %s\n", ep->dma ? "dma" : "pio", _ep->name); /* synch memory views with the device */ @@ -572,7 +569,7 @@ static void write_fifo(struct net2280_ep *ep, struct usb_request *req) if (count > total) /* min() cannot be used on a bitfield */ count = total; - VDEBUG(ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", + ep_vdbg(ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", ep->ep.name, count, (count != ep->ep.maxpacket) ? " (short)" : "", req); @@ -684,7 +681,7 @@ static int read_fifo(struct net2280_ep *ep, struct net2280_request *req) if (count > tmp) { /* as with DMA, data overflow gets flushed */ if ((tmp % ep->ep.maxpacket) != 0) { - ERROR(ep->dev, + ep_err(ep->dev, "%s out fifo %d bytes, expected %d\n", ep->ep.name, count, tmp); req->req.status = -EOVERFLOW; @@ -699,7 +696,7 @@ static int read_fifo(struct net2280_ep *ep, struct net2280_request *req) is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0); - VDEBUG(ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n", + ep_vdbg(ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n", ep->ep.name, count, is_short ? " (short)" : "", cleanup ? " flush" : "", prevent ? " nak" : "", req, req->req.actual, req->req.length); @@ -925,7 +922,7 @@ done(struct net2280_ep *ep, struct net2280_request *req, int status) usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in); if (status && status != -ESHUTDOWN) - VDEBUG(dev, "complete %s req %p stat %d len %u/%u\n", + ep_vdbg(dev, "complete %s req %p stat %d len %u/%u\n", ep->ep.name, &req->req, status, req->req.actual, req->req.length); @@ -978,7 +975,7 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } #if 0 - VDEBUG(dev, "%s queue req %p, len %d buf %p\n", + ep_vdbg(dev, "%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, _req->buf); #endif @@ -1012,7 +1009,7 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) if (ep->num == 0 && _req->length == 0) { allow_status(ep); done(ep, req, 0); - VDEBUG(dev, "%s status ack\n", ep->ep.name); + ep_vdbg(dev, "%s status ack\n", ep->ep.name); goto done; } @@ -1131,7 +1128,7 @@ static void scan_dma_completions(struct net2280_ep *ep) * 0122, and 0124; not all cases trigger the warning. */ if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) { - WARNING(ep->dev, "%s lost packet sync!\n", + ep_warn(ep->dev, "%s lost packet sync!\n", ep->ep.name); req->req.status = -EOVERFLOW; } else { @@ -1139,7 +1136,7 @@ static void scan_dma_completions(struct net2280_ep *ep) if (tmp) { /* fifo gets flushed later */ ep->out_overflow = 1; - DEBUG(ep->dev, + ep_dbg(ep->dev, "%s dma, discard %d len %d\n", ep->ep.name, tmp, req->req.length); @@ -1175,7 +1172,7 @@ static void restart_dma(struct net2280_ep *ep) struct net2280_request *entry, *prev = NULL; int reqmode, done = 0; - DEBUG(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); + ep_dbg(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); ep->in_fifo_validate = likely(req->req.zero || (req->req.length % ep->ep.maxpacket) != 0); if (ep->in_fifo_validate) @@ -1295,7 +1292,7 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* queue head may be partially complete. */ if (ep->queue.next == &req->queue) { if (ep->dma) { - DEBUG(ep->dev, "unlink (%s) dma\n", _ep->name); + ep_dbg(ep->dev, "unlink (%s) dma\n", _ep->name); _req->status = -ECONNRESET; abort_dma(ep); if (likely(ep->queue.next == &req->queue)) { @@ -1306,7 +1303,7 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req) -ECONNRESET); } } else { - DEBUG(ep->dev, "unlink (%s) pio\n", _ep->name); + ep_dbg(ep->dev, "unlink (%s) pio\n", _ep->name); done(ep, req, -ECONNRESET); } req = NULL; @@ -1379,7 +1376,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) else if (ep->is_in && value && net2280_fifo_status(_ep) != 0) retval = -EAGAIN; else { - VDEBUG(ep->dev, "%s %s %s\n", _ep->name, + ep_vdbg(ep->dev, "%s %s %s\n", _ep->name, value ? "set" : "clear", wedged ? "wedge" : "halt"); /* set/clear, then synch memory views with the device */ @@ -1566,7 +1563,7 @@ static const struct usb_gadget_ops net2280_ops = { /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_GADGET_DEBUG_FILES +#ifdef CONFIG_USB_GADGET_PDEBUG_FILES /* FIXME move these into procfs, and use seq_file. * Sysfs _still_ doesn't behave for arbitrarily sized files, @@ -1928,8 +1925,8 @@ static void defect7374_enable_data_eps_zero(struct net2280 *dev) /*See if firmware needs to set up for workaround*/ if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) { - WARNING(dev, "Operate Defect 7374 workaround soft this time"); - WARNING(dev, "It will operate on cold-reboot and SS connect"); + ep_warn(dev, "Operate Defect 7374 workaround soft this time"); + ep_warn(dev, "It will operate on cold-reboot and SS connect"); /*GPEPs:*/ tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) | @@ -1985,8 +1982,8 @@ static void defect7374_enable_data_eps_zero(struct net2280 *dev) set_idx_reg(dev->regs, SCRATCH, scratch); } else{ - WARNING(dev, "Defect 7374 workaround soft will NOT operate"); - WARNING(dev, "It will operate on cold-reboot and SS connect"); + ep_warn(dev, "Defect 7374 workaround soft will NOT operate"); + ep_warn(dev, "It will operate on cold-reboot and SS connect"); } } @@ -2050,7 +2047,7 @@ static void usb_reset_338x(struct net2280 *dev) /* See if firmware needs to set up for workaround: */ if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) { - INFO(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__, + ep_info(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__, fsmvalue); } else { /* disable automatic responses, and irqs */ @@ -2187,7 +2184,7 @@ static void usb_reinit_338x(struct net2280 *dev) /* See if driver needs to set up for workaround: */ if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) - INFO(dev, "%s: Defect 7374 FsmValue %08x\n", + ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__, fsmvalue); else { tmp = readl(&dev->usb_ext->usbctl2) & @@ -2302,7 +2299,7 @@ static void ep0_start_338x(struct net2280 *dev) (0xf << DEFECT7374_FSM_FIELD); if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) - INFO(dev, "%s: Defect 7374 FsmValue %08x\n", __func__, + ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__, fsmvalue); else writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) | @@ -2401,7 +2398,7 @@ static int net2280_start(struct usb_gadget *_gadget, ep0_start(dev); - DEBUG(dev, "%s ready, usbctl %08x stdrsp %08x\n", + ep_dbg(dev, "%s ready, usbctl %08x stdrsp %08x\n", driver->driver.name, readl(&dev->usb->usbctl), readl(&dev->usb->stdrsp)); @@ -2464,7 +2461,7 @@ static int net2280_stop(struct usb_gadget *_gadget, device_remove_file(&dev->pdev->dev, &dev_attr_function); device_remove_file(&dev->pdev->dev, &dev_attr_queues); - DEBUG(dev, "unregistered driver '%s'\n", + ep_dbg(dev, "unregistered driver '%s'\n", driver ? driver->driver.name : ""); return 0; @@ -2493,7 +2490,7 @@ static void handle_ep_small(struct net2280_ep *ep) t = readl(&ep->regs->ep_stat); ep->irqs++; #if 0 - VDEBUG(ep->dev, "%s ack ep_stat %08x, req %p\n", + ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n", ep->ep.name, t, req ? &req->req : 0); #endif if (!ep->is_in || ep->dev->pdev->device == 0x2280) @@ -2624,7 +2621,7 @@ static void handle_ep_small(struct net2280_ep *ep) if (!list_empty(&ep->queue)) restart_dma(ep); } else - DEBUG(ep->dev, "%s dma ep_stat %08x ??\n", + ep_dbg(ep->dev, "%s dma ep_stat %08x ??\n", ep->ep.name, t); return; @@ -2758,12 +2755,12 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r) if (ack_wait_timeout >= DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS) { - ERROR(dev, "FAIL: Defect 7374 workaround waited but failed " + ep_err(dev, "FAIL: Defect 7374 workaround waited but failed " "to detect SS host's data phase ACK."); - ERROR(dev, "PL_EP_STATUS_1(23:16):.Expected from 0x11 to 0x16" + ep_err(dev, "PL_EP_STATUS_1(23:16):.Expected from 0x11 to 0x16" "got 0x%2.2x.\n", state >> STATE); } else { - WARNING(dev, "INFO: Defect 7374 workaround waited about\n" + ep_warn(dev, "INFO: Defect 7374 workaround waited about\n" "%duSec for Control Read Data Phase ACK\n", DEFECT_7374_PROCESSOR_WAIT_TIME * ack_wait_timeout); } @@ -2953,7 +2950,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, goto do_stall3; if (w_value != USB_ENDPOINT_HALT) goto do_stall3; - VDEBUG(dev, "%s clear halt\n", e->ep.name); + ep_vdbg(dev, "%s clear halt\n", e->ep.name); ep_stall(e, false); if (!list_empty(&e->queue) && e->td_dma) restart_dma(e); @@ -3024,7 +3021,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, default: usb3_delegate: - VDEBUG(dev, "setup %02x.%02x v%04x i%04x l%04x ep_cfg %08x\n", + ep_vdbg(dev, "setup %02x.%02x v%04x i%04x l%04x ep_cfg %08x\n", r.bRequestType, r.bRequest, w_value, w_index, w_length, readl(&ep->cfg->ep_cfg)); @@ -3036,7 +3033,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, } do_stall3: if (tmp < 0) { - VDEBUG(dev, "req %02x.%02x protocol STALL; stat %d\n", + ep_vdbg(dev, "req %02x.%02x protocol STALL; stat %d\n", r.bRequestType, r.bRequest, tmp); dev->protocol_stall = 1; /* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */ @@ -3061,7 +3058,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) stat &= ~BIT(INTA_ASSERTED); if (!stat) return; - /* DEBUG(dev, "irqstat0 %04x\n", stat); */ + /* ep_dbg(dev, "irqstat0 %04x\n", stat); */ /* starting a control request? */ if (unlikely(stat & BIT(SETUP_PACKET_INTERRUPT))) { @@ -3088,7 +3085,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) EP0_HS_MAX_PACKET_SIZE); } net2280_led_speed(dev, dev->gadget.speed); - DEBUG(dev, "%s\n", + ep_dbg(dev, "%s\n", usb_speed_string(dev->gadget.speed)); } @@ -3196,7 +3193,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) set_fifo_bytecount(ep, w_length); writel((__force u32)status, &dev->epregs[0].ep_data); allow_status(ep); - VDEBUG(dev, "%s stat %02x\n", ep->ep.name, status); + ep_vdbg(dev, "%s stat %02x\n", ep->ep.name, status); goto next_endpoints; } break; @@ -3212,10 +3209,10 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) if (!e) goto do_stall; if (e->wedged) { - VDEBUG(dev, "%s wedged, halt not cleared\n", + ep_vdbg(dev, "%s wedged, halt not cleared\n", ep->ep.name); } else { - VDEBUG(dev, "%s clear halt\n", e->ep.name); + ep_vdbg(dev, "%s clear halt\n", e->ep.name); clear_halt(e); if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX && @@ -3243,13 +3240,13 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) if (dev->pdev->vendor == PCI_VENDOR_ID_PLX && e->dma) abort_dma(e); allow_status(ep); - VDEBUG(dev, "%s set halt\n", ep->ep.name); + ep_vdbg(dev, "%s set halt\n", ep->ep.name); goto next_endpoints; } break; default: delegate: - VDEBUG(dev, "setup %02x.%02x v%04x i%04x l%04x " + ep_vdbg(dev, "setup %02x.%02x v%04x i%04x l%04x " "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, w_value, w_index, w_length, @@ -3263,7 +3260,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) /* stall ep0 on error */ if (tmp < 0) { do_stall: - VDEBUG(dev, "req %02x.%02x protocol STALL; stat %d\n", + ep_vdbg(dev, "req %02x.%02x protocol STALL; stat %d\n", u.r.bRequestType, u.r.bRequest, tmp); dev->protocol_stall = 1; } @@ -3296,7 +3293,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) } if (stat) - DEBUG(dev, "unhandled irqstat0 %08x\n", stat); + ep_dbg(dev, "unhandled irqstat0 %08x\n", stat); } #define DMA_INTERRUPTS (BIT(DMA_D_INTERRUPT) | \ @@ -3329,7 +3326,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) ((readl(&dev->usb->usbctl) & BIT(VBUS_PIN)) == 0)) && (dev->gadget.speed != USB_SPEED_UNKNOWN)) { - DEBUG(dev, "disconnect %s\n", + ep_dbg(dev, "disconnect %s\n", dev->driver->driver.name); stop_activity(dev, dev->driver); ep0_start(dev); @@ -3381,7 +3378,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) if (!stat) return; - /* DEBUG(dev, "irqstat1 %08x\n", stat);*/ + /* ep_dbg(dev, "irqstat1 %08x\n", stat);*/ /* DMA status, for ep-{a,b,c,d} */ scratch = stat & DMA_INTERRUPTS; @@ -3418,7 +3415,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) */ if (!use_dma_chaining) { if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) { - DEBUG(ep->dev, "%s no xact done? %08x\n", + ep_dbg(ep->dev, "%s no xact done? %08x\n", ep->ep.name, tmp); continue; } @@ -3470,7 +3467,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) * if they appear very often, here's where to try recovering. */ if (stat & PCI_ERROR_INTERRUPTS) { - ERROR(dev, "pci dma error; stat %08x\n", stat); + ep_err(dev, "pci dma error; stat %08x\n", stat); stat &= ~PCI_ERROR_INTERRUPTS; /* these are fatal errors, but "maybe" they won't * happen again ... @@ -3481,7 +3478,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) } if (stat) - DEBUG(dev, "unhandled irqstat1 %08x\n", stat); + ep_dbg(dev, "unhandled irqstat1 %08x\n", stat); } static irqreturn_t net2280_irq(int irq, void *_dev) @@ -3557,7 +3554,7 @@ static void net2280_remove(struct pci_dev *pdev) pci_disable_device(pdev); device_remove_file(&pdev->dev, &dev_attr_registers); - INFO(dev, "unbind\n"); + ep_info(dev, "unbind\n"); } /* wrap this driver around the specified device, but @@ -3605,7 +3602,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) resource = pci_resource_start(pdev, 0); len = pci_resource_len(pdev, 0); if (!request_mem_region(resource, len, driver_name)) { - DEBUG(dev, "controller already in use\n"); + ep_dbg(dev, "controller already in use\n"); retval = -EBUSY; goto done; } @@ -3617,7 +3614,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) base = ioremap_nocache(resource, len); if (base == NULL) { - DEBUG(dev, "can't map memory\n"); + ep_dbg(dev, "can't map memory\n"); retval = -EFAULT; goto done; } @@ -3666,18 +3663,18 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* irq setup after old hardware is cleaned up */ if (!pdev->irq) { - ERROR(dev, "No IRQ. Check PCI setup!\n"); + ep_err(dev, "No IRQ. Check PCI setup!\n"); retval = -ENODEV; goto done; } if (use_msi && dev->pdev->vendor == PCI_VENDOR_ID_PLX) if (pci_enable_msi(pdev)) - ERROR(dev, "Failed to enable MSI mode\n"); + ep_err(dev, "Failed to enable MSI mode\n"); if (request_irq(pdev->irq, net2280_irq, IRQF_SHARED, driver_name, dev)) { - ERROR(dev, "request interrupt %d failed\n", pdev->irq); + ep_err(dev, "request interrupt %d failed\n", pdev->irq); retval = -EBUSY; goto done; } @@ -3690,7 +3687,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) 0 /* no alignment requirements */, 0 /* or page-crossing issues */); if (!dev->requests) { - DEBUG(dev, "can't get request pool\n"); + ep_dbg(dev, "can't get request pool\n"); retval = -ENOMEM; goto done; } @@ -3700,7 +3697,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) td = pci_pool_alloc(dev->requests, GFP_KERNEL, &dev->ep[i].td_dma); if (!td) { - DEBUG(dev, "can't get dummy %d\n", i); + ep_dbg(dev, "can't get dummy %d\n", i); retval = -ENOMEM; goto done; } @@ -3727,10 +3724,10 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->chiprev = get_idx_reg(dev->regs, REG_CHIPREV) & 0xffff; /* done */ - INFO(dev, "%s\n", driver_desc); - INFO(dev, "irq %d, pci mem %p, chip rev %04x\n", + ep_info(dev, "%s\n", driver_desc); + ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n", pdev->irq, base, dev->chiprev); - INFO(dev, "version: " DRIVER_VERSION "; dma %s %s\n", + ep_info(dev, "version: " DRIVER_VERSION "; dma %s %s\n", use_dma ? (use_dma_chaining ? "chaining" : "enabled") : "disabled", dev->enhanced_mode ? "enhanced mode" : "legacy mode"); diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index 77c39d9f6d8a..dc9ca1d5dc8e 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -314,32 +314,20 @@ static inline void net2280_led_shutdown(struct net2280 *dev) /*-------------------------------------------------------------------------*/ -#define xprintk(dev, level, fmt, args...) \ - printk(level "%s %s: " fmt, driver_name, \ - pci_name(dev->pdev), ## args) +#define ep_dbg(ndev, fmt, args...) \ + dev_dbg((&((ndev)->pdev->dev)), fmt, ##args) -#ifdef DEBUG -#undef DEBUG -#define DEBUG(dev, fmt, args...) \ - xprintk(dev, KERN_DEBUG, fmt, ## args) -#else -#define DEBUG(dev, fmt, args...) \ - do { } while (0) -#endif /* DEBUG*/ +#define ep_vdbg(ndev, fmt, args...) \ + dev_vdbg((&((ndev)->pdev->dev)), fmt, ##args) -#ifdef VERBOSE -#define VDEBUG DEBUG -#else -#define VDEBUG(dev, fmt, args...) \ - do { } while (0) -#endif /* VERBOSE */ +#define ep_info(ndev, fmt, args...) \ + dev_info((&((ndev)->pdev->dev)), fmt, ##args) -#define ERROR(dev, fmt, args...) \ - xprintk(dev, KERN_ERR, fmt, ## args) -#define WARNING(dev, fmt, args...) \ - xprintk(dev, KERN_WARNING, fmt, ## args) -#define INFO(dev, fmt, args...) \ - xprintk(dev, KERN_INFO, fmt, ## args) +#define ep_warn(ndev, fmt, args...) \ + dev_warn((&((ndev)->pdev->dev)), fmt, ##args) + +#define ep_err(ndev, fmt, args...) \ + dev_err((&((ndev)->pdev->dev)), fmt, ##args) /*-------------------------------------------------------------------------*/ @@ -368,7 +356,7 @@ static inline void assert_out_naking(struct net2280_ep *ep, const char *where) u32 tmp = readl(&ep->regs->ep_stat); if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) { - DEBUG(ep->dev, "%s %s %08x !NAK\n", + ep_dbg(ep->dev, "%s %s %08x !NAK\n", ep->ep.name, where, tmp); writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); From 2eeb0016c1242f275f9ebacc687ab639689f8bad Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 20 May 2014 18:30:12 +0200 Subject: [PATCH 042/211] usb: gadget: net2280: Use quirks instead of pci id Use of quirks improve readability and will be easier to add new devices to this driver. Suggested-by: Alan Stern Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 83 +++++++++++++++++++----------------- drivers/usb/gadget/net2280.h | 6 +++ 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 9ced9ff901e9..ce8bc8644c59 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -147,7 +147,7 @@ static inline void enable_pciirqenb(struct net2280_ep *ep) { u32 tmp = readl(&ep->dev->regs->pciirqenb0); - if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (ep->dev->quirks & PLX_LEGACY) tmp |= BIT(ep->num); else tmp |= BIT(ep_bit[ep->num]); @@ -177,7 +177,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) return -EDOM; - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { + if (dev->quirks & PLX_SUPERSPEED) { if ((desc->bEndpointAddress & 0x0f) >= 0x0c) return -EDOM; ep->is_in = !!usb_endpoint_dir_in(desc); @@ -187,8 +187,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* sanity check ep-e/ep-f since their fifos are small */ max = usb_endpoint_maxp(desc) & 0x1fff; - if (ep->num > 4 && max > 64 && - (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY)) + if (ep->num > 4 && max > 64 && (dev->quirks & PLX_LEGACY)) return -ERANGE; spin_lock_irqsave(&dev->lock, flags); @@ -233,7 +232,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); /* Enable this endpoint */ - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) { + if (dev->quirks & PLX_LEGACY) { tmp <<= ENDPOINT_TYPE; tmp |= desc->bEndpointAddress; /* default full fifo lines */ @@ -263,7 +262,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* for OUT transfers, block the rx fifo until a read is posted */ if (!ep->is_in) writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); - else if (dev->pdev->device != 0x2280) { + else if (!(dev->quirks & PLX_2280)) { /* Added for 2282, Don't use nak packets on an in endpoint, * this was ignored on 2280 */ @@ -279,7 +278,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) tmp = BIT(DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) | BIT(DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); - if (dev->pdev->device == 0x2280) + if (dev->quirks & PLX_2280) tmp |= readl(&ep->regs->ep_irqenb); writel(tmp, &ep->regs->ep_irqenb); } else { /* dma, per-request */ @@ -361,7 +360,7 @@ static void ep_reset_228x(struct net2280_regs __iomem *regs, /* init to our chosen defaults, notably so that we NAK OUT * packets until the driver queues a read (+note erratum 0112) */ - if (!ep->is_in || ep->dev->pdev->device == 0x2280) { + if (!ep->is_in || (ep->dev->quirks & PLX_2280)) { tmp = BIT(SET_NAK_OUT_PACKETS_MODE) | BIT(SET_NAK_OUT_PACKETS) | BIT(CLEAR_EP_HIDE_STATUS_PHASE) | @@ -381,7 +380,7 @@ static void ep_reset_228x(struct net2280_regs __iomem *regs, writel(tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ - if (ep->dev->pdev->device == 0x2280) + if (ep->dev->quirks & PLX_2280) tmp = BIT(FIFO_OVERFLOW) | BIT(FIFO_UNDERFLOW); else @@ -468,7 +467,7 @@ static int net2280_disable(struct usb_ep *_ep) spin_lock_irqsave(&ep->dev->lock, flags); nuke(ep); - if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (ep->dev->quirks & PLX_SUPERSPEED) ep_reset_338x(ep->dev->regs, ep); else ep_reset_228x(ep->dev->regs, ep); @@ -742,7 +741,7 @@ static void fill_dma_desc(struct net2280_ep *ep, if (ep->is_in) dmacount |= BIT(DMA_DIRECTION); if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || - ep->dev->pdev->device != 0x2280) + !(ep->dev->quirks & PLX_2280)) dmacount |= BIT(END_OF_CHAIN); req->valid = valid; @@ -786,14 +785,14 @@ static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma) struct net2280_dma_regs __iomem *dma = ep->dma; unsigned int tmp = BIT(VALID_BIT) | (ep->is_in << DMA_DIRECTION); - if (ep->dev->pdev->device != 0x2280) + if (!(ep->dev->quirks & PLX_2280)) tmp |= BIT(END_OF_CHAIN); writel(tmp, &dma->dmacount); writel(readl(&dma->dmastat), &dma->dmastat); writel(td_dma, &dma->dmadesc); - if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (ep->dev->quirks & PLX_SUPERSPEED) dmactl |= BIT(DMA_REQUEST_OUTSTANDING); writel(dmactl, &dma->dmactl); @@ -989,7 +988,7 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* DMA request while EP halted */ if (ep->dma && (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) && - (dev->pdev->vendor == PCI_VENDOR_ID_PLX)) { + (dev->quirks & PLX_SUPERSPEED)) { int valid = 1; if (ep->is_in) { int expect; @@ -1120,7 +1119,7 @@ static void scan_dma_completions(struct net2280_ep *ep) } else if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { tmp = readl(&ep->regs->ep_stat); - if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (ep->dev->quirks & PLX_SUPERSPEED) return dma_done(ep, req, tmp, 0); /* AVOID TROUBLE HERE by not issuing short reads from @@ -1231,7 +1230,7 @@ static void abort_dma_338x(struct net2280_ep *ep) static void abort_dma(struct net2280_ep *ep) { - if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (ep->dev->quirks & PLX_LEGACY) return abort_dma_228x(ep); return abort_dma_338x(ep); } @@ -1389,7 +1388,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) ep->wedged = 1; } else { clear_halt(ep); - if (ep->dev->pdev->vendor == PCI_VENDOR_ID_PLX && + if (ep->dev->quirks & PLX_SUPERSPEED && !list_empty(&ep->queue) && ep->td_dma) restart_dma(ep); ep->wedged = 0; @@ -2087,7 +2086,7 @@ static void usb_reset_338x(struct net2280 *dev) static void usb_reset(struct net2280 *dev) { - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (dev->quirks & PLX_LEGACY) return usb_reset_228x(dev); return usb_reset_338x(dev); } @@ -2243,7 +2242,7 @@ static void usb_reinit_338x(struct net2280 *dev) static void usb_reinit(struct net2280 *dev) { - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (dev->quirks & PLX_LEGACY) return usb_reinit_228x(dev); return usb_reinit_338x(dev); } @@ -2341,7 +2340,7 @@ static void ep0_start_338x(struct net2280 *dev) static void ep0_start(struct net2280 *dev) { - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (dev->quirks & PLX_LEGACY) return ep0_start_228x(dev); return ep0_start_338x(dev); } @@ -2385,7 +2384,7 @@ static int net2280_start(struct usb_gadget *_gadget, goto err_func; /* Enable force-full-speed testing mode, if desired */ - if (full_speed && dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (full_speed && (dev->quirks & PLX_LEGACY)) writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag); /* ... then enable host detection and ep0; and we're ready @@ -2393,7 +2392,7 @@ static int net2280_start(struct usb_gadget *_gadget, */ net2280_led_active(dev, 1); - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (dev->quirks & PLX_SUPERSPEED) defect7374_enable_data_eps_zero(dev); ep0_start(dev); @@ -2455,7 +2454,7 @@ static int net2280_stop(struct usb_gadget *_gadget, net2280_led_active(dev, 0); /* Disable full-speed test mode */ - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (dev->quirks & PLX_LEGACY) writel(0, &dev->usb->xcvrdiag); device_remove_file(&dev->pdev->dev, &dev_attr_function); @@ -2493,7 +2492,7 @@ static void handle_ep_small(struct net2280_ep *ep) ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n", ep->ep.name, t, req ? &req->req : 0); #endif - if (!ep->is_in || ep->dev->pdev->device == 0x2280) + if (!ep->is_in || (ep->dev->quirks & PLX_2280)) writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat); else /* Added for 2282 */ @@ -3102,10 +3101,10 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) } ep->stopped = 0; dev->protocol_stall = 0; - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (dev->quirks & PLX_SUPERSPEED) ep->is_halt = 0; else{ - if (ep->dev->pdev->device == 0x2280) + if (ep->dev->quirks & PLX_2280) tmp = BIT(FIFO_OVERFLOW) | BIT(FIFO_UNDERFLOW); else @@ -3131,7 +3130,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) cpu_to_le32s(&u.raw[0]); cpu_to_le32s(&u.raw[1]); - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (dev->quirks & PLX_SUPERSPEED) defect7374_workaround(dev, u.r); tmp = 0; @@ -3214,8 +3213,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) } else { ep_vdbg(dev, "%s clear halt\n", e->ep.name); clear_halt(e); - if (ep->dev->pdev->vendor == - PCI_VENDOR_ID_PLX && + if ((ep->dev->quirks & PLX_SUPERSPEED) && !list_empty(&e->queue) && e->td_dma) restart_dma(e); } @@ -3237,7 +3235,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) if (e->ep.name == ep0name) goto do_stall; set_halt(e); - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX && e->dma) + if ((dev->quirks & PLX_SUPERSPEED) && e->dma) abort_dma(e); allow_status(ep); ep_vdbg(dev, "%s set halt\n", ep->ep.name); @@ -3365,7 +3363,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) writel(stat, &dev->regs->irqstat1); /* some status we can just ignore */ - if (dev->pdev->device == 0x2280) + if (dev->quirks & PLX_2280) stat &= ~(BIT(CONTROL_STATUS_INTERRUPT) | BIT(SUSPEND_REQUEST_INTERRUPT) | BIT(RESUME_INTERRUPT) | @@ -3403,7 +3401,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) writel(tmp, &dma->dmastat); /* dma sync*/ - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { + if (dev->quirks & PLX_SUPERSPEED) { u32 r_dmacount = readl(&dma->dmacount); if (!ep->is_in && (r_dmacount & 0x00FFFFFF) && (tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) @@ -3486,7 +3484,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev) struct net2280 *dev = _dev; /* shared interrupt, not ours */ - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY && + if ((dev->quirks & PLX_LEGACY) && (!(readl(&dev->regs->irqstat0) & BIT(INTA_ASSERTED)))) return IRQ_NONE; @@ -3498,7 +3496,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev) /* control requests and PIO */ handle_stat0_irqs(dev, readl(&dev->regs->irqstat0)); - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { + if (dev->quirks & PLX_SUPERSPEED) { /* re-enable interrupt to trigger any possible new interrupt */ u32 pciirqenb1 = readl(&dev->regs->pciirqenb1); writel(pciirqenb1 & 0x7FFFFFFF, &dev->regs->pciirqenb1); @@ -3543,7 +3541,7 @@ static void net2280_remove(struct pci_dev *pdev) } if (dev->got_irq) free_irq(pdev->irq, dev); - if (use_msi && dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (use_msi && dev->quirks & PLX_SUPERSPEED) pci_disable_msi(pdev); if (dev->regs) iounmap(dev->regs); @@ -3580,9 +3578,10 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, dev); spin_lock_init(&dev->lock); + dev->quirks = id->driver_data; dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - dev->gadget.max_speed = (dev->pdev->vendor == PCI_VENDOR_ID_PLX) ? + dev->gadget.max_speed = (dev->quirks & PLX_SUPERSPEED) ? USB_SPEED_SUPER : USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ @@ -3625,7 +3624,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200); dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300); - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX) { + if (dev->quirks & PLX_SUPERSPEED) { u32 fsmvalue; u32 usbstat; dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *) @@ -3668,7 +3667,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto done; } - if (use_msi && dev->pdev->vendor == PCI_VENDOR_ID_PLX) + if (use_msi && (dev->quirks & PLX_SUPERSPEED)) if (pci_enable_msi(pdev)) ep_err(dev, "Failed to enable MSI mode\n"); @@ -3707,7 +3706,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* enable lower-overhead pci memory bursts during DMA */ - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (dev->quirks & PLX_LEGACY) writel(BIT(DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) | /* * 256 write retries may not be enough... @@ -3763,7 +3762,7 @@ static void net2280_shutdown(struct pci_dev *pdev) writel(0, &dev->usb->usbctl); /* Disable full-speed test mode */ - if (dev->pdev->vendor == PCI_VENDOR_ID_PLX_LEGACY) + if (dev->quirks & PLX_LEGACY) writel(0, &dev->usb->xcvrdiag); } @@ -3777,6 +3776,7 @@ static const struct pci_device_id pci_ids[] = { { .device = 0x2280, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .driver_data = PLX_LEGACY | PLX_2280, }, { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, @@ -3784,6 +3784,7 @@ static const struct pci_device_id pci_ids[] = { { .device = 0x2282, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .driver_data = PLX_LEGACY, }, { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), @@ -3792,6 +3793,7 @@ static const struct pci_device_id pci_ids[] = { { .device = 0x3380, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .driver_data = PLX_SUPERSPEED, }, { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), @@ -3800,6 +3802,7 @@ static const struct pci_device_id pci_ids[] = { { .device = 0x3382, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .driver_data = PLX_SUPERSPEED, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index dc9ca1d5dc8e..03f15242d794 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -44,6 +44,10 @@ set_idx_reg(struct net2280_regs __iomem *regs, u32 index, u32 value) #define PCI_VENDOR_ID_PLX_LEGACY 0x17cc +#define PLX_LEGACY BIT(0) +#define PLX_2280 BIT(1) +#define PLX_SUPERSPEED BIT(2) + #define REG_DIAG 0x0 #define RETRY_COUNTER 16 #define FORCE_PCI_SERR 11 @@ -166,6 +170,8 @@ struct net2280 { u16 chiprev; int enhanced_mode; int n_ep; + kernel_ulong_t quirks; + /* pci state used to access those endpoints */ struct pci_dev *pdev; From d2999e1b10fb740371a896b33fa1e6d89669ffba Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 25 Jun 2014 08:26:47 +0200 Subject: [PATCH 043/211] tools: ffs-aio-example: fix header values endianess We wrap numeric values of fs_count and hs_count fields in htole32, because they should be in little-endian format. Acked-by: Michal Nazarewicz Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- .../usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c | 4 ++-- tools/usb/ffs-aio-example/simple/device_app/aio_simple.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c index 87216a0c4a8b..a349a872781b 100644 --- a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c +++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c @@ -37,8 +37,8 @@ static const struct { .header = { .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), .length = htole32(sizeof(descriptors)), - .fs_count = 3, - .hs_count = 3, + .fs_count = htole32(3), + .hs_count = htole32(3), }, .fs_descs = { .intf = { diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c index f558664a3317..28c22cb51249 100644 --- a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c +++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c @@ -35,8 +35,8 @@ static const struct { .header = { .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), .length = htole32(sizeof(descriptors)), - .fs_count = 3, - .hs_count = 3, + .fs_count = htole32(3), + .hs_count = htole32(3), }, .fs_descs = { .intf = { From 0ebe991042c927e68a50e206ad6244483f66301c Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 25 Jun 2014 08:26:48 +0200 Subject: [PATCH 044/211] tools: ffs-aio-example: convert to new descriptor format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit [ac8dde11: “Add flags to descriptors block”] functionfs supports a new descriptor format, so we update example application to make it using recomended version of descriptors. Acked-by: Michal Nazarewicz Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- .../multibuff/device_app/aio_multibuff.c | 12 ++++++++---- .../ffs-aio-example/simple/device_app/aio_simple.c | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c index a349a872781b..4b8279f373d5 100644 --- a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c +++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c @@ -27,7 +27,9 @@ /******************** Descriptors and Strings *******************************/ static const struct { - struct usb_functionfs_descs_head header; + struct usb_functionfs_descs_head_v2 header; + __le32 fs_count; + __le32 hs_count; struct { struct usb_interface_descriptor intf; struct usb_endpoint_descriptor_no_audio bulk_sink; @@ -35,11 +37,12 @@ static const struct { } __attribute__ ((__packed__)) fs_descs, hs_descs; } __attribute__ ((__packed__)) descriptors = { .header = { - .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), + .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), + .flags = htole32(FUNCTIONFS_HAS_FS_DESC | + FUNCTIONFS_HAS_HS_DESC), .length = htole32(sizeof(descriptors)), - .fs_count = htole32(3), - .hs_count = htole32(3), }, + .fs_count = htole32(3), .fs_descs = { .intf = { .bLength = sizeof(descriptors.fs_descs.intf), @@ -61,6 +64,7 @@ static const struct { .bmAttributes = USB_ENDPOINT_XFER_BULK, }, }, + .hs_count = htole32(3), .hs_descs = { .intf = { .bLength = sizeof(descriptors.hs_descs.intf), diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c index 28c22cb51249..2d6f59be4e7b 100644 --- a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c +++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c @@ -25,7 +25,9 @@ /******************** Descriptors and Strings *******************************/ static const struct { - struct usb_functionfs_descs_head header; + struct usb_functionfs_descs_head_v2 header; + __le32 fs_count; + __le32 hs_count; struct { struct usb_interface_descriptor intf; struct usb_endpoint_descriptor_no_audio bulk_sink; @@ -33,11 +35,12 @@ static const struct { } __attribute__ ((__packed__)) fs_descs, hs_descs; } __attribute__ ((__packed__)) descriptors = { .header = { - .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), + .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), + .flags = htole32(FUNCTIONFS_HAS_FS_DESC | + FUNCTIONFS_HAS_HS_DESC), .length = htole32(sizeof(descriptors)), - .fs_count = htole32(3), - .hs_count = htole32(3), }, + .fs_count = htole32(3), .fs_descs = { .intf = { .bLength = sizeof(descriptors.fs_descs.intf), @@ -59,6 +62,7 @@ static const struct { .bmAttributes = USB_ENDPOINT_XFER_BULK, }, }, + .hs_count = htole32(3), .hs_descs = { .intf = { .bLength = sizeof(descriptors.hs_descs.intf), From aa491320f4fb00f4ff6b67790bc75a96f6eb7790 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 25 Jun 2014 08:26:49 +0200 Subject: [PATCH 045/211] tools: ffs-aio-example: add license information Add missing information about license. Some people will probably want to reuse this code in their projects released under variety of licenses. For this reason this example is under Public Domain license to avoid GPL limitations. Acked-by: Michal Nazarewicz Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- .../multibuff/device_app/aio_multibuff.c | 27 +++++++++++++++++++ .../ffs-aio-example/multibuff/host_app/test.c | 27 +++++++++++++++++++ .../simple/device_app/aio_simple.c | 27 +++++++++++++++++++ .../ffs-aio-example/simple/host_app/test.c | 27 +++++++++++++++++++ 4 files changed, 108 insertions(+) diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c index 4b8279f373d5..af4b0508be77 100644 --- a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c +++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c @@ -1,3 +1,30 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + #define _BSD_SOURCE /* for endian.h */ #include diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c index b0ad8747d03f..daa3abe6bebd 100644 --- a/tools/usb/ffs-aio-example/multibuff/host_app/test.c +++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c @@ -1,3 +1,30 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + #include #include #include diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c index 2d6f59be4e7b..adc310a6d489 100644 --- a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c +++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c @@ -1,3 +1,30 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + #define _BSD_SOURCE /* for endian.h */ #include diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c index 64b6a57d8ca3..acd6332811f3 100644 --- a/tools/usb/ffs-aio-example/simple/host_app/test.c +++ b/tools/usb/ffs-aio-example/simple/host_app/test.c @@ -1,3 +1,30 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + #include #include #include From e176475daa9a0b99d7e01bcfa24c7800400a9cdc Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 29 Jun 2014 16:01:10 +0200 Subject: [PATCH 046/211] usb: gadget: pxa27x_udc: prepare and unprepare the clock Add clock prepare and unprepare as required by clock framework. Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi --- drivers/usb/gadget/pxa27x_udc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index cdf4d678be96..597d39f89420 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -2446,6 +2446,9 @@ static int pxa_udc_probe(struct platform_device *pdev) retval = PTR_ERR(udc->clk); goto err_clk; } + retval = clk_prepare(udc->clk); + if (retval) + goto err_clk_prepare; retval = -ENOMEM; udc->regs = ioremap(regs->start, resource_size(regs)); @@ -2483,6 +2486,8 @@ static int pxa_udc_probe(struct platform_device *pdev) err_irq: iounmap(udc->regs); err_map: + clk_unprepare(udc->clk); +err_clk_prepare: clk_put(udc->clk); udc->clk = NULL; err_clk: @@ -2509,6 +2514,7 @@ static int pxa_udc_remove(struct platform_device *_dev) udc->transceiver = NULL; the_controller = NULL; + clk_unprepare(udc->clk); clk_put(udc->clk); iounmap(udc->regs); From e44f1f4c04f273469b2a396f5f0fe03b5bb373d2 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 30 Jun 2014 18:29:49 +0100 Subject: [PATCH 047/211] usb: phy: msm: Make phy_reset clk and reset line optional. This patch makes the phy reset clk and reset line optional as this clk is not available on boards like IFC6410 with APQ8064. Signed-off-by: Srinivas Kandagatla Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-msm-usb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 625c14494c9a..d1f5da5b8d1b 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -279,11 +279,11 @@ static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) static int msm_otg_phy_clk_reset(struct msm_otg *motg) { - int ret; + int ret = 0; - if (motg->pdata->phy_clk_reset) + if (motg->pdata->phy_clk_reset && motg->phy_reset_clk) ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk); - else + else if (motg->phy_rst) ret = reset_control_reset(motg->phy_rst); if (ret) @@ -1464,7 +1464,7 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy"); if (IS_ERR(motg->phy_rst)) - return PTR_ERR(motg->phy_rst); + motg->phy_rst = NULL; pdata->mode = of_usb_get_dr_mode(node); if (pdata->mode == USB_DR_MODE_UNKNOWN) @@ -1556,7 +1556,7 @@ static int msm_otg_probe(struct platform_device *pdev) np ? "phy" : "usb_phy_clk"); if (IS_ERR(motg->phy_reset_clk)) { dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); - return PTR_ERR(motg->phy_reset_clk); + motg->phy_reset_clk = NULL; } motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk"); From ed7a3a9d8f507a18ce80d942d5880fed30de4a38 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 21 May 2014 09:04:17 +0800 Subject: [PATCH 048/211] usb: gadget: fsl_udc_core: should not call gadget driver's .unbind It has already been covered by udc core Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fsl_udc_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index ccbb3023cf42..57944ee8ad90 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1957,7 +1957,6 @@ static int fsl_udc_start(struct usb_gadget *g, &udc_controller->gadget); if (retval < 0) { ERR("can't bind to transceiver\n"); - driver->unbind(&udc_controller->gadget); udc_controller->driver = 0; return retval; } From 3b0f069fa3c4b26c7d9e90a0921881e08eff6674 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 21 May 2014 09:04:18 +0800 Subject: [PATCH 049/211] usb: gadget: fusb300_udc: should not call gadget driver's .unbind It has already been covered by udc core Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fusb300_udc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index d8e2c0c40106..d40255f784df 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1325,8 +1325,6 @@ static int fusb300_udc_stop(struct usb_gadget *g, { struct fusb300 *fusb300 = to_fusb300(g); - driver->unbind(&fusb300->gadget); - init_controller(fusb300); fusb300->driver = NULL; From 7a61612aef56244cbb31e5e54c9df8c599b25f55 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 21 May 2014 09:04:19 +0800 Subject: [PATCH 050/211] usb: gadget: m66592-udc: should not call gadget driver's .unbind It has already been covered by udc core Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/m66592-udc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 3d6609b5265e..de88d33b44b2 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1492,8 +1492,6 @@ static int m66592_udc_stop(struct usb_gadget *g, m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); - driver->unbind(&m66592->gadget); - init_controller(m66592); disable_controller(m66592); From a6c7c1c49c358b80b313b95eed2e199133f4dab2 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 21 May 2014 09:04:20 +0800 Subject: [PATCH 051/211] usb: gadget: net2272: do not need to judge gadget driver's .unbind It has already been covered by udc core, besides, we do not need unbind at .udc_start Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2272.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index ca15405583e2..059cfe527982 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -1453,7 +1453,7 @@ static int net2272_start(struct usb_gadget *_gadget, struct net2272 *dev; unsigned i; - if (!driver || !driver->unbind || !driver->setup || + if (!driver || !driver->setup || driver->max_speed != USB_SPEED_HIGH) return -EINVAL; From 50f741c8dd681410a1bfd822eb8cb0e2ec387539 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 21 May 2014 09:04:21 +0800 Subject: [PATCH 052/211] usb: gadget: omap_udc: should not call gadget driver's .unbind It has already been covered by udc core Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/omap_udc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 2ae4f6d69f74..e731373fd4d7 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2079,10 +2079,7 @@ static int omap_udc_start(struct usb_gadget *g, &udc->gadget); if (status < 0) { ERR("can't bind to transceiver\n"); - if (driver->unbind) { - driver->unbind(&udc->gadget); - udc->driver = NULL; - } + udc->driver = NULL; goto done; } } else { From d668b4f3cb43522158987f70b5d7744b583c551d Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Wed, 21 May 2014 14:05:35 +0200 Subject: [PATCH 053/211] usb: gadget: FunctionFS: Return -ENOENT instead of -ENODEV when device not found. Syscall mount returns -ENODEV error if requested FS type has not been found. Returning the same error from FFS mount callback makes value returned to userspace misleading. Other file systems returns -ENOENT if requested device has not been found. Adjust FFS to this convention to make error codes meaningfull. Acked-by: Michal Nazarewicz Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 4 ++-- drivers/usb/gadget/g_ffs.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 74202d67f911..88d6fa2290fd 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -2899,12 +2899,12 @@ static void *ffs_acquire_dev(const char *dev_name) ffs_dev = _ffs_find_dev(dev_name); if (!ffs_dev) - ffs_dev = ERR_PTR(-ENODEV); + ffs_dev = ERR_PTR(-ENOENT); else if (ffs_dev->mounted) ffs_dev = ERR_PTR(-EBUSY); else if (ffs_dev->ffs_acquire_dev_callback && ffs_dev->ffs_acquire_dev_callback(ffs_dev)) - ffs_dev = ERR_PTR(-ENODEV); + ffs_dev = ERR_PTR(-ENOENT); else ffs_dev->mounted = true; diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index fe12e6a27448..06acfa55864a 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -276,7 +276,7 @@ module_exit(gfs_exit); static void *functionfs_acquire_dev(struct ffs_dev *dev) { if (!try_module_get(THIS_MODULE)) - return ERR_PTR(-ENODEV); + return ERR_PTR(-ENOENT); return 0; } From 9c547699cce1f9da38af525b692fefb50d96158d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 26 May 2014 14:52:35 +0200 Subject: [PATCH 054/211] usb: musb: remove unnecessary (void) prefix at function calls Just a little cleanup that removes unnecessary casts. Signed-off-by: Daniel Mack Acked-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_host.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 3b11f98f3a56..0745839d7cd8 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1295,7 +1295,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) if (status) { if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { dma->status = MUSB_DMA_STATUS_CORE_ABORT; - (void) musb->dma_controller->channel_abort(dma); + musb->dma_controller->channel_abort(dma); } /* do the proper sequence to abort the transfer in the @@ -1640,7 +1640,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* clean up dma and collect transfer count */ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { dma->status = MUSB_DMA_STATUS_CORE_ABORT; - (void) musb->dma_controller->channel_abort(dma); + musb->dma_controller->channel_abort(dma); xfer_len = dma->actual_len; } musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG); @@ -1671,7 +1671,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) */ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { dma->status = MUSB_DMA_STATUS_CORE_ABORT; - (void) musb->dma_controller->channel_abort(dma); + musb->dma_controller->channel_abort(dma); xfer_len = dma->actual_len; done = true; } From c03da38d5d4b28f6ab559c4df8646dbda536b674 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 26 May 2014 14:52:36 +0200 Subject: [PATCH 055/211] usb: musb: use is_host_active() to distinguish between host and gadget mode On AM33xx platforms, unplugging a device in the middle of an active transfer leads to a drop of MUSB_DEVCTL_HM in MUSB_DEVCTL before the system is informed about a disconnect. This consequently makes the musb core call the gadget code to handle the interrupt request, which then crashes the kernel because the relevant pointers haven't been set up for gadget mode. To fix this, use is_host_active() rather than (devctl & MUSB_DEVCTL_HM) in musb_interrupt() and musb_dma_completion() to detect whether the controller is in host or peripheral mode. This information is provided by the driver logic and does not rely on register contents. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 61da471b7aed..3c6043c1b8ac 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1517,7 +1517,7 @@ irqreturn_t musb_interrupt(struct musb *musb) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", - (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", + is_host_active(musb) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); /* the core can interrupt us for multiple reasons; docs have @@ -1531,7 +1531,7 @@ irqreturn_t musb_interrupt(struct musb *musb) /* handle endpoint 0 first */ if (musb->int_tx & 1) { - if (devctl & MUSB_DEVCTL_HM) + if (is_host_active(musb)) retval |= musb_h_ep0_irq(musb); else retval |= musb_g_ep0_irq(musb); @@ -1545,7 +1545,7 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval = ep->rx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) + if (is_host_active(musb)) musb_host_rx(musb, ep_num); else musb_g_rx(musb, ep_num); @@ -1563,7 +1563,7 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval |= ep->tx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) + if (is_host_active(musb)) musb_host_tx(musb, ep_num); else musb_g_tx(musb, ep_num); @@ -1585,15 +1585,13 @@ MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) { - u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - /* called with controller lock already held */ if (!epnum) { #ifndef CONFIG_USB_TUSB_OMAP_DMA if (!is_cppi_enabled()) { /* endpoint 0 */ - if (devctl & MUSB_DEVCTL_HM) + if (is_host_active(musb)) musb_h_ep0_irq(musb); else musb_g_ep0_irq(musb); @@ -1602,13 +1600,13 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) } else { /* endpoints 1..15 */ if (transmit) { - if (devctl & MUSB_DEVCTL_HM) + if (is_host_active(musb)) musb_host_tx(musb, epnum); else musb_g_tx(musb, epnum); } else { /* receive */ - if (devctl & MUSB_DEVCTL_HM) + if (is_host_active(musb)) musb_host_rx(musb, epnum); else musb_g_rx(musb, epnum); From 2ccc6d30a0abf3e1a38f264e279428b846712e0f Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 26 May 2014 14:52:37 +0200 Subject: [PATCH 056/211] usb: musb: fix bit mask for CSR in musb_h_tx_flush_fifo() The datasheet says that MUSB_TXCSR_FLUSHFIFO is only valid when MUSB_TXCSR_TXPKTRDY is set as well. With this patch applied, the warning in this function does no longer kick in when an USB soundcard is unplugged while the stream is active. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 0745839d7cd8..3381fa56db29 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -120,7 +120,7 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) if (csr != lastcsr) dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr); lastcsr = csr; - csr |= MUSB_TXCSR_FLUSHFIFO; + csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_TXPKTRDY; musb_writew(epio, MUSB_TXCSR, csr); csr = musb_readw(epio, MUSB_TXCSR); if (WARN(retries-- < 1, From ff3fcac949187d98684aaf3f1c35c7cae7712649 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 26 May 2014 14:52:38 +0200 Subject: [PATCH 057/211] usb: musb: introduce dma_channel.rx_packet_done The musb/cppi41 glue layer is capable of handling transactions that span over more than one USB packet by reloading the DMA descriptors partially. An urb is considered completed when either its transfer buffer has been filled entirely (actual_length == transfer_buffer_length) or if a packet in the stream has less bytes than the endpoint's wMaxPacketSize. Once one of the above conditions is met, musb_dma_completion() is called from cppi41_trans_done(). However, the final decision whether or not to return the urb to its owner is made by the core and its determination of the variable 'done' in musb_host_rx(). This code has currently no way of knowing what the size of the last packet was, and whether or not to give back the urb due to a short read. Fix this by introducing a new boolean flag in 'struct dma_channel', and set it from musb_cppi41.c. If set, it will make the core do what the DMA layer decided and complete the urb. Signed-off-by: Daniel Mack Acked-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 2 ++ drivers/usb/musb/musb_dma.h | 1 + drivers/usb/musb/musb_host.c | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 7b8bbf53127e..4187ef1fab29 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -139,6 +139,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) cppi41_channel->channel.actual_len = cppi41_channel->transferred; cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; + cppi41_channel->channel.rx_packet_done = true; musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx); } else { /* next iteration, reload */ @@ -450,6 +451,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel, dma_desc->callback = cppi41_dma_callback; dma_desc->callback_param = channel; cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); + cppi41_channel->channel.rx_packet_done = false; save_rx_toggle(cppi41_channel); dma_async_issue_pending(dc); diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 1345a4ff041a..1d44faa86252 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -129,6 +129,7 @@ struct dma_channel { size_t actual_len; enum dma_channel_status status; bool desired_mode; + bool rx_packet_done; }; /* diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 3381fa56db29..88435cd7fe3d 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1737,7 +1737,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* done if urb buffer is full or short packet is recd */ done = (urb->actual_length + xfer_len >= urb->transfer_buffer_length - || dma->actual_len < qh->maxpacket); + || dma->actual_len < qh->maxpacket + || dma->rx_packet_done); } /* send IN token for next packet, without AUTOREQ */ From f50e67853b363b96336718597823ed7a7e8652de Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 26 May 2014 14:52:39 +0200 Subject: [PATCH 058/211] usb: musb/cppi41: call musb_ep_select() before accessing an endpoint's CSR Before accessing any of an endpoint's CSR registers, make sure the correct endpoint is selected. Otherwise, data read from or written to the registers is likely to affect the wrong endpoint as long as the connected device has more than one endpoint. This, of course, leads to all sorts of strange effects such as stream starvation and driver internal state machine confusion due to spurious interrupts. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 4187ef1fab29..932464ffb10c 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -74,15 +74,18 @@ static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) { + struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + struct musb *musb = hw_ep->musb; u16 csr; u8 toggle; if (cppi41_channel->is_tx) return; - if (!is_host_active(cppi41_channel->controller->musb)) + if (!is_host_active(musb)) return; - csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); + musb_ep_select(musb->mregs, hw_ep->epnum); + csr = musb_readw(hw_ep->regs, MUSB_RXCSR); toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; /* @@ -107,6 +110,7 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) void __iomem *epio = musb->endpoints[epnum].regs; u16 csr; + musb_ep_select(musb->mregs, hw_ep->epnum); csr = musb_readw(epio, MUSB_TXCSR); if (csr & MUSB_TXCSR_TXPKTRDY) return false; @@ -173,6 +177,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) dma_async_issue_pending(dc); if (!cppi41_channel->is_tx) { + musb_ep_select(musb->mregs, hw_ep->epnum); csr = musb_readw(epio, MUSB_RXCSR); csr |= MUSB_RXCSR_H_REQPKT; musb_writew(epio, MUSB_RXCSR, csr); From 49a9e885306a54048cc81b1da6b7df2b692cd8c1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 26 May 2014 14:52:40 +0200 Subject: [PATCH 059/211] usb: musb: fix wrong indentation in musb_host.c Just a cosmetic cleanup with no functional change. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_host.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 88435cd7fe3d..855793d701bb 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1734,11 +1734,11 @@ void musb_host_rx(struct musb *musb, u8 epnum) } } else { - /* done if urb buffer is full or short packet is recd */ - done = (urb->actual_length + xfer_len >= - urb->transfer_buffer_length - || dma->actual_len < qh->maxpacket - || dma->rx_packet_done); + /* done if urb buffer is full or short packet is recd */ + done = (urb->actual_length + xfer_len >= + urb->transfer_buffer_length + || dma->actual_len < qh->maxpacket + || dma->rx_packet_done); } /* send IN token for next packet, without AUTOREQ */ From eefae89e00cc7186fc8cde811e43074844af83c0 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 20 Jun 2014 00:20:43 +0200 Subject: [PATCH 060/211] Revert "usb: musb: musb_cppi41: Handle ISOCH differently and not use the hrtimer." This reverts commit 1af54b7a4. The commit tried to address cases in which isochronous transfers are 'not reliable', most probably in the tests conducted, polling for the MUSB_TXCSR_TXPKTRDY bit in MUSB_TXCSR is done too late. Hence, it installs a work struct which basically busy-polls for the bit in a rather agressive way by rescheduling the work if the FIFO is not empty. With USB audio devices, tests have shown that it takes approximately 100 iterations of the asynchronous worker until the FIFO signals completion, which leads to 100% CPU loads when streaming audio. The issue the patch tried to address can be handled differently, which is what the next patch does. Signed-off-by: Daniel Mack Reported-by: Sebastian Reimers Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 53 ---------------------------------- 1 file changed, 53 deletions(-) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 932464ffb10c..a2c445608e75 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -39,7 +39,6 @@ struct cppi41_dma_channel { u32 transferred; u32 packet_sz; struct list_head tx_check; - struct work_struct dma_completion; }; #define MUSB_DMA_NUM_CHANNELS 15 @@ -117,18 +116,6 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) return true; } -static bool is_isoc(struct musb_hw_ep *hw_ep, bool in) -{ - if (in && hw_ep->in_qh) { - if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC) - return true; - } else if (hw_ep->out_qh) { - if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC) - return true; - } - return false; -} - static void cppi41_dma_callback(void *private_data); static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) @@ -185,32 +172,6 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) } } -static void cppi_trans_done_work(struct work_struct *work) -{ - unsigned long flags; - struct cppi41_dma_channel *cppi41_channel = - container_of(work, struct cppi41_dma_channel, dma_completion); - struct cppi41_dma_controller *controller = cppi41_channel->controller; - struct musb *musb = controller->musb; - struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; - bool empty; - - if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) { - spin_lock_irqsave(&musb->lock, flags); - cppi41_trans_done(cppi41_channel); - spin_unlock_irqrestore(&musb->lock, flags); - } else { - empty = musb_is_tx_fifo_empty(hw_ep); - if (empty) { - spin_lock_irqsave(&musb->lock, flags); - cppi41_trans_done(cppi41_channel); - spin_unlock_irqrestore(&musb->lock, flags); - } else { - schedule_work(&cppi41_channel->dma_completion); - } - } -} - static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) { struct cppi41_dma_controller *controller; @@ -274,14 +235,6 @@ static void cppi41_dma_callback(void *private_data) transferred < cppi41_channel->packet_sz) cppi41_channel->prog_len = 0; - if (!cppi41_channel->is_tx) { - if (is_isoc(hw_ep, 1)) - schedule_work(&cppi41_channel->dma_completion); - else - cppi41_trans_done(cppi41_channel); - goto out; - } - empty = musb_is_tx_fifo_empty(hw_ep); if (empty) { cppi41_trans_done(cppi41_channel); @@ -318,10 +271,6 @@ static void cppi41_dma_callback(void *private_data) goto out; } } - if (is_isoc(hw_ep, 0)) { - schedule_work(&cppi41_channel->dma_completion); - goto out; - } list_add_tail(&cppi41_channel->tx_check, &controller->early_tx_list); if (!hrtimer_active(&controller->early_tx)) { @@ -679,8 +628,6 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) cppi41_channel->port_num = port; cppi41_channel->is_tx = is_tx; INIT_LIST_HEAD(&cppi41_channel->tx_check); - INIT_WORK(&cppi41_channel->dma_completion, - cppi_trans_done_work); musb_dma = &cppi41_channel->channel; musb_dma->private_data = cppi41_channel; From 50aea6fca771d6daf3ec24f771da866f7fd836e4 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 20 Jun 2014 00:20:44 +0200 Subject: [PATCH 061/211] usb: musb: cppi41: fire hrtimer according to programmed channel length The musb/cppi41 code installs a hrtimer to work around DMA completion interrupts that have fired too early on AM335x hardware. This timer is currently programmed to first fire 140 microseconds after the DMA completion callback. According to the commit which introduced it (a655f481d83, "usb: musb: musb_cppi41: handle pre-mature TX complete interrupt"), that value is is considered a 'rule of thumb' that worked well with the test case described in the commit log. Test show, however, that for USB audio devices and much smaller packet sizes, the timer has to fire earlier in order to correctly handle the audio stream. The original test case had output transfer sizes of 1514 bytes, and a delay of 140 microseconds. For audio devices with 24 bytes channel size, 3 microseconds seem to work well. Hence, let's assume that the time it takes to clear the bit correlates with the number of bytes transferred. The referenced commit log mentions such a suspicion as well. Let the timer fire in cppi41_channel->total_len/10 microseconds to correctly handle both cases. Also, shorten the interval in which the timer fires again in case of a non-empty early_tx list. With these changes in place, both FS and HS audio devices appear to work well on AM335x hardware. Signed-off-by: Daniel Mack Reported-by: Sebastian Reimers Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index a2c445608e75..adfffe884891 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -200,7 +200,7 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) if (!list_empty(&controller->early_tx_list)) { ret = HRTIMER_RESTART; hrtimer_forward_now(&controller->early_tx, - ktime_set(0, 150 * NSEC_PER_USEC)); + ktime_set(0, 50 * NSEC_PER_USEC)); } spin_unlock_irqrestore(&musb->lock, flags); @@ -274,8 +274,10 @@ static void cppi41_dma_callback(void *private_data) list_add_tail(&cppi41_channel->tx_check, &controller->early_tx_list); if (!hrtimer_active(&controller->early_tx)) { + unsigned long usecs = cppi41_channel->total_len / 10; + hrtimer_start_range_ns(&controller->early_tx, - ktime_set(0, 140 * NSEC_PER_USEC), + ktime_set(0, usecs * NSEC_PER_USEC), 40 * NSEC_PER_USEC, HRTIMER_MODE_REL); } From 527b570c842710ca32905808bea630ec53ad0b3b Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Mon, 30 Jun 2014 22:13:29 +0300 Subject: [PATCH 062/211] usb: gadget: s3c2410: Move to clk_prepare_enable/clk_disable_unprepare Use clk_prepare_enable/clk_disable_unprepare to make the driver work properly with common clock framework. Signed-off-by: Vasily Khoruzhick Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c2410_udc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 7987aa049fab..357b58e0087b 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1788,7 +1788,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) return PTR_ERR(usb_bus_clock); } - clk_enable(usb_bus_clock); + clk_prepare_enable(usb_bus_clock); udc_clock = clk_get(NULL, "usb-device"); if (IS_ERR(udc_clock)) { @@ -1796,7 +1796,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) return PTR_ERR(udc_clock); } - clk_enable(udc_clock); + clk_prepare_enable(udc_clock); mdelay(10); @@ -1952,13 +1952,13 @@ static int s3c2410_udc_remove(struct platform_device *pdev) release_mem_region(rsrc_start, rsrc_len); if (!IS_ERR(udc_clock) && udc_clock != NULL) { - clk_disable(udc_clock); + clk_disable_unprepare(udc_clock); clk_put(udc_clock); udc_clock = NULL; } if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) { - clk_disable(usb_bus_clock); + clk_disable_unprepare(usb_bus_clock); clk_put(usb_bus_clock); usb_bus_clock = NULL; } From af6f9e8355b2200df1ed077bc1b8ebf6b4592b01 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 5 Jun 2014 16:05:53 +0200 Subject: [PATCH 063/211] USB: ftdi_sio: make port probe less verbose There's no need to print the number of endpoints per interface or endpoint wMaxPacketSize during port probe. This information is readily available using lsusb should it ever be needed. Note that this also fixes the wMaxPacketSize being incorrectly reported on big-endian systems due to a missing le16_to_cpu(). Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 115662c16dcc..ca84d2cdd655 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1572,8 +1572,6 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) unsigned i; num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; - dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); - if (!num_endpoints) return; @@ -1582,8 +1580,6 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) * want to override the endpoint descriptor setting and use a * value of 64 for wMaxPacketSize */ for (i = 0; i < num_endpoints; i++) { - dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1, - interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize); ep_desc = &interface->cur_altsetting->endpoint[i].desc; if (ep_desc->wMaxPacketSize == 0) { ep_desc->wMaxPacketSize = cpu_to_le16(0x40); @@ -1593,8 +1589,6 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) /* set max packet size based on descriptor */ priv->max_packet_size = usb_endpoint_maxp(ep_desc); - - dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } From a90d84adb43936f66ede77794940dc27156d58da Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 5 Jun 2014 16:05:54 +0200 Subject: [PATCH 064/211] USB: ftdi_sio: fix max-packet-size warning Promote max-packet-size-override message to warning level and use the port device for logging, while using actual endpoint numbers in the message itself. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ca84d2cdd655..6cfa55a2f804 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1563,8 +1563,6 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; - struct usb_device *udev = serial->dev; - struct usb_interface *interface = serial->interface; struct usb_endpoint_descriptor *ep_desc; @@ -1583,7 +1581,8 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) ep_desc = &interface->cur_altsetting->endpoint[i].desc; if (ep_desc->wMaxPacketSize == 0) { ep_desc->wMaxPacketSize = cpu_to_le16(0x40); - dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i); + dev_warn(&port->dev, "Overriding wMaxPacketSize on endpoint %d\n", + usb_endpoint_num(ep_desc)); } } From 47e575952bdbd6a9bbf9e087069c658322cb0622 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 5 Jun 2014 16:05:55 +0200 Subject: [PATCH 065/211] USB: ftdi_sio: clean up ftdi_set_max_packet_size() Code and comment style clean ups of ftdi_set_max_packet_size(). Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6cfa55a2f804..6451bf47b05b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1556,16 +1556,16 @@ static void ftdi_determine_type(struct usb_serial_port *port) } -/* Determine the maximum packet size for the device. This depends on the chip - * type and the USB host capabilities. The value should be obtained from the - * device descriptor as the chip will use the appropriate values for the host.*/ +/* + * Determine the maximum packet size for the device. This depends on the chip + * type and the USB host capabilities. The value should be obtained from the + * device descriptor as the chip will use the appropriate values for the host. + */ static void ftdi_set_max_packet_size(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - struct usb_interface *interface = serial->interface; + struct usb_interface *interface = port->serial->interface; struct usb_endpoint_descriptor *ep_desc; - unsigned num_endpoints; unsigned i; @@ -1573,20 +1573,22 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) if (!num_endpoints) return; - /* NOTE: some customers have programmed FT232R/FT245R devices - * with an endpoint size of 0 - not good. In this case, we + /* + * NOTE: Some customers have programmed FT232R/FT245R devices + * with an endpoint size of 0 - not good. In this case, we * want to override the endpoint descriptor setting and use a - * value of 64 for wMaxPacketSize */ + * value of 64 for wMaxPacketSize. + */ for (i = 0; i < num_endpoints; i++) { ep_desc = &interface->cur_altsetting->endpoint[i].desc; - if (ep_desc->wMaxPacketSize == 0) { + if (!ep_desc->wMaxPacketSize) { ep_desc->wMaxPacketSize = cpu_to_le16(0x40); dev_warn(&port->dev, "Overriding wMaxPacketSize on endpoint %d\n", usb_endpoint_num(ep_desc)); } } - /* set max packet size based on descriptor */ + /* Set max packet size based on last descriptor. */ priv->max_packet_size = usb_endpoint_maxp(ep_desc); } From 19de4278121f59aaca68492ed1a66adda0e06294 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 5 Jun 2014 16:05:56 +0200 Subject: [PATCH 066/211] USB: ftdi_sio: remove redundant mtxorb quirk Remove redundant mtxorb quirk used to fix up incorrect wMaxPacketSize, which was added before 895f28badce9 ("USB: ftdi_sio: fix hi-speed device packet size calculation") which does the same thing for all devices. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 47 ++++++----------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6451bf47b05b..3496486927ea 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -87,7 +87,6 @@ struct ftdi_sio_quirk { }; static int ftdi_jtag_probe(struct usb_serial *serial); -static int ftdi_mtxorb_hack_setup(struct usb_serial *serial); static int ftdi_NDI_device_setup(struct usb_serial *serial); static int ftdi_stmclite_probe(struct usb_serial *serial); static int ftdi_8u2232c_probe(struct usb_serial *serial); @@ -98,10 +97,6 @@ static struct ftdi_sio_quirk ftdi_jtag_quirk = { .probe = ftdi_jtag_probe, }; -static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = { - .probe = ftdi_mtxorb_hack_setup, -}; - static struct ftdi_sio_quirk ftdi_NDI_device_quirk = { .probe = ftdi_NDI_device_setup, }; @@ -256,14 +251,12 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) }, @@ -302,18 +295,12 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) }, @@ -1858,24 +1845,6 @@ static int ftdi_stmclite_probe(struct usb_serial *serial) return 0; } -/* - * The Matrix Orbital VK204-25-USB has an invalid IN endpoint. - * We have to correct it if we want to read from it. - */ -static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) -{ - struct usb_host_endpoint *ep = serial->dev->ep_in[1]; - struct usb_endpoint_descriptor *ep_desc = &ep->desc; - - if (ep->enabled && ep_desc->wMaxPacketSize == 0) { - ep_desc->wMaxPacketSize = cpu_to_le16(0x40); - dev_info(&serial->dev->dev, - "Fixing invalid wMaxPacketSize on read pipe\n"); - } - - return 0; -} - static int ftdi_sio_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); From cca16d62426680b49dd3b6008d10f50156874080 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 28 Jun 2014 14:44:09 +0200 Subject: [PATCH 067/211] USB: mos7840: remove unnecessary null test before kfree Cc: Johan Hovold Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: Johan Hovold --- drivers/usb/serial/mos7840.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 393be562d875..3d88eefdf1d1 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1181,10 +1181,7 @@ static void mos7840_close(struct usb_serial_port *port) /* Freeing Write URBs */ for (j = 0; j < NUM_URBS; ++j) { if (mos7840_port->write_urb_pool[j]) { - if (mos7840_port->write_urb_pool[j]->transfer_buffer) - kfree(mos7840_port->write_urb_pool[j]-> - transfer_buffer); - + kfree(mos7840_port->write_urb_pool[j]->transfer_buffer); usb_free_urb(mos7840_port->write_urb_pool[j]); } } From 5bc9e5933a41888f9e0d77dedc9f8a972fa1f493 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Sat, 31 May 2014 13:03:00 -0300 Subject: [PATCH 068/211] USB: kl5kusb105: Remove klsi_105_tiocmset function This patch remove the function klsi_105_tiocmset which was only returning -EINVAL. It also removes the function prototype and the .tiocmset entry in the struct usb_serial_driver. Verified by compilation only. Signed-off-by: Peter Senna Tschudin Signed-off-by: Johan Hovold --- drivers/usb/serial/kl5kusb105.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index d7440b7557af..e020ad28a00c 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -62,8 +62,6 @@ static void klsi_105_close(struct usb_serial_port *port); static void klsi_105_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int klsi_105_tiocmget(struct tty_struct *tty); -static int klsi_105_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); static void klsi_105_process_read_urb(struct urb *urb); static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size); @@ -93,7 +91,6 @@ static struct usb_serial_driver kl5kusb105d_device = { .set_termios = klsi_105_set_termios, /*.break_ctl = klsi_105_break_ctl,*/ .tiocmget = klsi_105_tiocmget, - .tiocmset = klsi_105_tiocmset, .port_probe = klsi_105_port_probe, .port_remove = klsi_105_port_remove, .throttle = usb_serial_generic_throttle, @@ -602,33 +599,6 @@ static int klsi_105_tiocmget(struct tty_struct *tty) return (int)line_state; } -static int klsi_105_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - int retval = -EINVAL; - -/* if this ever gets implemented, it should be done something like this: - struct usb_serial *serial = port->serial; - struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int control; - - spin_lock_irqsave (&priv->lock, flags); - if (set & TIOCM_RTS) - priv->control_state |= TIOCM_RTS; - if (set & TIOCM_DTR) - priv->control_state |= TIOCM_DTR; - if (clear & TIOCM_RTS) - priv->control_state &= ~TIOCM_RTS; - if (clear & TIOCM_DTR) - priv->control_state &= ~TIOCM_DTR; - control = priv->control_state; - spin_unlock_irqrestore (&priv->lock, flags); - retval = mct_u232_set_modem_ctrl(serial, control); -*/ - return retval; -} - module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); From ec5734c41bee2ee7c938a8f34853d31cada7e67a Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Tue, 17 Jun 2014 16:38:50 +0530 Subject: [PATCH 069/211] usb: misc: usb3503: Update error code in print message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'err' is uninitialized, rather print the error code directly. This also fixes following warning. drivers/usb/misc/usb3503.c: In function ‘usb3503_probe’: drivers/usb/misc/usb3503.c:195:11: warning: ‘err’ may be used uninitialized in this function [-Wmaybe-uninitialized] dev_err(dev, "unable to request refclk (%d)\n", err); Signed-off-by: Tushar Behera Acked-by: Marek Szyprowski Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb3503.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index f43c61989cef..652855b40289 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -192,7 +192,8 @@ static int usb3503_probe(struct usb3503 *hub) clk = devm_clk_get(dev, "refclk"); if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT) { - dev_err(dev, "unable to request refclk (%d)\n", err); + dev_err(dev, "unable to request refclk (%ld)\n", + PTR_ERR(clk)); return PTR_ERR(clk); } From 9502c46cc9d39330b29d9dc27d8baff4f55d0abc Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 4 Jul 2014 17:01:23 +0300 Subject: [PATCH 070/211] xhci: A default implementation for Ux timeout calculation and tier policy check As best case, a host controller should support U0 to U1 switching for the devices connected below any tier of hub level supported by usb specification. Therefore xhci_check_tier_policy should always return success as default implementation. A host should be able to issue LGO_Ux after the timeout calculated as per definition of system exit latency defined in C.1.5.2. Therefore xhci_calculate_ux_timeout returns ux_params.sel as the default implementation. Use default calculation in absence of any vendor specific limitations. Signed-off-by: Pratyush Anand Tested-by: Aymen Bouattay Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 66 ++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f07be65b4e70..b04fef1e4ff8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4288,8 +4288,7 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, return USB3_LPM_DISABLED; } -/* Returns the hub-encoded U1 timeout value. - * The U1 timeout should be the maximum of the following values: +/* The U1 timeout should be the maximum of the following values: * - For control endpoints, U1 system exit latency (SEL) * 3 * - For bulk endpoints, U1 SEL * 5 * - For interrupt endpoints: @@ -4297,7 +4296,8 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, * - Periodic EPs, max(105% of bInterval, U1 SEL * 2) * - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2) */ -static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev, +static unsigned long long xhci_calculate_intel_u1_timeout( + struct usb_device *udev, struct usb_endpoint_descriptor *desc) { unsigned long long timeout_ns; @@ -4329,11 +4329,28 @@ static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev, return 0; } - /* The U1 timeout is encoded in 1us intervals. */ - timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000); - /* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */ + return timeout_ns; +} + +/* Returns the hub-encoded U1 timeout value. */ +static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + + if (xhci->quirks & XHCI_INTEL_HOST) + timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc); + else + timeout_ns = udev->u1_params.sel; + + /* The U1 timeout is encoded in 1us intervals. + * Don't return a timeout of zero, because that's USB3_LPM_DISABLED. + */ if (timeout_ns == USB3_LPM_DISABLED) - timeout_ns++; + timeout_ns = 1; + else + timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000); /* If the necessary timeout value is bigger than what we can set in the * USB 3.0 hub, we have to disable hub-initiated U1. @@ -4345,14 +4362,14 @@ static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev, return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1); } -/* Returns the hub-encoded U2 timeout value. - * The U2 timeout should be the maximum of: +/* The U2 timeout should be the maximum of: * - 10 ms (to avoid the bandwidth impact on the scheduler) * - largest bInterval of any active periodic endpoint (to avoid going * into lower power link states between intervals). * - the U2 Exit Latency of the device */ -static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev, +static unsigned long long xhci_calculate_intel_u2_timeout( + struct usb_device *udev, struct usb_endpoint_descriptor *desc) { unsigned long long timeout_ns; @@ -4368,6 +4385,21 @@ static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev, if (u2_del_ns > timeout_ns) timeout_ns = u2_del_ns; + return timeout_ns; +} + +/* Returns the hub-encoded U2 timeout value. */ +static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + + if (xhci->quirks & XHCI_INTEL_HOST) + timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc); + else + timeout_ns = udev->u2_params.sel; + /* The U2 timeout is encoded in 256us intervals */ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000); /* If the necessary timeout value is bigger than what we can set in the @@ -4386,13 +4418,10 @@ static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci, enum usb3_link_state state, u16 *timeout) { - if (state == USB3_LPM_U1) { - if (xhci->quirks & XHCI_INTEL_HOST) - return xhci_calculate_intel_u1_timeout(udev, desc); - } else { - if (xhci->quirks & XHCI_INTEL_HOST) - return xhci_calculate_intel_u2_timeout(udev, desc); - } + if (state == USB3_LPM_U1) + return xhci_calculate_u1_timeout(xhci, udev, desc); + else if (state == USB3_LPM_U2) + return xhci_calculate_u2_timeout(xhci, udev, desc); return USB3_LPM_DISABLED; } @@ -4469,7 +4498,8 @@ static int xhci_check_tier_policy(struct xhci_hcd *xhci, { if (xhci->quirks & XHCI_INTEL_HOST) return xhci_check_intel_tier_policy(udev, state); - return -EINVAL; + else + return 0; } /* Returns the U1 or U2 timeout that should be enabled. From 94ef3d50426240a5402688e8d43a079df5ae21be Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 4 Jul 2014 17:01:24 +0300 Subject: [PATCH 071/211] xhci: Platform: Add (en/dis)able_usb3_lpm_timeout To use auto U0-U1/U2 transition by xhci platform device add (en/dis)able_usb3_lpm_timeout function to the xhci_plat_xhci_driver struct. Signed-off-by: Pratyush Anand Tested-by: Aymen Bouattay Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 29d8adb5c8d1..a4ccd0eb793e 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -90,6 +90,9 @@ static const struct hc_driver xhci_plat_xhci_driver = { .hub_status_data = xhci_hub_status_data, .bus_suspend = xhci_bus_suspend, .bus_resume = xhci_bus_resume, + + .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, + .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, }; static int xhci_plat_probe(struct platform_device *pdev) From 20f6fdd01c2c0de9cc1109083222edded24c5350 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 4 Jul 2014 17:01:25 +0300 Subject: [PATCH 072/211] xhci: Platform: Set xhci lpm support quirk based on platform data If an xhci platform supports USB3 LPM capability then enable XHCI_LPM_SUPPORT quirk flag. Signed-off-by: Pratyush Anand Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/usb-xhci.txt | 3 ++- drivers/usb/host/xhci-plat.c | 6 +++++ include/linux/usb/xhci_pdriver.h | 27 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 include/linux/usb/xhci_pdriver.h diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index 5a79377c6a96..86f67f0886bc 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -9,8 +9,9 @@ Required properties: register set for the device. - interrupts: one XHCI interrupt should be described here. -Optional property: +Optional properties: - clocks: reference to a clock + - usb3-lpm-capable: determines if platform is USB3 LPM capable Example: usb@f0931000 { diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index a4ccd0eb793e..b17459d3fcc8 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "xhci.h" #include "xhci-mvebu.h" @@ -97,6 +98,8 @@ static const struct hc_driver xhci_plat_xhci_driver = { static int xhci_plat_probe(struct platform_device *pdev) { + struct device_node *node = pdev->dev.of_node; + struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); const struct hc_driver *driver; struct xhci_hcd *xhci; struct resource *res; @@ -185,6 +188,9 @@ static int xhci_plat_probe(struct platform_device *pdev) goto dealloc_usb2_hcd; } + if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || + (pdata && pdata->usb3_lpm_capable)) + xhci->quirks |= XHCI_LPM_SUPPORT; /* * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) * is called by usb_add_hcd(). diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h new file mode 100644 index 000000000000..376654b5b0f7 --- /dev/null +++ b/include/linux/usb/xhci_pdriver.h @@ -0,0 +1,27 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __USB_CORE_XHCI_PDRIVER_H +#define __USB_CORE_XHCI_PDRIVER_H + +/** + * struct usb_xhci_pdata - platform_data for generic xhci platform driver + * + * @usb3_lpm_capable: determines if this xhci platform supports USB3 + * LPM capability + * + */ +struct usb_xhci_pdata { + unsigned usb3_lpm_capable:1; +}; + +#endif /* __USB_CORE_XHCI_PDRIVER_H */ From b2f463e1300016785d63475c56f5807e2be00934 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 4 Jul 2014 17:01:26 +0300 Subject: [PATCH 073/211] dwc3: host: Enable USB3 LPM capability All dwc3 based xhci host controller supports USB3.0 LPM functionality. Therefore enable it in platform data for all dwc3 based xhci device if DWC3_HOST_USB3_LPM_ENABLE is selected in Kconfig. Signed-off-by: Pratyush Anand Signed-off-by: Mathias Nyman Signed-of-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/Kconfig | 7 +++++++ drivers/usb/dwc3/host.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 261c3b428220..785510a0a0c3 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -93,4 +93,11 @@ config USB_DWC3_VERBOSE help Say Y here to enable verbose debugging messages on DWC3 Driver. +config DWC3_HOST_USB3_LPM_ENABLE + bool "Enable USB3 LPM Capability" + depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y + default n + help + Select this when you want to enable USB3 LPM with dwc3 xhci host. + endif diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 32db328cc769..dcb8ca084598 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -16,12 +16,14 @@ */ #include +#include #include "core.h" int dwc3_host_init(struct dwc3 *dwc) { struct platform_device *xhci; + struct usb_xhci_pdata pdata; int ret; xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); @@ -46,6 +48,18 @@ int dwc3_host_init(struct dwc3 *dwc) goto err1; } + memset(&pdata, 0, sizeof(pdata)); + +#ifdef CONFIG_DWC3_HOST_USB3_LPM_ENABLE + pdata.usb3_lpm_capable = 1; +#endif + + ret = platform_device_add_data(xhci, &pdata, sizeof(pdata)); + if (ret) { + dev_err(dwc->dev, "couldn't add platform data to xHCI device\n"); + goto err1; + } + ret = platform_device_add(xhci); if (ret) { dev_err(dwc->dev, "failed to register xHCI device\n"); From 51df62ff74b371866c1006dee887a8e42838c1f2 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 4 Jul 2014 17:01:27 +0300 Subject: [PATCH 074/211] usb: allow lpm (en/dis)able only if device is atleast in default state When a USB device is disconnected, usb_unbind_interface is called, which tries to enable and disable LPM. usb_enable_lpm also try to send a control command SET SEL to the device. Since device is already disconnected, therefore it does not make sense to execute usb_(en/dis)able_lpm. This patch returns from usb_(en/dis)able_lpm, if device was not in default state atleast. Signed-off-by: Pratyush Anand Tested-by: Aymen Bouattay Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 21b99b4b4082..b90c6287bf47 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3860,7 +3860,8 @@ int usb_disable_lpm(struct usb_device *udev) if (!udev || !udev->parent || udev->speed != USB_SPEED_SUPER || - !udev->lpm_capable) + !udev->lpm_capable || + udev->state < USB_STATE_DEFAULT) return 0; hcd = bus_to_hcd(udev->bus); @@ -3916,7 +3917,8 @@ void usb_enable_lpm(struct usb_device *udev) if (!udev || !udev->parent || udev->speed != USB_SPEED_SUPER || - !udev->lpm_capable) + !udev->lpm_capable || + udev->state < USB_STATE_DEFAULT) return; udev->lpm_disable_count--; From 3cd12f91514da6893954de479dc60b16d3b381f4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 29 May 2014 12:58:46 -0700 Subject: [PATCH 075/211] usb: force warm reset to break link re-connect livelock Resuming a powered down port sometimes results in the port state being stuck in the training sequence. hub 3-0:1.0: debounce: port 1: total 2000ms stable 0ms status 0x2e0 port1: can't get reconnection after setting port power on, status -110 hub 3-0:1.0: port 1 status 0000.02e0 after resume, -19 usb 3-1: can't resume, status -19 hub 3-0:1.0: logical disconnect on port 1 In the case above we wait for the port re-connect timeout of 2 seconds and observe that the port status is USB_SS_PORT_LS_POLLING (although it is likely toggling between this state and USB_SS_PORT_LS_RX_DETECT). This is indicative of a case where the device is failing to progress the link training state machine. It is resolved by issuing a warm reset to get the hub and device link state machines back in sync. hub 3-0:1.0: debounce: port 1: total 2000ms stable 0ms status 0x2e0 usb usb3: port1 usb_port_runtime_resume requires warm reset hub 3-0:1.0: port 1 not warm reset yet, waiting 50ms usb 3-1: reset SuperSpeed USB device number 2 using xhci_hcd After a reconnect timeout when we expect the device to be present, force a warm reset of the device. Note that we can not simply look at the link status to determine if a warm reset is required as any of the training states USB_SS_PORT_LS_POLLING, USB_SS_PORT_LS_RX_DETECT, or USB_SS_PORT_LS_COMP_MOD are valid states that do not indicate the need for warm reset by themselves. Cc: Alan Stern Cc: Kukjin Kim Cc: Vincent Palatin Cc: Lan Tianyu Cc: Ksenia Ragiadakou Cc: Vivek Gautam Cc: Douglas Anderson Cc: Felipe Balbi Cc: Sunil Joshi Cc: Hans de Goede Acked-by: Julius Werner Signed-off-by: Dan Williams Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 36 +++++++++++++++++++++++++----------- drivers/usb/core/hub.h | 2 ++ drivers/usb/core/port.c | 21 ++++++++++++--------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b90c6287bf47..88f1db27e0af 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2587,13 +2587,20 @@ static int hub_port_reset(struct usb_hub *hub, int port1, /* Is a USB 3.0 port in the Inactive or Compliance Mode state? * Port worm reset is required to recover */ -static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) +static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, + u16 portstatus) { - return hub_is_superspeed(hub->hdev) && - (((portstatus & USB_PORT_STAT_LINK_STATE) == - USB_SS_PORT_LS_SS_INACTIVE) || - ((portstatus & USB_PORT_STAT_LINK_STATE) == - USB_SS_PORT_LS_COMP_MOD)) ; + u16 link_state; + + if (!hub_is_superspeed(hub->hdev)) + return false; + + if (test_bit(port1, hub->warm_reset_bits)) + return true; + + link_state = portstatus & USB_PORT_STAT_LINK_STATE; + return link_state == USB_SS_PORT_LS_SS_INACTIVE + || link_state == USB_SS_PORT_LS_COMP_MOD; } static int hub_port_wait_reset(struct usb_hub *hub, int port1, @@ -2630,7 +2637,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, if ((portstatus & USB_PORT_STAT_RESET)) return -EBUSY; - if (hub_port_warm_reset_required(hub, portstatus)) + if (hub_port_warm_reset_required(hub, port1, portstatus)) return -ENOTCONN; /* Device went away? */ @@ -2730,9 +2737,10 @@ static int hub_port_reset(struct usb_hub *hub, int port1, if (status < 0) goto done; - if (hub_port_warm_reset_required(hub, portstatus)) + if (hub_port_warm_reset_required(hub, port1, portstatus)) warm = true; } + clear_bit(port1, hub->warm_reset_bits); /* Reset the port */ for (i = 0; i < PORT_RESET_TRIES; i++) { @@ -2769,7 +2777,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, &portstatus, &portchange) < 0) goto done; - if (!hub_port_warm_reset_required(hub, portstatus)) + if (!hub_port_warm_reset_required(hub, port1, + portstatus)) goto done; /* @@ -2856,8 +2865,13 @@ static int check_port_resume_type(struct usb_device *udev, { struct usb_port *port_dev = hub->ports[port1 - 1]; + /* Is a warm reset needed to recover the connection? */ + if (status == 0 && udev->reset_resume + && hub_port_warm_reset_required(hub, port1, portstatus)) { + /* pass */; + } /* Is the device still present? */ - if (status || port_is_suspended(hub, portstatus) || + else if (status || port_is_suspended(hub, portstatus) || !port_is_power_on(hub, portstatus) || !(portstatus & USB_PORT_STAT_CONNECTION)) { if (status >= 0) @@ -4872,7 +4886,7 @@ static void port_event(struct usb_hub *hub, int port1) * Warm reset a USB3 protocol port if it's in * SS.Inactive state. */ - if (hub_port_warm_reset_required(hub, portstatus)) { + if (hub_port_warm_reset_required(hub, port1, portstatus)) { dev_dbg(&port_dev->dev, "do warm reset\n"); if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) || udev->state == USB_STATE_NOTATTACHED) { diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 326308e53961..c77d8778af4b 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -52,6 +52,8 @@ struct usb_hub { unsigned long power_bits[1]; /* ports that are powered */ unsigned long child_usage_bits[1]; /* ports powered on for children */ + unsigned long warm_reset_bits[1]; /* ports requesting warm + reset recovery */ #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ #error event_bits[] is too short! #endif diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index fe1b6d0967e3..cd3f9dc24a06 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -103,16 +103,19 @@ static int usb_port_runtime_resume(struct device *dev) msleep(hub_power_on_good_delay(hub)); if (udev && !retval) { /* - * Attempt to wait for usb hub port to be reconnected in order - * to make the resume procedure successful. The device may have - * disconnected while the port was powered off, so ignore the - * return status. + * Our preference is to simply wait for the port to reconnect, + * as that is the lowest latency method to restart the port. + * However, there are cases where toggling port power results in + * the host port and the device port getting out of sync causing + * a link training live lock. Upon timeout, flag the port as + * needing warm reset recovery (to be performed later by + * usb_port_resume() as requested via usb_wakeup_notification()) */ - retval = hub_port_debounce_be_connected(hub, port1); - if (retval < 0) - dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n", - retval); - retval = 0; + if (hub_port_debounce_be_connected(hub, port1) < 0) { + dev_dbg(&port_dev->dev, "reconnect timeout\n"); + if (hub_is_superspeed(hdev)) + set_bit(port1, hub->warm_reset_bits); + } /* Force the child awake to revalidate after the power loss. */ if (!test_and_set_bit(port1, hub->child_usage_bits)) { From f64c51975dd635eba2a65f258013a95859b3d04a Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 29 May 2014 12:58:52 -0700 Subject: [PATCH 076/211] usb: documentation for usb port power off mechanisms describe the mechanisms for controlling port power policy and discovering the port power state. [oliver]: fixes, clarification of wakeup vs port-power-control [sarah]: wordsmithing [djbw]: updates for peer port changes [alan]: review and fixes Cc: Oliver Neukum Signed-off-by: Lan Tianyu Signed-off-by: Dan Williams Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/power-management.txt | 243 ++++++++++++++++++++++++- 1 file changed, 242 insertions(+), 1 deletion(-) diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt index 1392b61d6ebe..7b90fe034c4b 100644 --- a/Documentation/usb/power-management.txt +++ b/Documentation/usb/power-management.txt @@ -2,9 +2,28 @@ Alan Stern - October 28, 2010 + Last-updated: February 2014 + Contents: + --------- + * What is Power Management? + * What is Remote Wakeup? + * When is a USB device idle? + * Forms of dynamic PM + * The user interface for dynamic PM + * Changing the default idle-delay time + * Warnings + * The driver interface for Power Management + * The driver interface for autosuspend and autoresume + * Other parts of the driver interface + * Mutual exclusion + * Interaction between dynamic PM and system PM + * xHCI hardware link PM + * USB Port Power Control + * User Interface for Port Power Control + * Suggested Userspace Port Power Policy + What is Power Management? ------------------------- @@ -516,3 +535,225 @@ relevant attribute files is usb2_hardware_lpm. driver will enable hardware LPM for the device. You can write y/Y/1 or n/N/0 to the file to enable/disable USB2 hardware LPM manually. This is for test purpose mainly. + + + USB Port Power Control + ---------------------- + +In addition to suspending endpoint devices and enabling hardware +controlled link power management, the USB subsystem also has the +capability to disable power to ports under some conditions. Power is +controlled through Set/ClearPortFeature(PORT_POWER) requests to a hub. +In the case of a root or platform-internal hub the host controller +driver translates PORT_POWER requests into platform firmware (ACPI) +method calls to set the port power state. For more background see the +Linux Plumbers Conference 2012 slides [1] and video [2]: + +Upon receiving a ClearPortFeature(PORT_POWER) request a USB port is +logically off, and may trigger the actual loss of VBUS to the port [3]. +VBUS may be maintained in the case where a hub gangs multiple ports into +a shared power well causing power to remain until all ports in the gang +are turned off. VBUS may also be maintained by hub ports configured for +a charging application. In any event a logically off port will lose +connection with its device, not respond to hotplug events, and not +respond to remote wakeup events*. + +WARNING: turning off a port may result in the inability to hot add a device. +Please see "User Interface for Port Power Control" for details. + +As far as the effect on the device itself it is similar to what a device +goes through during system suspend, i.e. the power session is lost. Any +USB device or driver that misbehaves with system suspend will be +similarly affected by a port power cycle event. For this reason the +implementation shares the same device recovery path (and honors the same +quirks) as the system resume path for the hub. + +[1]: http://dl.dropbox.com/u/96820575/sarah-sharp-lpt-port-power-off2-mini.pdf +[2]: http://linuxplumbers.ubicast.tv/videos/usb-port-power-off-kerneluserspace-api/ +[3]: USB 3.1 Section 10.12 +* wakeup note: if a device is configured to send wakeup events the port + power control implementation will block poweroff attempts on that + port. + + + User Interface for Port Power Control + ------------------------------------- + +The port power control mechanism uses the PM runtime system. Poweroff is +requested by clearing the power/pm_qos_no_power_off flag of the port device +(defaults to 1). If the port is disconnected it will immediately receive a +ClearPortFeature(PORT_POWER) request. Otherwise, it will honor the pm runtime +rules and require the attached child device and all descendants to be suspended. +This mechanism is dependent on the hub advertising port power switching in its +hub descriptor (wHubCharacteristics logical power switching mode field). + +Note, some interface devices/drivers do not support autosuspend. Userspace may +need to unbind the interface drivers before the usb_device will suspend. An +unbound interface device is suspended by default. When unbinding, be careful +to unbind interface drivers, not the driver of the parent usb device. Also, +leave hub interface drivers bound. If the driver for the usb device (not +interface) is unbound the kernel is no longer able to resume the device. If a +hub interface driver is unbound, control of its child ports is lost and all +attached child-devices will disconnect. A good rule of thumb is that if the +'driver/module' link for a device points to /sys/module/usbcore then unbinding +it will interfere with port power control. + +Example of the relevant files for port power control. Note, in this example +these files are relative to a usb hub device (prefix). + + prefix=/sys/devices/pci0000:00/0000:00:14.0/usb3/3-1 + + attached child device + + hub port device + | + hub interface device + | | + v v v + $prefix/3-1:1.0/3-1-port1/device + + $prefix/3-1:1.0/3-1-port1/power/pm_qos_no_power_off + $prefix/3-1:1.0/3-1-port1/device/power/control + $prefix/3-1:1.0/3-1-port1/device/3-1.1:/driver/unbind + $prefix/3-1:1.0/3-1-port1/device/3-1.1:/driver/unbind + ... + $prefix/3-1:1.0/3-1-port1/device/3-1.1:/driver/unbind + +In addition to these files some ports may have a 'peer' link to a port on +another hub. The expectation is that all superspeed ports have a +hi-speed peer. + +$prefix/3-1:1.0/3-1-port1/peer -> ../../../../usb2/2-1/2-1:1.0/2-1-port1 +../../../../usb2/2-1/2-1:1.0/2-1-port1/peer -> ../../../../usb3/3-1/3-1:1.0/3-1-port1 + +Distinct from 'companion ports', or 'ehci/xhci shared switchover ports' +peer ports are simply the hi-speed and superspeed interface pins that +are combined into a single usb3 connector. Peer ports share the same +ancestor XHCI device. + +While a superspeed port is powered off a device may downgrade its +connection and attempt to connect to the hi-speed pins. The +implementation takes steps to prevent this: + +1/ Port suspend is sequenced to guarantee that hi-speed ports are powered-off + before their superspeed peer is permitted to power-off. The implication is + that the setting pm_qos_no_power_off to zero on a superspeed port may not cause + the port to power-off until its highspeed peer has gone to its runtime suspend + state. Userspace must take care to order the suspensions if it wants to + guarantee that a superspeed port will power-off. + +2/ Port resume is sequenced to force a superspeed port to power-on prior to its + highspeed peer. + +3/ Port resume always triggers an attached child device to resume. After a + power session is lost the device may have been removed, or need reset. + Resuming the child device when the parent port regains power resolves those + states and clamps the maximum port power cycle frequency at the rate the child + device can suspend (autosuspend-delay) and resume (reset-resume latency). + +Sysfs files relevant for port power control: + /power/pm_qos_no_power_off: + This writable flag controls the state of an idle port. + Once all children and descendants have suspended the + port may suspend/poweroff provided that + pm_qos_no_power_off is '0'. If pm_qos_no_power_off is + '1' the port will remain active/powered regardless of + the stats of descendants. Defaults to 1. + + /power/runtime_status: + This file reflects whether the port is 'active' (power is on) + or 'suspended' (logically off). There is no indication to + userspace whether VBUS is still supplied. + + /connect_type: + An advisory read-only flag to userspace indicating the + location and connection type of the port. It returns + one of four values 'hotplug', 'hardwired', 'not used', + and 'unknown'. All values, besides unknown, are set by + platform firmware. + + "hotplug" indicates an externally connectable/visible + port on the platform. Typically userspace would choose + to keep such a port powered to handle new device + connection events. + + "hardwired" refers to a port that is not visible but + connectable. Examples are internal ports for USB + bluetooth that can be disconnected via an external + switch or a port with a hardwired USB camera. It is + expected to be safe to allow these ports to suspend + provided pm_qos_no_power_off is coordinated with any + switch that gates connections. Userspace must arrange + for the device to be connected prior to the port + powering off, or to activate the port prior to enabling + connection via a switch. + + "not used" refers to an internal port that is expected + to never have a device connected to it. These may be + empty internal ports, or ports that are not physically + exposed on a platform. Considered safe to be + powered-off at all times. + + "unknown" means platform firmware does not provide + information for this port. Most commonly refers to + external hub ports which should be considered 'hotplug' + for policy decisions. + + NOTE1: since we are relying on the BIOS to get this ACPI + information correct, the USB port descriptions may be + missing or wrong. + + NOTE2: Take care in clearing pm_qos_no_power_off. Once + power is off this port will + not respond to new connect events. + + Once a child device is attached additional constraints are + applied before the port is allowed to poweroff. + + /power/control: + Must be 'auto', and the port will not + power down until /power/runtime_status + reflects the 'suspended' state. Default + value is controlled by child device driver. + + /power/persist: + This defaults to '1' for most devices and indicates if + kernel can persist the device's configuration across a + power session loss (suspend / port-power event). When + this value is '0' (quirky devices), port poweroff is + disabled. + + /driver/unbind: + Wakeup capable devices will block port poweroff. At + this time the only mechanism to clear the usb-internal + wakeup-capability for an interface device is to unbind + its driver. + +Summary of poweroff pre-requisite settings relative to a port device: + + echo 0 > power/pm_qos_no_power_off + echo 0 > peer/power/pm_qos_no_power_off # if it exists + echo auto > power/control # this is the default value + echo auto > /power/control + echo 1 > /power/persist # this is the default value + + Suggested Userspace Port Power Policy + ------------------------------------- + +As noted above userspace needs to be careful and deliberate about what +ports are enabled for poweroff. + +The default configuration is that all ports start with +power/pm_qos_no_power_off set to '1' causing ports to always remain +active. + +Given confidence in the platform firmware's description of the ports +(ACPI _PLD record for a port populates 'connect_type') userspace can +clear pm_qos_no_power_off for all 'not used' ports. The same can be +done for 'hardwired' ports provided poweroff is coordinated with any +connection switch for the port. + +A more aggressive userspace policy is to enable USB port power off for +all ports (set /power/pm_qos_no_power_off to '0') when +some external factor indicates the user has stopped interacting with the +system. For example, a distro may want to enable power off all USB +ports when the screen blanks, and re-power them when the screen becomes +active. Smart phones and tablets may want to power off USB ports when +the user pushes the power button. From f4f8ae0568abf9389cccb2d7be796955b60f891c Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Sat, 31 May 2014 13:03:00 -0300 Subject: [PATCH 077/211] USB: kl5kusb105: Remove klsi_105_tiocmset function This patch remove the function klsi_105_tiocmset which was only returning -EINVAL. It also removes the function prototype and the .tiocmset entry in the struct usb_serial_driver. Verified by compilation only. Signed-off-by: Peter Senna Tschudin Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kl5kusb105.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index d7440b7557af..e020ad28a00c 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -62,8 +62,6 @@ static void klsi_105_close(struct usb_serial_port *port); static void klsi_105_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int klsi_105_tiocmget(struct tty_struct *tty); -static int klsi_105_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); static void klsi_105_process_read_urb(struct urb *urb); static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size); @@ -93,7 +91,6 @@ static struct usb_serial_driver kl5kusb105d_device = { .set_termios = klsi_105_set_termios, /*.break_ctl = klsi_105_break_ctl,*/ .tiocmget = klsi_105_tiocmget, - .tiocmset = klsi_105_tiocmset, .port_probe = klsi_105_port_probe, .port_remove = klsi_105_port_remove, .throttle = usb_serial_generic_throttle, @@ -602,33 +599,6 @@ static int klsi_105_tiocmget(struct tty_struct *tty) return (int)line_state; } -static int klsi_105_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - int retval = -EINVAL; - -/* if this ever gets implemented, it should be done something like this: - struct usb_serial *serial = port->serial; - struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int control; - - spin_lock_irqsave (&priv->lock, flags); - if (set & TIOCM_RTS) - priv->control_state |= TIOCM_RTS; - if (set & TIOCM_DTR) - priv->control_state |= TIOCM_DTR; - if (clear & TIOCM_RTS) - priv->control_state &= ~TIOCM_RTS; - if (clear & TIOCM_DTR) - priv->control_state &= ~TIOCM_DTR; - control = priv->control_state; - spin_unlock_irqrestore (&priv->lock, flags); - retval = mct_u232_set_modem_ctrl(serial, control); -*/ - return retval; -} - module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); From 288c0f44eb5535fe367ac70c5772b5f0404bf74f Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 2 Jun 2014 15:25:17 +0200 Subject: [PATCH 078/211] xhci: make error messages grepable grep must work, not matter the line length. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index b04fef1e4ff8..0342d9b63977 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1804,15 +1804,15 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, ret = -ETIME; break; case COMP_ENOMEM: - dev_warn(&udev->dev, "Not enough host controller resources " - "for new device state.\n"); + dev_warn(&udev->dev, + "Not enough host controller resources for new device state.\n"); ret = -ENOMEM; /* FIXME: can we allocate more resources for the HC? */ break; case COMP_BW_ERR: case COMP_2ND_BW_ERR: - dev_warn(&udev->dev, "Not enough bandwidth " - "for new device state.\n"); + dev_warn(&udev->dev, + "Not enough bandwidth for new device state.\n"); ret = -ENOSPC; /* FIXME: can we go back to the old state? */ break; @@ -1824,8 +1824,8 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, ret = -EINVAL; break; case COMP_DEV_ERR: - dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint " - "configure command.\n"); + dev_warn(&udev->dev, + "ERROR: Incompatible device for endpoint configure command.\n"); ret = -ENODEV; break; case COMP_SUCCESS: @@ -1834,8 +1834,8 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, ret = 0; break; default: - xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", *cmd_status); + xhci_err(xhci, "ERROR: unexpected command completion code 0x%x.\n", + *cmd_status); ret = -EINVAL; break; } @@ -1855,24 +1855,24 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, ret = -ETIME; break; case COMP_EINVAL: - dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate " - "context command.\n"); + dev_warn(&udev->dev, + "WARN: xHCI driver setup invalid evaluate context command.\n"); ret = -EINVAL; break; case COMP_EBADSLT: - dev_warn(&udev->dev, "WARN: slot not enabled for" - "evaluate context command.\n"); + dev_warn(&udev->dev, + "WARN: slot not enabled for evaluate context command.\n"); ret = -EINVAL; break; case COMP_CTX_STATE: - dev_warn(&udev->dev, "WARN: invalid context state for " - "evaluate context command.\n"); + dev_warn(&udev->dev, + "WARN: invalid context state for evaluate context command.\n"); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); ret = -EINVAL; break; case COMP_DEV_ERR: - dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate " - "context command.\n"); + dev_warn(&udev->dev, + "ERROR: Incompatible device for evaluate context command.\n"); ret = -ENODEV; break; case COMP_MEL_ERR: @@ -1886,8 +1886,8 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, ret = 0; break; default: - xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", *cmd_status); + xhci_err(xhci, "ERROR: unexpected command completion code 0x%x.\n", + *cmd_status); ret = -EINVAL; break; } From fd666348c51f6ab66410c98a149e0418b9a258f0 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 20 Jun 2014 23:11:23 +0530 Subject: [PATCH 079/211] usb: host: xhci-plat: use devm_functions This patch introduces the use of managed interface devm_ioremap_resource for ioremap_nocache and request_mem_region and removes the corresponding free functions in the probe and remove functions. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Reviewed-by: Felipe Balbi Acked-by: Felipe Balbi Cc: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index b17459d3fcc8..794219d8d2a9 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -146,20 +146,12 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - ret = -EBUSY; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); goto put_hcd; } - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -EFAULT; - goto release_mem_region; - } - /* * Not all platforms have a clk so it is not an error if the * clock does not exists. @@ -168,7 +160,7 @@ static int xhci_plat_probe(struct platform_device *pdev) if (!IS_ERR(clk)) { ret = clk_prepare_enable(clk); if (ret) - goto unmap_registers; + goto put_hcd; } ret = usb_add_hcd(hcd, irq, IRQF_SHARED); @@ -216,12 +208,6 @@ static int xhci_plat_probe(struct platform_device *pdev) if (!IS_ERR(clk)) clk_disable_unprepare(clk); -unmap_registers: - iounmap(hcd->regs); - -release_mem_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - put_hcd: usb_put_hcd(hcd); @@ -240,8 +226,6 @@ static int xhci_plat_remove(struct platform_device *dev) usb_remove_hcd(hcd); if (!IS_ERR(clk)) clk_disable_unprepare(clk); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); kfree(xhci); From 4ac8918f3a737c21d81e250e4194c12ea2b7eb04 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 9 Jul 2014 10:08:52 +0900 Subject: [PATCH 080/211] usb: host: xhci-plat: add support for the R-Car H2 and M2 xHCI controllers The R-Car H2 and M2 SoCs come with an xHCI controller that requires some specific initializations related to the firmware downloading and some specific registers. This patch adds the support for this special configuration as an xHCI quirk executed during probe and start. Signed-off-by: Yoshihiro Shimoda Cc: "mathias.nyman@intel.com" Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 8 ++ drivers/usb/host/Makefile | 3 + drivers/usb/host/xhci-plat.c | 19 +++++ drivers/usb/host/xhci-rcar.c | 148 +++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci-rcar.h | 27 +++++++ 5 files changed, 205 insertions(+) create mode 100644 drivers/usb/host/xhci-rcar.c create mode 100644 drivers/usb/host/xhci-rcar.h diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 03314f861bee..82800a775501 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -37,6 +37,14 @@ config USB_XHCI_MVEBU Say 'Y' to enable the support for the xHCI host controller found in Marvell Armada 375/38x ARM SOCs. +config USB_XHCI_RCAR + tristate "xHCI support for Renesas R-Car SoCs" + select USB_XHCI_PLATFORM + depends on ARCH_SHMOBILE || COMPILE_TEST + ---help--- + Say 'Y' to enable the support for the xHCI host controller + found in Renesas R-Car ARM SoCs. + endif # USB_XHCI_HCD config USB_EHCI_HCD diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index af89a903d97e..144c038ef70f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -22,6 +22,9 @@ ifneq ($(CONFIG_USB_XHCI_PLATFORM), ) ifneq ($(CONFIG_USB_XHCI_MVEBU), ) xhci-hcd-y += xhci-mvebu.o endif +ifneq ($(CONFIG_USB_XHCI_RCAR), ) + xhci-hcd-y += xhci-rcar.o +endif endif obj-$(CONFIG_USB_WHCI_HCD) += whci/ diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 794219d8d2a9..1a0cf9f31e43 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -21,6 +21,7 @@ #include "xhci.h" #include "xhci-mvebu.h" +#include "xhci-rcar.h" static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { @@ -35,11 +36,27 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) /* called during probe() after chip reset completes */ static int xhci_plat_setup(struct usb_hcd *hcd) { + struct device_node *of_node = hcd->self.controller->of_node; + int ret; + + if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") || + of_device_is_compatible(of_node, "renesas,xhci-r8a7791")) { + ret = xhci_rcar_init_quirk(hcd); + if (ret) + return ret; + } + return xhci_gen_setup(hcd, xhci_plat_quirks); } static int xhci_plat_start(struct usb_hcd *hcd) { + struct device_node *of_node = hcd->self.controller->of_node; + + if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") || + of_device_is_compatible(of_node, "renesas,xhci-r8a7791")) + xhci_rcar_start(hcd); + return xhci_run(hcd); } @@ -263,6 +280,8 @@ static const struct of_device_id usb_xhci_of_match[] = { { .compatible = "xhci-platform" }, { .compatible = "marvell,armada-375-xhci"}, { .compatible = "marvell,armada-380-xhci"}, + { .compatible = "renesas,xhci-r8a7790"}, + { .compatible = "renesas,xhci-r8a7791"}, { }, }; MODULE_DEVICE_TABLE(of, usb_xhci_of_match); diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c new file mode 100644 index 000000000000..ff0d1b44ea58 --- /dev/null +++ b/drivers/usb/host/xhci-rcar.c @@ -0,0 +1,148 @@ +/* + * xHCI host controller driver for R-Car SoCs + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "xhci.h" +#include "xhci-rcar.h" + +#define FIRMWARE_NAME "r8a779x_usb3_v1.dlmem" +MODULE_FIRMWARE(FIRMWARE_NAME); + +/*** Register Offset ***/ +#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */ +#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */ +#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */ + +#define RCAR_USB3_LCLK 0xa44 /* LCLK Select */ +#define RCAR_USB3_CONF1 0xa48 /* USB3.0 Configuration1 */ +#define RCAR_USB3_CONF2 0xa5c /* USB3.0 Configuration2 */ +#define RCAR_USB3_CONF3 0xaa8 /* USB3.0 Configuration3 */ +#define RCAR_USB3_RX_POL 0xab0 /* USB3.0 RX Polarity */ +#define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */ + +/*** Register Settings ***/ +/* Interrupt Enable */ +#define RCAR_USB3_INT_XHC_ENA 0x00000001 +#define RCAR_USB3_INT_PME_ENA 0x00000002 +#define RCAR_USB3_INT_HSE_ENA 0x00000004 +#define RCAR_USB3_INT_ENA_VAL (RCAR_USB3_INT_XHC_ENA | \ + RCAR_USB3_INT_PME_ENA | RCAR_USB3_INT_HSE_ENA) + +/* FW Download Control & Status */ +#define RCAR_USB3_DL_CTRL_ENABLE 0x00000001 +#define RCAR_USB3_DL_CTRL_FW_SUCCESS 0x00000010 +#define RCAR_USB3_DL_CTRL_FW_SET_DATA0 0x00000100 + +/* LCLK Select */ +#define RCAR_USB3_LCLK_ENA_VAL 0x01030001 + +/* USB3.0 Configuration */ +#define RCAR_USB3_CONF1_VAL 0x00030204 +#define RCAR_USB3_CONF2_VAL 0x00030300 +#define RCAR_USB3_CONF3_VAL 0x13802007 + +/* USB3.0 Polarity */ +#define RCAR_USB3_RX_POL_VAL BIT(21) +#define RCAR_USB3_TX_POL_VAL BIT(4) + +void xhci_rcar_start(struct usb_hcd *hcd) +{ + u32 temp; + + if (hcd->regs != NULL) { + /* Interrupt Enable */ + temp = readl(hcd->regs + RCAR_USB3_INT_ENA); + temp |= RCAR_USB3_INT_ENA_VAL; + writel(temp, hcd->regs + RCAR_USB3_INT_ENA); + /* LCLK Select */ + writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK); + /* USB3.0 Configuration */ + writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1); + writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2); + writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3); + /* USB3.0 Polarity */ + writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL); + writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL); + } +} + +static int xhci_rcar_download_firmware(struct device *dev, void __iomem *regs) +{ + const struct firmware *fw; + int retval, index, j, time; + int timeout = 10000; + u32 data, val, temp; + + /* request R-Car USB3.0 firmware */ + retval = request_firmware(&fw, FIRMWARE_NAME, dev); + if (retval) + return retval; + + /* download R-Car USB3.0 firmware */ + temp = readl(regs + RCAR_USB3_DL_CTRL); + temp |= RCAR_USB3_DL_CTRL_ENABLE; + writel(temp, regs + RCAR_USB3_DL_CTRL); + + for (index = 0; index < fw->size; index += 4) { + /* to avoid reading beyond the end of the buffer */ + for (data = 0, j = 3; j >= 0; j--) { + if ((j + index) < fw->size) + data |= fw->data[index + j] << (8 * j); + } + writel(data, regs + RCAR_USB3_FW_DATA0); + temp = readl(regs + RCAR_USB3_DL_CTRL); + temp |= RCAR_USB3_DL_CTRL_FW_SET_DATA0; + writel(temp, regs + RCAR_USB3_DL_CTRL); + + for (time = 0; time < timeout; time++) { + val = readl(regs + RCAR_USB3_DL_CTRL); + if ((val & RCAR_USB3_DL_CTRL_FW_SET_DATA0) == 0) + break; + udelay(1); + } + if (time == timeout) { + retval = -ETIMEDOUT; + break; + } + } + + temp = readl(regs + RCAR_USB3_DL_CTRL); + temp &= ~RCAR_USB3_DL_CTRL_ENABLE; + writel(temp, regs + RCAR_USB3_DL_CTRL); + + for (time = 0; time < timeout; time++) { + val = readl(regs + RCAR_USB3_DL_CTRL); + if (val & RCAR_USB3_DL_CTRL_FW_SUCCESS) { + retval = 0; + break; + } + udelay(1); + } + if (time == timeout) + retval = -ETIMEDOUT; + + release_firmware(fw); + + return retval; +} + +/* This function needs to initialize a "phy" of usb before */ +int xhci_rcar_init_quirk(struct usb_hcd *hcd) +{ + /* If hcd->regs is NULL, we don't just call the following function */ + if (!hcd->regs) + return 0; + + return xhci_rcar_download_firmware(hcd->self.controller, hcd->regs); +} diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h new file mode 100644 index 000000000000..58501256715d --- /dev/null +++ b/drivers/usb/host/xhci-rcar.h @@ -0,0 +1,27 @@ +/* + * drivers/usb/host/xhci-rcar.h + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef _XHCI_RCAR_H +#define _XHCI_RCAR_H + +#if IS_ENABLED(CONFIG_USB_XHCI_RCAR) +void xhci_rcar_start(struct usb_hcd *hcd); +int xhci_rcar_init_quirk(struct usb_hcd *hcd); +#else +static inline void xhci_rcar_start(struct usb_hcd *hcd) +{ +} + +static inline int xhci_rcar_init_quirk(struct usb_hcd *hcd) +{ + return 0; +} +#endif +#endif /* _XHCI_RCAR_H */ From e9ebe7c3b76c24fd5bc2f3b99db453ea71c3072b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 3 Jun 2014 22:14:56 +0900 Subject: [PATCH 081/211] usb: dwc2: gadget: fix checkpatch errors Fix checkpatch errors as belows. ERROR: open brace '{' following function declarations go on the next line ERROR: space required before the open parenthesis '(' Signed-off-by: Jingoo Han Acked-by: Paul Zimmerman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/gadget.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index f3c56a2fed5b..df432726333a 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1022,7 +1022,8 @@ static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg); * * Set stall for ep0 as response for setup request. */ -static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) { +static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) +{ struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; u32 reg; u32 ctrl; @@ -1994,7 +1995,7 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, s3c_hsotg_complete_request(hsotg, ep, req, result); } - if(hsotg->dedicated_fifos) + if (hsotg->dedicated_fifos) if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072) s3c_hsotg_txfifo_flush(hsotg, ep->index); } From d04477d84be0bcac96452bdb824ff6eec4b49c96 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 3 Jun 2014 22:15:56 +0900 Subject: [PATCH 082/211] usb: dwc2: gadget: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Paul Zimmerman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/gadget.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index df432726333a..73df48a6cc22 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3391,10 +3391,8 @@ static int s3c_hsotg_probe(struct platform_device *pdev) int i; hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL); - if (!hsotg) { - dev_err(dev, "cannot get memory\n"); + if (!hsotg) return -ENOMEM; - } /* * Attempt to find a generic PHY, then look for an old style @@ -3513,7 +3511,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev) eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep), GFP_KERNEL); if (!eps) { - dev_err(dev, "cannot get memory\n"); ret = -ENOMEM; goto err_supplies; } From 53dbcb399b22dad14becb2557a1ebea258ac266d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 3 Jun 2014 22:16:29 +0900 Subject: [PATCH 083/211] usb: dwc2: gadget: remove incorrect file reference The file and folder movements resulted in the incorrect reference. So for better code maintainability, let's remove it. Signed-off-by: Jingoo Han Acked-by: Paul Zimmerman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/gadget.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 73df48a6cc22..0ba9c335b584 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1,6 +1,4 @@ /** - * linux/drivers/usb/gadget/s3c-hsotg.c - * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * From ab53eb97369a4fb19c3ba7b827b949c1015bc948 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 1 Jun 2014 15:43:19 +0200 Subject: [PATCH 084/211] usb: class: usbtmc.c: Cleaning up uninitialized variables There is a risk that the variable will be used without being initialized. This was largely found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 103a6e9ee49d..ec978408a2ee 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -715,7 +715,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) u8 *buffer; int rv; int n; - int actual; + int actual = 0; int max_size; dev = &data->intf->dev; From 473e92e69e3dcdb16b48573374b11b958a7985ed Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 6 Jun 2014 14:13:44 +0530 Subject: [PATCH 085/211] usb: ohci-exynos: Use NULL instead of 0 The third argument of devm_of_phy_get expects a pointer. Hence use NULL instead of 0. Signed-off-by: Sachin Kamat Acked-by: Jingoo Han Reviewed-by: Vivek Gautam Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-exynos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 060a6a414750..a72ab8fe8cd3 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -87,7 +87,7 @@ static int exynos_ohci_get_phy(struct device *dev, return -EINVAL; } - phy = devm_of_phy_get(dev, child, 0); + phy = devm_of_phy_get(dev, child, NULL); of_node_put(child); if (IS_ERR(phy)) { ret = PTR_ERR(phy); From 14ad5a94cbf49399e3bc5262428df07f7c3a75c7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 6 Jun 2014 14:13:45 +0530 Subject: [PATCH 086/211] usb: ehci-exynos: Use NULL instead of 0 The third argument of devm_of_phy_get expects a pointer. Hence use NULL instead of 0. Fixes the following warning: drivers/usb/host/ehci-exynos.c:91:51: warning: Using plain integer as NULL pointer Signed-off-by: Sachin Kamat Acked-by: Jingoo Han Reviewed-by: Vivek Gautam Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-exynos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index d1c76216350f..cda0a2f5c467 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -88,7 +88,7 @@ static int exynos_ehci_get_phy(struct device *dev, return -EINVAL; } - phy = devm_of_phy_get(dev, child, 0); + phy = devm_of_phy_get(dev, child, NULL); of_node_put(child); if (IS_ERR(phy)) { ret = PTR_ERR(phy); From 31e01f0aca3e9b77fea0b1c1b569b02fa2812eb6 Mon Sep 17 00:00:00 2001 From: Jeremiah Mahler Date: Fri, 6 Jun 2014 12:29:17 -0700 Subject: [PATCH 087/211] usb: doc: hotplug.txt code typos Fixed several typos in the code examples given in Documentation/usb/hotplug.txt. - missing [] with array of struct usb_device_id - checkpatch.pl warning: space between function name and parenthesis - missing terminating ';' Signed-off-by: Jeremiah Mahler Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/hotplug.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/usb/hotplug.txt b/Documentation/usb/hotplug.txt index 6424b130485c..a80b0e9a7a0b 100644 --- a/Documentation/usb/hotplug.txt +++ b/Documentation/usb/hotplug.txt @@ -105,13 +105,13 @@ macros such as these, and use driver_info to store more information. A short example, for a driver that supports several specific USB devices and their quirks, might have a MODULE_DEVICE_TABLE like this: - static const struct usb_device_id mydriver_id_table = { + static const struct usb_device_id mydriver_id_table[] = { { USB_DEVICE (0x9999, 0xaaaa), driver_info: QUIRK_X }, { USB_DEVICE (0xbbbb, 0x8888), driver_info: QUIRK_Y|QUIRK_Z }, ... { } /* end with an all-zeroes entry */ - } - MODULE_DEVICE_TABLE (usb, mydriver_id_table); + }; + MODULE_DEVICE_TABLE(usb, mydriver_id_table); Most USB device drivers should pass these tables to the USB subsystem as well as to the module management subsystem. Not all, though: some driver @@ -134,7 +134,7 @@ something like this: if exposing any operations through usbdevfs: .ioctl = my_ioctl, */ - } + }; When the USB subsystem knows about a driver's device ID table, it's used when choosing drivers to probe(). The thread doing new device processing checks From f6d9d89f8672dcc1c1474c8d8ba3a0f0a0e375c4 Mon Sep 17 00:00:00 2001 From: Mickael Maison Date: Sat, 7 Jun 2014 13:30:51 +0200 Subject: [PATCH 088/211] USB: gadget: Fixed a few typos in comments Signed-off-by: Mickael Maison Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/mv_udc_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index fcff3a571b45..040fb169b162 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -332,7 +332,7 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req) /* clear active and halt bit, in case set from a previous error */ dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); - /* Ensure that updates to the QH will occure before priming. */ + /* Ensure that updates to the QH will occur before priming. */ wmb(); /* Prime the Endpoint */ @@ -1656,7 +1656,7 @@ static void handle_setup_packet(struct mv_udc *udc, u8 ep_num, dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", setup->bRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); - /* We process some stardard setup requests here */ + /* We process some standard setup requests here */ if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (setup->bRequest) { case USB_REQ_GET_STATUS: From 2eb5dbdd1263a4f014d53501e01b896ac71d3c82 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Thu, 19 Jun 2014 12:56:53 -0600 Subject: [PATCH 089/211] usb: host: max3421-hcd: Use atomic bitops in lieu of bit fields Bit fields are not MP-safe. Signed-off-by: David Mosberger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 45 +++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 858efcfda50b..f8ecd7d7212d 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -102,6 +102,15 @@ enum scheduling_pass { SCHED_PASS_DONE }; +/* Bit numbers for max3421_hcd->todo: */ +enum { + ENABLE_IRQ = 0, + RESET_HCD, + RESET_PORT, + CHECK_UNLINK, + IOPIN_UPDATE +}; + struct max3421_dma_buf { u8 data[2]; }; @@ -146,11 +155,7 @@ struct max3421_hcd { u8 hien; u8 mode; u8 iopins[2]; - unsigned int do_enable_irq:1; - unsigned int do_reset_hcd:1; - unsigned int do_reset_port:1; - unsigned int do_check_unlink:1; - unsigned int do_iopin_update:1; + unsigned long todo; #ifdef DEBUG unsigned long err_stat[16]; #endif @@ -1165,10 +1170,8 @@ max3421_irq_handler(int irq, void *dev_id) if (max3421_hcd->spi_thread && max3421_hcd->spi_thread->state != TASK_RUNNING) wake_up_process(max3421_hcd->spi_thread); - if (!max3421_hcd->do_enable_irq) { - max3421_hcd->do_enable_irq = 1; + if (!test_and_set_bit(ENABLE_IRQ, &max3421_hcd->todo)) disable_irq_nosync(spi->irq); - } return IRQ_HANDLED; } @@ -1423,10 +1426,8 @@ max3421_spi_thread(void *dev_id) spi_wr8(hcd, MAX3421_REG_HIEN, max3421_hcd->hien); set_current_state(TASK_INTERRUPTIBLE); - if (max3421_hcd->do_enable_irq) { - max3421_hcd->do_enable_irq = 0; + if (test_and_clear_bit(ENABLE_IRQ, &max3421_hcd->todo)) enable_irq(spi->irq); - } schedule(); __set_current_state(TASK_RUNNING); } @@ -1440,23 +1441,18 @@ max3421_spi_thread(void *dev_id) else if (!max3421_hcd->curr_urb) i_worked |= max3421_select_and_start_urb(hcd); - if (max3421_hcd->do_reset_hcd) { + if (test_and_clear_bit(RESET_HCD, &max3421_hcd->todo)) /* reset the HCD: */ - max3421_hcd->do_reset_hcd = 0; i_worked |= max3421_reset_hcd(hcd); - } - if (max3421_hcd->do_reset_port) { + if (test_and_clear_bit(RESET_PORT, &max3421_hcd->todo)) { /* perform a USB bus reset: */ - max3421_hcd->do_reset_port = 0; spi_wr8(hcd, MAX3421_REG_HCTL, BIT(MAX3421_HCTL_BUSRST_BIT)); i_worked = 1; } - if (max3421_hcd->do_check_unlink) { - max3421_hcd->do_check_unlink = 0; + if (test_and_clear_bit(CHECK_UNLINK, &max3421_hcd->todo)) i_worked |= max3421_check_unlink(hcd); - } - if (max3421_hcd->do_iopin_update) { + if (test_and_clear_bit(IOPIN_UPDATE, &max3421_hcd->todo)) { /* * IOPINS1/IOPINS2 do not auto-increment, so we can't * use spi_wr_buf(). @@ -1469,7 +1465,6 @@ max3421_spi_thread(void *dev_id) spi_wr8(hcd, MAX3421_REG_IOPINS1 + i, val); max3421_hcd->iopins[i] = val; } - max3421_hcd->do_iopin_update = 0; i_worked = 1; } } @@ -1485,7 +1480,7 @@ max3421_reset_port(struct usb_hcd *hcd) max3421_hcd->port_status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED); - max3421_hcd->do_reset_port = 1; + set_bit(RESET_PORT, &max3421_hcd->todo); wake_up_process(max3421_hcd->spi_thread); return 0; } @@ -1498,7 +1493,7 @@ max3421_reset(struct usb_hcd *hcd) hcd->self.sg_tablesize = 0; hcd->speed = HCD_USB2; hcd->self.root_hub->speed = USB_SPEED_FULL; - max3421_hcd->do_reset_hcd = 1; + set_bit(RESET_HCD, &max3421_hcd->todo); wake_up_process(max3421_hcd->spi_thread); return 0; } @@ -1590,7 +1585,7 @@ max3421_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) */ retval = usb_hcd_check_unlink_urb(hcd, urb, status); if (retval == 0) { - max3421_hcd->do_check_unlink = 1; + set_bit(CHECK_UNLINK, &max3421_hcd->todo); wake_up_process(max3421_hcd->spi_thread); } spin_unlock_irqrestore(&max3421_hcd->lock, flags); @@ -1690,7 +1685,7 @@ max3421_gpout_set_value(struct usb_hcd *hcd, u8 pin_number, u8 value) max3421_hcd->iopins[idx] |= mask; else max3421_hcd->iopins[idx] &= ~mask; - max3421_hcd->do_iopin_update = 1; + set_bit(IOPIN_UPDATE, &max3421_hcd->todo); wake_up_process(max3421_hcd->spi_thread); } From a2b63cb52ff1088fd4c3f7ee883d6a247571a70c Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Thu, 19 Jun 2014 12:57:28 -0600 Subject: [PATCH 090/211] usb: host: max3421-hcd: Fix max3421_reset_port() to set USB_PORT_STAT_RESET Signed-off-by: David Mosberger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index f8ecd7d7212d..6dbf1e9c137c 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1480,6 +1480,7 @@ max3421_reset_port(struct usb_hcd *hcd) max3421_hcd->port_status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED); + max3421_hcd->port_status |= USB_PORT_STAT_RESET; set_bit(RESET_PORT, &max3421_hcd->todo); wake_up_process(max3421_hcd->spi_thread); return 0; From 6c0f36954b9bcfedb87d785aa453132146645abc Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Thu, 19 Jun 2014 23:44:57 +0400 Subject: [PATCH 091/211] usb: host: max3421-hcd: unconditionally use GFP_ATOMIC in max3421_urb_enqueue() As far as kzalloc() is called with spinlock held, we have to pass GFP_ATOMIC regardless of mem_flags argument. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: David Mosberger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 6dbf1e9c137c..6234c75da33f 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1547,7 +1547,7 @@ max3421_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) max3421_ep = urb->ep->hcpriv; if (!max3421_ep) { /* gets freed in max3421_endpoint_disable: */ - max3421_ep = kzalloc(sizeof(struct max3421_ep), mem_flags); + max3421_ep = kzalloc(sizeof(struct max3421_ep), GFP_ATOMIC); if (!max3421_ep) { retval = -ENOMEM; goto out; From cc583db3d708886ef89bce9d686419c58400182c Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 2 Jul 2014 12:10:45 +0200 Subject: [PATCH 092/211] Documentation: sysfs-bus-usb: update power/persist description There's no power/persist file for hubs. And CONFIG_USB_PERSIST was removed in v2.6.26. Update the description of power/persist accordingly. Also remove the line on its default value. It is not entirely correct, as CONFIG_USB_DEFAULT_PERSIST and the USB_QUIRK_RESET flag influence the default. It is not needed to understand this file anyhow. Signed-off-by: Paul Bolle Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-bus-usb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-bus-usb b/Documentation/ABI/stable/sysfs-bus-usb index a6b685724740..e2bc700a6f9c 100644 --- a/Documentation/ABI/stable/sysfs-bus-usb +++ b/Documentation/ABI/stable/sysfs-bus-usb @@ -3,13 +3,13 @@ Date: May 2007 KernelVersion: 2.6.23 Contact: Alan Stern Description: - If CONFIG_USB_PERSIST is set, then each USB device directory - will contain a file named power/persist. The file holds a - boolean value (0 or 1) indicating whether or not the - "USB-Persist" facility is enabled for the device. Since the - facility is inherently dangerous, it is disabled by default - for all devices except hubs. For more information, see - Documentation/usb/persist.txt. + USB device directories can contain a file named power/persist. + The file holds a boolean value (0 or 1) indicating whether or + not the "USB-Persist" facility is enabled for the device. For + hubs this facility is always enabled and their device + directories will not contain this file. + + For more information, see Documentation/usb/persist.txt. What: /sys/bus/usb/devices/.../power/autosuspend Date: March 2007 From 2097937467a5f6c93fd4a16fff0db2b6c475c85d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 7 Jul 2014 14:06:35 +0200 Subject: [PATCH 093/211] usb: phy: tegra: Do not include asm/mach-types.h It is no longer needed and keeping it will break 64-bit ARM builds. Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-tegra-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index bbe4f8e6e8d7..467a5e152afa 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include From 8968614a8ca52f2ea855eccf7b2df66cb34c154d Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 29 Jun 2014 12:37:44 +0530 Subject: [PATCH 094/211] USB: oxu210hp-hcd.c: use devm_ functions This patch introduces the use of devm_ioremap_resource instead of request_mem_region and ioremap. The error handling on platform_get_resource and the error message for ioremap are removed. The function devm_kzalloc replaces memory allocation by unmanaged kzalloc. The function calls to free the allocated memory in the probe and remove functions are done away with. Some labels are removed and a label error is added to make is less specific to the context. The debug message is removed as devm_ioremap generates debug messages of its own. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/oxu210hp-hcd.c | 48 +++++++-------------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index e07248b6ab67..da5fb0e3c363 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3826,49 +3826,36 @@ static int oxu_drv_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "IRQ resource %d\n", irq); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no registers address! Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto error; } memstart = res->start; memlen = resource_size(res); - dev_dbg(&pdev->dev, "MEM resource %lx-%lx\n", memstart, memlen); - if (!request_mem_region(memstart, memlen, - oxu_hc_driver.description)) { - dev_dbg(&pdev->dev, "memory area already in use\n"); - return -EBUSY; - } ret = irq_set_irq_type(irq, IRQF_TRIGGER_FALLING); if (ret) { dev_err(&pdev->dev, "error setting irq type\n"); ret = -EFAULT; - goto error_set_irq_type; - } - - base = ioremap(memstart, memlen); - if (!base) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -EFAULT; - goto error_ioremap; + goto error; } /* Allocate a driver data struct to hold useful info for both * SPH & OTG devices */ - info = kzalloc(sizeof(struct oxu_info), GFP_KERNEL); + info = devm_kzalloc(&pdev->dev, sizeof(struct oxu_info), GFP_KERNEL); if (!info) { dev_dbg(&pdev->dev, "error allocating memory\n"); ret = -EFAULT; - goto error_alloc; + goto error; } platform_set_drvdata(pdev, info); ret = oxu_init(pdev, memstart, memlen, base, irq); if (ret < 0) { dev_dbg(&pdev->dev, "cannot init USB devices\n"); - goto error_init; + goto error; } dev_info(&pdev->dev, "devices enabled and running\n"); @@ -3876,16 +3863,7 @@ static int oxu_drv_probe(struct platform_device *pdev) return 0; -error_init: - kfree(info); - -error_alloc: - iounmap(base); - -error_set_irq_type: -error_ioremap: - release_mem_region(memstart, memlen); - +error: dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret); return ret; } @@ -3899,18 +3877,10 @@ static void oxu_remove(struct platform_device *pdev, struct usb_hcd *hcd) static int oxu_drv_remove(struct platform_device *pdev) { struct oxu_info *info = platform_get_drvdata(pdev); - unsigned long memstart = info->hcd[0]->rsrc_start, - memlen = info->hcd[0]->rsrc_len; - void *base = info->hcd[0]->regs; oxu_remove(pdev, info->hcd[0]); oxu_remove(pdev, info->hcd[1]); - iounmap(base); - release_mem_region(memstart, memlen); - - kfree(info); - return 0; } From 3587fb3ba05efd920da1395c2437cd40f9c7d1b4 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:33:17 +0900 Subject: [PATCH 095/211] USB: ehci-msm: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-msm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 982c09bebe0f..934b39d5e44a 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -190,7 +190,7 @@ static const struct dev_pm_ops ehci_msm_dev_pm_ops = { .resume = ehci_msm_pm_resume, }; -static struct of_device_id msm_ehci_dt_match[] = { +static const struct of_device_id msm_ehci_dt_match[] = { { .compatible = "qcom,ehci-host", }, {} }; From 10e15d6d903b138ea6340107227d4ec311391343 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:38:10 +0900 Subject: [PATCH 096/211] USB: ohci-spear: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Acked-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-spear.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 8b29a0c04c23..8d5876692e7c 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -162,7 +162,7 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev) } #endif -static struct of_device_id spear_ohci_id_table[] = { +static const struct of_device_id spear_ohci_id_table[] = { { .compatible = "st,spear600-ohci", }, { }, }; From 1b45049a37a67912ac15b7ae07ad1a095de2f669 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:37:24 +0900 Subject: [PATCH 097/211] USB: ehci-tegra: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 6fdcb8ad2296..c303371f67bc 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -326,7 +326,7 @@ static const struct tegra_ehci_soc_config tegra20_soc_config = { .has_hostpc = false, }; -static struct of_device_id tegra_ehci_of_match[] = { +static const struct of_device_id tegra_ehci_of_match[] = { { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config }, { .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config }, { }, From 3632eba532fce0651f69d605177b53ff8d91d91e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 18 Jun 2014 13:35:41 +0900 Subject: [PATCH 098/211] USB: ehci-spear: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Acked-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-spear.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 1d59958ad0ce..1355ff0946b9 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -150,7 +150,7 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev) return 0; } -static struct of_device_id spear_ehci_id_table[] = { +static const struct of_device_id spear_ehci_id_table[] = { { .compatible = "st,spear600-ehci", }, { }, }; From 64024d9f2af45552b93d9d07d0119fe1855ca45f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Thu, 26 Jun 2014 19:18:38 +0200 Subject: [PATCH 099/211] drivers/usb/host/fhci-dbg.c: remove unnecessary null test before debugfs_remove This fixes checkpatch warning: "WARNING: debugfs_remove(NULL) is safe this check is probably not required" Signed-off-by: Fabian Frederick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fhci-dbg.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c index f238cb37305c..b58e7a60913a 100644 --- a/drivers/usb/host/fhci-dbg.c +++ b/drivers/usb/host/fhci-dbg.c @@ -129,11 +129,7 @@ void fhci_dfs_destroy(struct fhci_hcd *fhci) if (!fhci->dfs_root) return; - if (fhci->dfs_irq_stat) - debugfs_remove(fhci->dfs_irq_stat); - - if (fhci->dfs_regs) - debugfs_remove(fhci->dfs_regs); - + debugfs_remove(fhci->dfs_irq_stat); + debugfs_remove(fhci->dfs_regs); debugfs_remove(fhci->dfs_root); } From 47c6ae7cdc4dc0c72686cca1819c7368bef2e1bf Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 3 Jul 2014 17:53:30 +0300 Subject: [PATCH 100/211] USB: EHCI: don't allocate hardware periodic table atomically by default ehci_mem_init() is executed one time during ehci_init() and by default all memory allocations but ehci->periodic are done not atomically, GFP_KERNEL is passed as flags parameter. Do similar allocation for ehci->periodic and free some space in coherent atomic DMA pool by default. Signed-off-by: Vladimir Zapolskiy Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index c0fb6a8ae6a3..b6205fac3567 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -209,7 +209,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) ehci->periodic = (__le32 *) dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller, ehci->periodic_size * sizeof(__le32), - &ehci->periodic_dma, 0); + &ehci->periodic_dma, flags); if (ehci->periodic == NULL) { goto fail; } From f589b3e0408ccebfac98f6c2eb38d445a9423e7c Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 3 Jul 2014 21:37:42 +0300 Subject: [PATCH 101/211] USB: UHCI: don't allocate frame list atomically uhci_start() is executed one time during usb_add_hcd() call and by default UHCI frame list is allocated from atomic DMA pool. Do non-atomic allocation of uhci->frame and free some space in coherent atomic DMA pool. Signed-off-by: Vladimir Zapolskiy Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 27f35e8f161b..a7de8e8bb458 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -591,7 +591,7 @@ static int uhci_start(struct usb_hcd *hcd) uhci->frame = dma_alloc_coherent(uhci_dev(uhci), UHCI_NUMFRAMES * sizeof(*uhci->frame), - &uhci->frame_dma_handle, 0); + &uhci->frame_dma_handle, GFP_KERNEL); if (!uhci->frame) { dev_err(uhci_dev(uhci), "unable to allocate consistent memory for frame list\n"); From 4428524d8d01afae18844e73f330d2e8431f312e Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 3 Jul 2014 21:37:41 +0300 Subject: [PATCH 102/211] USB: OHCI: don't allocate HCCA atomically OHCI HCCA memory region is allocated from atomic DMA pool one time during usb_add_hcd() and deallocated by usb_remove_hcd(). Do non-atomic allocation of OHCI HCCA and free some space in coherent atomic DMA pool. Signed-off-by: Vladimir Zapolskiy Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f98d03f3144c..6f8ec52c7e0c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -559,7 +559,7 @@ static int ohci_init (struct ohci_hcd *ohci) return 0; ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma, 0); + sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); if (!ohci->hcca) return -ENOMEM; From 6e693739e9b603b3ca9ce0d4f4178f0633458465 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 2 Jul 2014 01:58:18 -0700 Subject: [PATCH 103/211] USB: ehci-pci: USB host controller support for Intel Quark X1000 The EHCI packet buffer in/out threshold is programmable for Intel Quark X1000 USB host controller, and the default value is 0x20 dwords. The in/out threshold can be programmed to 0x80 dwords (512 Bytes) to maximize the perfomrance, but only when isochronous/interrupt transactions are not initiated by the USB host controller. This patch is to reconfigure the packet buffer in/out threshold as maximal as possible to maximize the performance, and 0x7F dwords (508 Bytes) should be used because the USB host controller initiates isochronous/interrupt transactions. Signed-off-by: Bryan O'Donoghue Signed-off-by: Alvin (Weike) Chen Acked-by: Alan Stern Reviewed-by: Jingoo Han Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 3e86bf4371b3..ca7b964124af 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -35,6 +35,21 @@ static const char hcd_name[] = "ehci-pci"; #define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70 /*-------------------------------------------------------------------------*/ +#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939 +static inline bool is_intel_quark_x1000(struct pci_dev *pdev) +{ + return pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC; +} + +/* + * 0x84 is the offset of in/out threshold register, + * and it is the same offset as the register of 'hostpc'. + */ +#define intel_quark_x1000_insnreg01 hostpc + +/* Maximum usable threshold value is 0x7f dwords for both IN and OUT */ +#define INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD 0x007f007f /* called after powerup, by probe or system-pm "wakeup" */ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) @@ -50,6 +65,16 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if (!retval) ehci_dbg(ehci, "MWI active\n"); + /* Reset the threshold limit */ + if (is_intel_quark_x1000(pdev)) { + /* + * For the Intel QUARK X1000, raise the I/O threshold to the + * maximum usable value in order to improve performance. + */ + ehci_writel(ehci, INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD, + ehci->regs->intel_quark_x1000_insnreg01); + } + return 0; } From 6a70b621227d1fd3efd150fce63ea4d51d4acaa9 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Tue, 17 Jun 2014 17:17:40 +0300 Subject: [PATCH 104/211] USB: EHCI: tegra: Fix use-after-free in .remove() The tegra_ehci_hcd structure is located in the private space allocated by the core USB code so it must not be accessed after the HCD is freed. Signed-off-by: Tuomas Tynkkynen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-tegra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index c303371f67bc..693f792aa7f5 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -479,10 +479,11 @@ static int tegra_ehci_remove(struct platform_device *pdev) usb_phy_shutdown(hcd->phy); usb_remove_hcd(hcd); - usb_put_hcd(hcd); clk_disable_unprepare(tegra->clk); + usb_put_hcd(hcd); + return 0; } From ddd94257410fa6be955af4592d8727e3b4ba51ef Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Thu, 12 Jun 2014 00:08:23 +0530 Subject: [PATCH 105/211] usb: host: uhci-grlib.c : use devm_ functions The various devm_ functions allocate memory that is released when a driver detaches. This patch uses devm_ioremap_resource for data that is allocated in the probe function of a platform device and is only freed in the remove function. The corresponding free functions are removed and two labels are done away with. Also, linux/device.h is added to make sure the devm_*() routine declarations are unambiguously available. Signed-off-by: Himangi Saraogi Acked-by: Andreas Larsson Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-grlib.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c index ab25dc397e8b..05f57ffdf9ab 100644 --- a/drivers/usb/host/uhci-grlib.c +++ b/drivers/usb/host/uhci-grlib.c @@ -17,6 +17,7 @@ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu */ +#include #include #include #include @@ -113,24 +114,17 @@ static int uhci_hcd_grlib_probe(struct platform_device *op) hcd->rsrc_start = res.start; hcd->rsrc_len = resource_size(&res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - irq = irq_of_parse_and_map(dn, 0); if (irq == NO_IRQ) { printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); rv = -EBUSY; - goto err_irq; + goto err_usb; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); - rv = -ENOMEM; - goto err_ioremap; + hcd->regs = devm_ioremap_resource(&op->dev, &res); + if (IS_ERR(hcd->regs)) { + rv = PTR_ERR(hcd->regs); + goto err_irq; } uhci = hcd_to_uhci(hcd); @@ -139,18 +133,14 @@ static int uhci_hcd_grlib_probe(struct platform_device *op) rv = usb_add_hcd(hcd, irq, 0); if (rv) - goto err_uhci; + goto err_irq; device_wakeup_enable(hcd->self.controller); return 0; -err_uhci: - iounmap(hcd->regs); -err_ioremap: - irq_dispose_mapping(irq); err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: + irq_dispose_mapping(irq); +err_usb: usb_put_hcd(hcd); return rv; @@ -164,10 +154,7 @@ static int uhci_hcd_grlib_remove(struct platform_device *op) usb_remove_hcd(hcd); - iounmap(hcd->regs); irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); return 0; From 91c72df1fc978b081224b2058067e2f5adc7143e Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 28 Jun 2014 14:44:09 +0200 Subject: [PATCH 106/211] drivers/usb/serial/mos7840.c: remove unnecessary null test before kfree Cc: Johan Hovold Signed-off-by: Fabian Frederick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 393be562d875..3d88eefdf1d1 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1181,10 +1181,7 @@ static void mos7840_close(struct usb_serial_port *port) /* Freeing Write URBs */ for (j = 0; j < NUM_URBS; ++j) { if (mos7840_port->write_urb_pool[j]) { - if (mos7840_port->write_urb_pool[j]->transfer_buffer) - kfree(mos7840_port->write_urb_pool[j]-> - transfer_buffer); - + kfree(mos7840_port->write_urb_pool[j]->transfer_buffer); usb_free_urb(mos7840_port->write_urb_pool[j]); } } From 883df42abff97b4791c7bc466226b878a828ecc5 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Fri, 4 Jul 2014 04:09:36 +0300 Subject: [PATCH 107/211] USB: tegra: Add resets & has-utmi-pad-registers flag to the PHY binding When Tegra was converted to use the standard reset bindings, the PHY was forgotten, probably because all the resetting of the USB blocks were done in the EHCI driver. What also went unnoticed is that resetting the 1st on-chip USB module also wipes some of the UTMI pad configuration registers that are also used by the other USB blocks. So this fact needs to be described in the device tree, and the driver modified not to reset the 1st module at inappropriate times. In order to stay compatible with old device trees, the USB drivers will still function without these properties but with the old, potentially buggy behaviour. Signed-off-by: Tuomas Tynkkynen Acked-by: Mark Rutland Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index ba797d3e6326..c9205fbf26e2 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -20,6 +20,12 @@ Required properties : Present if phy_type == utmi. - ulpi-link: The clock Tegra provides to the ULPI PHY (cdev2). Present if phy_type == ulpi, and ULPI link mode is in use. + - resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names : Must include the following entries: + - usb: The PHY's own reset signal. + - utmi-pads: The reset of the PHY containing the chip-wide UTMI pad control + registers. Required even if phy_type == ulpi. Required properties for phy_type == ulpi: - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. @@ -56,6 +62,8 @@ Optional properties: host means this is a host controller peripheral means it is device controller otg means it can operate as either ("on the go") + - nvidia,has-utmi-pad-registers : boolean indicates whether this controller + contains the UTMI pad control registers common to all USB controllers. VBUS control (required for dr_mode == otg, optional for dr_mode == host): - vbus-supply: regulator for VBUS From 308efde202bb3509b3c4868d8bbd42486992eeaa Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Fri, 4 Jul 2014 04:09:37 +0300 Subject: [PATCH 108/211] ARM: tegra: Add resets & has-utmi-pad-registers flag to all USB PHYs Add new properties to all of the Tegra PHYs that are now required according to the binding. In order to stay compatible with old device trees, the USB drivers will still function without these reset properties but with the old, potentially buggy behaviour. Signed-off-by: Tuomas Tynkkynen Acked-by: Mark Rutland Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/tegra114.dtsi | 5 +++++ arch/arm/boot/dts/tegra124.dtsi | 7 +++++++ arch/arm/boot/dts/tegra20.dtsi | 7 +++++++ arch/arm/boot/dts/tegra30.dtsi | 7 +++++++ 4 files changed, 26 insertions(+) diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index fdc559ab2db3..7da20ca633dd 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -657,6 +657,8 @@ phy1: usb-phy@7d000000 { <&tegra_car TEGRA114_CLK_PLL_U>, <&tegra_car TEGRA114_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 22>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; @@ -667,6 +669,7 @@ phy1: usb-phy@7d000000 { nvidia,hssquelch-level = <2>; nvidia,hsdiscon-level = <5>; nvidia,xcvr-hsslew = <12>; + nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -690,6 +693,8 @@ phy3: usb-phy@7d008000 { <&tegra_car TEGRA114_CLK_PLL_U>, <&tegra_car TEGRA114_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 59>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index 6e6bc4e8185c..aa8753a7c211 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -613,6 +613,8 @@ phy1: usb-phy@0,7d000000 { <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 59>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; @@ -647,6 +649,8 @@ phy2: usb-phy@0,7d004000 { <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 22>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; @@ -657,6 +661,7 @@ phy2: usb-phy@0,7d004000 { nvidia,hssquelch-level = <2>; nvidia,hsdiscon-level = <5>; nvidia,xcvr-hsslew = <12>; + nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -681,6 +686,8 @@ phy3: usb-phy@0,7d008000 { <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 58>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index a7ddf70df50b..935df8906f25 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -630,6 +630,8 @@ phy1: usb-phy@c5000000 { <&tegra_car TEGRA20_CLK_CLK_M>, <&tegra_car TEGRA20_CLK_USBD>; clock-names = "reg", "pll_u", "timer", "utmi-pads"; + resets = <&tegra_car 22>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,has-legacy-mode; nvidia,hssync-start-delay = <9>; nvidia,idle-wait-delay = <17>; @@ -638,6 +640,7 @@ phy1: usb-phy@c5000000 { nvidia,xcvr-setup = <9>; nvidia,xcvr-lsfslew = <1>; nvidia,xcvr-lsrslew = <1>; + nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -661,6 +664,8 @@ phy2: usb-phy@c5004000 { <&tegra_car TEGRA20_CLK_PLL_U>, <&tegra_car TEGRA20_CLK_CDEV2>; clock-names = "reg", "pll_u", "ulpi-link"; + resets = <&tegra_car 58>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; status = "disabled"; }; @@ -685,6 +690,8 @@ phy3: usb-phy@c5008000 { <&tegra_car TEGRA20_CLK_CLK_M>, <&tegra_car TEGRA20_CLK_USBD>; clock-names = "reg", "pll_u", "timer", "utmi-pads"; + resets = <&tegra_car 59>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <9>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index dec4fc823901..54805ce5efe0 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -775,6 +775,8 @@ phy1: usb-phy@7d000000 { <&tegra_car TEGRA30_CLK_PLL_U>, <&tegra_car TEGRA30_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 22>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <9>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; @@ -786,6 +788,7 @@ phy1: usb-phy@7d000000 { nvidia,xcvr-hsslew = <32>; nvidia,hssquelch-level = <2>; nvidia,hsdiscon-level = <5>; + nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -809,6 +812,8 @@ phy2: usb-phy@7d004000 { <&tegra_car TEGRA30_CLK_PLL_U>, <&tegra_car TEGRA30_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 58>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <9>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; @@ -843,6 +848,8 @@ phy3: usb-phy@7d008000 { <&tegra_car TEGRA30_CLK_PLL_U>, <&tegra_car TEGRA30_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; + resets = <&tegra_car 59>, <&tegra_car 22>; + reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; nvidia,elastic-limit = <16>; From a47cc24cd1e5a55ef0b240180ce7ec6a9afc939d Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Fri, 4 Jul 2014 04:09:38 +0300 Subject: [PATCH 109/211] USB: EHCI: tegra: Fix probe order issue leading to broken USB The Tegra USB complex has a particularly annoying misdesign: some of the UTMI pad configuration registers are global for all the 3 USB controllers on the chip, but those registers are located in the first controller's register space and will be cleared when the reset to the first controller is asserted. Currently, this means that if the 1st controller were to finish probing after the 2nd or 3rd controller, USB would not work at all. Fix this situation by always resetting the 1st controller before doing any other setup to any of the controllers, and then never ever reset the first controller again. As the UTMI registers are related to the PHY, the PHY driver should probably reset the Tegra controllers instead, but since old device trees only have reset phandles in the EHCI nodes, do it here, which means a bit of device tree groveling. Those old DTs also won't get the reset fix from this commit, so we'll dev_warn() them, but the driver will still keep probing successfully. Signed-off-by: Tuomas Tynkkynen Acked-by: Alan Stern Acked-by: Mark Rutland Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-tegra.c | 62 +++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 693f792aa7f5..7aafb05e7a40 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -46,6 +46,7 @@ #define DRV_NAME "tegra-ehci" static struct hc_driver __read_mostly tegra_ehci_hc_driver; +static bool usb1_reset_attempted; struct tegra_ehci_soc_config { bool has_hostpc; @@ -60,6 +61,61 @@ struct tegra_ehci_hcd { enum tegra_usb_phy_port_speed port_speed; }; +/* + * The 1st USB controller contains some UTMI pad registers that are global for + * all the controllers on the chip. Those registers are also cleared when + * reset is asserted to the 1st controller. This means that the 1st controller + * can only be reset when no other controlled has finished probing. So we'll + * reset the 1st controller before doing any other setup on any of the + * controllers, and then never again. + * + * Since this is a PHY issue, the Tegra PHY driver should probably be doing + * the resetting of the USB controllers. But to keep compatibility with old + * device trees that don't have reset phandles in the PHYs, do it here. + * Those old DTs will be vulnerable to total USB breakage if the 1st EHCI + * device isn't the first one to finish probing, so warn them. + */ +static int tegra_reset_usb_controller(struct platform_device *pdev) +{ + struct device_node *phy_np; + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct tegra_ehci_hcd *tegra = + (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; + + phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0); + if (!phy_np) + return -ENOENT; + + if (!usb1_reset_attempted) { + struct reset_control *usb1_reset; + + usb1_reset = of_reset_control_get(phy_np, "usb"); + if (IS_ERR(usb1_reset)) { + dev_warn(&pdev->dev, + "can't get utmi-pads reset from the PHY\n"); + dev_warn(&pdev->dev, + "continuing, but please update your DT\n"); + } else { + reset_control_assert(usb1_reset); + udelay(1); + reset_control_deassert(usb1_reset); + } + + reset_control_put(usb1_reset); + usb1_reset_attempted = true; + } + + if (!of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers")) { + reset_control_assert(tegra->rst); + udelay(1); + reset_control_deassert(tegra->rst); + } + + of_node_put(phy_np); + + return 0; +} + static int tegra_ehci_internal_port_reset( struct ehci_hcd *ehci, u32 __iomem *portsc_reg @@ -389,9 +445,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (err) goto cleanup_hcd_create; - reset_control_assert(tegra->rst); - udelay(1); - reset_control_deassert(tegra->rst); + err = tegra_reset_usb_controller(pdev); + if (err) + goto cleanup_clk_en; u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); if (IS_ERR(u_phy)) { From 3e346d41bfcdf803284b06ef6e4bf13fa2b86277 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Fri, 4 Jul 2014 04:09:39 +0300 Subject: [PATCH 110/211] USB: PHY: tegra: Call tegra_usb_phy_close only on device removal tegra_usb_phy_close() is supposed to undo the effects of tegra_usb_phy_init(). It is also currently added as the USB PHY shutdown callback, which is wrong, since tegra_usb_phy_init() is only called during probing wheras the shutdown callback can get called multiple times. This then leads to warnings about unbalanced regulator_disable if the EHCI driver is unbound and bound again at runtime. Signed-off-by: Tuomas Tynkkynen Acked-by: Mark Rutland Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-tegra-usb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 467a5e152afa..50dc69e1666f 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -685,10 +685,8 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy) return gpio_direction_output(phy->reset_gpio, 0); } -static void tegra_usb_phy_close(struct usb_phy *x) +static void tegra_usb_phy_close(struct tegra_usb_phy *phy) { - struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); - if (!IS_ERR(phy->vbus)) regulator_disable(phy->vbus); @@ -1060,14 +1058,13 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) if (err < 0) return err; - tegra_phy->u_phy.shutdown = tegra_usb_phy_close; tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend; platform_set_drvdata(pdev, tegra_phy); err = usb_add_phy_dev(&tegra_phy->u_phy); if (err < 0) { - tegra_usb_phy_close(&tegra_phy->u_phy); + tegra_usb_phy_close(tegra_phy); return err; } @@ -1079,6 +1076,7 @@ static int tegra_usb_phy_remove(struct platform_device *pdev) struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev); usb_remove_phy(&tegra_phy->u_phy); + tegra_usb_phy_close(tegra_phy); return 0; } From 96ae571338a4b2ecd2e42a6881bb0daa1a4e7d4f Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Thu, 12 Jun 2014 00:48:44 +0530 Subject: [PATCH 111/211] uhci-platform: use devm_ioremap resource This patch replaces the memory allocation using request_mem_region and the ioremap by a single call to managed interface devm_ioremap_reource. The corresponding calls to release_mem_region and iounmap in the probe and release functions are now unnecessary and are removed. Also a label is done away with and linux/device.h is added to make sure the devm_*() outine declarations are unambiguously available. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-platform.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 01833ab2b5c3..b987f1d10058 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -8,6 +8,7 @@ */ #include +#include #include static int uhci_platform_init(struct usb_hcd *hcd) @@ -88,33 +89,22 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_err("%s: request_mem_region failed\n", __func__); - ret = -EBUSY; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); goto err_rmr; } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_err("%s: ioremap failed\n", __func__); - ret = -ENOMEM; - goto err_irq; - } uhci = hcd_to_uhci(hcd); uhci->regs = hcd->regs; ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); if (ret) - goto err_uhci; + goto err_rmr; device_wakeup_enable(hcd->self.controller); return 0; -err_uhci: - iounmap(hcd->regs); -err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_rmr: usb_put_hcd(hcd); @@ -126,8 +116,6 @@ static int uhci_hcd_platform_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); return 0; From 0e278b3408999d5bdce50bd0d7f97608483eebea Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 2 Jul 2014 02:04:44 +0530 Subject: [PATCH 112/211] fotg210: Use managed interfaces for allocation of resources This patch intoduces the use of devm_ioremap_resource instead of request_mem_region and ioremap_nocache and removes the calls to free the allocated memory. Some labels are removes and a new label failed introduced to make it less specific to the context. The call to a platform get resource with IORESOURCE_IO is removed as it allocates memory that is not needed. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fotg210-hcd.c | 48 +++++++--------------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 98a89d16cc3e..adcd2050dced 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -5838,41 +5838,17 @@ static int fotg210_hcd_probe(struct platform_device *pdev) goto fail_create_hcd; } + hcd->has_tt = 1; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(dev)); - retval = -ENODEV; - goto fail_request_resource; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); + goto failed; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->has_tt = 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - fotg210_fotg210_hc_driver.description)) { - dev_dbg(dev, "controller already in use\n"); - retval = -EBUSY; - goto fail_request_resource; - } - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!res) { - dev_err(dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(dev)); - retval = -ENODEV; - goto fail_request_resource; - } - - hcd->regs = ioremap_nocache(res->start, resource_size(res)); - if (hcd->regs == NULL) { - dev_dbg(dev, "error mapping memory\n"); - retval = -EFAULT; - goto fail_ioremap; - } fotg210 = hcd_to_fotg210(hcd); @@ -5880,24 +5856,20 @@ static int fotg210_hcd_probe(struct platform_device *pdev) retval = fotg210_setup(hcd); if (retval) - goto fail_add_hcd; + goto failed; fotg210_init(fotg210); retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) { dev_err(dev, "failed to add hcd with err %d\n", retval); - goto fail_add_hcd; + goto failed; } device_wakeup_enable(hcd->self.controller); return retval; -fail_add_hcd: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -fail_request_resource: +failed: usb_put_hcd(hcd); fail_create_hcd: dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); @@ -5918,8 +5890,6 @@ static int fotg210_hcd_remove(struct platform_device *pdev) return 0; usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); return 0; From 6a0541599f54b556442d6130e4f9faaad91bf3a2 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 9 Jul 2014 20:30:03 +0900 Subject: [PATCH 113/211] usb: renesas_usbhs: fix usbhs_pipe_malloc() to re-enable a pipe. This patch fixes an issue that the driver cannot push a new data when a pipe is re-enabled after the pipe is queued. Acked-by: Kuninori Morimoto Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/pipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 7926e1c700f1..239b889ca5b5 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -710,6 +710,7 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, usbhsp_pipe_select(pipe); usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg); usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf); + usbhs_pipe_clear(pipe); usbhs_pipe_sequence_data0(pipe); From dfb87b8bfe09f933abaf387693992089f6f9053e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 9 Jul 2014 20:30:13 +0900 Subject: [PATCH 114/211] usb: renesas_usbhs: gadget: fix re-enabling pipe without re-connecting This patch fixes an issue that the renesas_usbhs driver in gadget mode cannot work correctly even if I disabled DMAC of the driver when I used the g_zero driver and the testusb tool. When a usb cable is re-connected, the renesas_usbhs driver calls the usbhsp_flags_init() (via usbhs_hotplug() --> usbhs_mod_call(start) --> usbhsg_try_start() --> usbhs_pipe_init()). However, the driver doesn't call the usbhsp_flags_init() when usbhsg_ep_disable() is called. So, if a gadget driver calls usb_ep_enable() and usb_ep_disable() again and again, the renesas_usbhs driver will output the following log: renesas_usbhs renesas_usbhs: can't get pipe (BULK) renesas_usbhs renesas_usbhs: wrong recip request Acked-by: Kuninori Morimoto Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 2 ++ drivers/usb/renesas_usbhs/pipe.c | 10 ++++++++++ drivers/usb/renesas_usbhs/pipe.h | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 458f3766bef1..04e6505777d0 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -600,8 +600,10 @@ static int usbhsg_ep_enable(struct usb_ep *ep, static int usbhsg_ep_disable(struct usb_ep *ep) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); usbhsg_pipe_disable(uep); + usbhs_pipe_free(pipe); uep->pipe->mod_private = NULL; uep->pipe = NULL; diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 239b889ca5b5..75fbcf6b102e 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -640,6 +640,11 @@ static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) return pipe; } +static void usbhsp_put_pipe(struct usbhs_pipe *pipe) +{ + usbhsp_flags_init(pipe); +} + void usbhs_pipe_init(struct usbhs_priv *priv, int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) { @@ -727,6 +732,11 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, return pipe; } +void usbhs_pipe_free(struct usbhs_pipe *pipe) +{ + usbhsp_put_pipe(pipe); +} + void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) { if (pipe->fifo) diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 3e5349879838..406f36d050e4 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -75,6 +75,7 @@ struct usbhs_pipe_info { char *usbhs_pipe_name(struct usbhs_pipe *pipe); struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, int endpoint_type, int dir_in); +void usbhs_pipe_free(struct usbhs_pipe *pipe); int usbhs_pipe_probe(struct usbhs_priv *priv); void usbhs_pipe_remove(struct usbhs_priv *priv); int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe); From 56e5cea9047e96bd58de5bca760c055cc35036aa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 9 Jul 2014 11:24:44 +0200 Subject: [PATCH 115/211] usb: gadget: pxa25x_udc: use correct header for gpio devm_ functions commit c63d2225e7be ("usb: gadget: pxa25x_udc: use devm_ functions") introduced the use of devm_gpio_request in this driver, but did not correctly include the header file declaring this function, which causes a build failure. This changes pxa25x_udc to include linux/gpio.h instead of asm/gpio.h to fix this. Signed-off-by: Arnd Bergmann Cc: Himangi Saraogi Cc: Julia Lawall Cc: Felipe Balbi Signed-off-by: Felipe Balbi --- drivers/usb/gadget/pxa25x_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index f1a5cdcd70ff..251e4d5ee152 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -16,6 +16,7 @@ /* #define VERBOSE_DEBUG */ #include +#include #include #include #include @@ -40,7 +41,6 @@ #include #include -#include #include #include From b99b406c990def280d64ceb6739ac32001497a90 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Fri, 4 Jul 2014 11:27:03 +0200 Subject: [PATCH 116/211] usb: gadget: net2280: Fix typo on #ifdef Commit e56e69cc0ff4 ("usb: gadget: net2280: Use pr_* function") includes a editing mistake on one of the #ifdef. This patch fixes it. Reported-by: Paul Bolle Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index ce8bc8644c59..248dccb3e542 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1562,7 +1562,7 @@ static const struct usb_gadget_ops net2280_ops = { /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_GADGET_PDEBUG_FILES +#ifdef CONFIG_USB_GADGET_DEBUG_FILES /* FIXME move these into procfs, and use seq_file. * Sysfs _still_ doesn't behave for arbitrarily sized files, From 3d75bd3d0af16c7b8dda13440202fa24769d8e17 Mon Sep 17 00:00:00 2001 From: Apelete Seketeli Date: Sun, 6 Jul 2014 19:58:03 +0200 Subject: [PATCH 117/211] usb: musb: register nop transceiver driver for jz4740 Following the name change of the NOP transceiver driver in commit 4525bee (usb: phy: rename usb_nop_xceiv to usb_phy_generic), the transceiver driver was no longer operable under its old name. Register the transceiver driver before calling usb_get_phy() to make sure we are noticed by an error message if it is not available. Signed-off-by: Apelete Seketeli Signed-off-by: Felipe Balbi --- drivers/usb/musb/jz4740.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index 5f30537f1927..d1187290d4e3 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "musb_core.h" @@ -80,6 +81,7 @@ static struct musb_hdrc_platform_data jz4740_musb_platform_data = { static int jz4740_musb_init(struct musb *musb) { + usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (!musb->xceiv) { pr_err("HS UDC: no transceiver configured\n"); @@ -182,6 +184,7 @@ static int jz4740_remove(struct platform_device *pdev) struct jz4740_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(pdev); clk_disable_unprepare(glue->clk); return 0; From e18366da2f7130b857ad6f11112e42d1ab1c7ceb Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 7 Jul 2014 14:06:35 +0200 Subject: [PATCH 118/211] usb: phy: tegra: Do not include asm/mach-types.h It is no longer needed and keeping it will break 64-bit ARM builds. Signed-off-by: Thierry Reding Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index cd36cb43ecc0..cd9d25e804b2 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include From f96cbd149aff4b0c4f23629051ed5d28b6804fb1 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Jul 2014 12:20:06 +0200 Subject: [PATCH 119/211] usb: gadget: f_fs: rename descriptor parsing functions ffs_do_desc() handles one descriptor, while ffs_do_descs() handles a number of descriptors. The tho names are so similar that it causes confusion. Rename to reflect their purpose better. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 88d6fa2290fd..e1b2ddd7964a 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1649,8 +1649,9 @@ typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, struct usb_descriptor_header *desc, void *priv); -static int __must_check ffs_do_desc(char *data, unsigned len, - ffs_entity_callback entity, void *priv) +static int __must_check ffs_do_single_desc(char *data, unsigned len, + ffs_entity_callback entity, + void *priv) { struct usb_descriptor_header *_ds = (void *)data; u8 length; @@ -1802,7 +1803,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, if (!data) return _len - len; - ret = ffs_do_desc(data, len, entity, priv); + ret = ffs_do_single_desc(data, len, entity, priv); if (unlikely(ret < 0)) { pr_debug("%s returns %d\n", __func__, ret); return ret; From 7ea4f088c810dab3ba3ab4c7a3879238f790e1fd Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Jul 2014 12:20:07 +0200 Subject: [PATCH 120/211] usb: gadget: u_os_desc: helper functions for accessing ext prop buffer Provide helper functions to get pointers to particular locations within a buffer holding an extended properties descriptor. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/u_os_desc.h | 59 ++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h index ea5cf8c2da28..947b7ddff691 100644 --- a/drivers/usb/gadget/u_os_desc.h +++ b/drivers/usb/gadget/u_os_desc.h @@ -35,27 +35,63 @@ #define USB_EXT_PROP_UNICODE_LINK 6 #define USB_EXT_PROP_UNICODE_MULTI 7 +static inline u8 *__usb_ext_prop_ptr(u8 *buf, size_t offset) +{ + return buf + offset; +} + +static inline u8 *usb_ext_prop_size_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_SIZE); +} + +static inline u8 *usb_ext_prop_type_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_PROPERTY_DATA_TYPE); +} + +static inline u8 *usb_ext_prop_name_len_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_W_PROPERTY_NAME_LENGTH); +} + +static inline u8 *usb_ext_prop_name_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_NAME); +} + +static inline u8 *usb_ext_prop_data_len_ptr(u8 *buf, size_t off) +{ + return __usb_ext_prop_ptr(buf, + USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + off); +} + +static inline u8 *usb_ext_prop_data_ptr(u8 *buf, size_t off) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_DATA + off); +} + static inline void usb_ext_prop_put_size(u8 *buf, int dw_size) { - put_unaligned_le32(dw_size, &buf[USB_EXT_PROP_DW_SIZE]); + put_unaligned_le32(dw_size, usb_ext_prop_size_ptr(buf)); } static inline void usb_ext_prop_put_type(u8 *buf, int type) { - put_unaligned_le32(type, &buf[USB_EXT_PROP_DW_PROPERTY_DATA_TYPE]); + put_unaligned_le32(type, usb_ext_prop_type_ptr(buf)); } static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl) { int result; - put_unaligned_le16(pnl, &buf[USB_EXT_PROP_W_PROPERTY_NAME_LENGTH]); + put_unaligned_le16(pnl, usb_ext_prop_name_len_ptr(buf)); result = utf8s_to_utf16s(name, strlen(name), UTF16_LITTLE_ENDIAN, - (wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_NAME], pnl - 2); + (wchar_t *) usb_ext_prop_name_ptr(buf), pnl - 2); if (result < 0) return result; - put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl]); + put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl - 2]); return pnl; } @@ -63,26 +99,23 @@ static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl) static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const u8 *data, int data_len) { - put_unaligned_le32(data_len, - &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); - memcpy(&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], data, data_len); + put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl)); + memcpy(usb_ext_prop_data_ptr(buf, pnl), data, data_len); } static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string, int data_len) { int result; - put_unaligned_le32(data_len, - &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); - + put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl)); result = utf8s_to_utf16s(string, data_len >> 1, UTF16_LITTLE_ENDIAN, - (wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], + (wchar_t *) usb_ext_prop_data_ptr(buf, pnl), data_len - 2); if (result < 0) return result; put_unaligned_le16(0, - &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len]); + &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len - 2]); return data_len; } From f0175ab51993d2dc2728e7b22a16ffb0c8f4cfa0 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Jul 2014 12:20:08 +0200 Subject: [PATCH 121/211] usb: gadget: f_fs: OS descriptors support Add support for OS descriptors. The new format of descriptors is used, because the "flags" field is required for extensions. os_count gives the number of OSDesc[] elements. The format of descriptors is given in include/uapi/linux/usb/functionfs.h. For extended properties descriptor the usb_ext_prop_desc structure covers only a part of a descriptor, because the wPropertyNameLength is unknown up front. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 341 +++++++++++++++++++++++++++- drivers/usb/gadget/u_fs.h | 7 + include/uapi/linux/usb/functionfs.h | 81 ++++++- 3 files changed, 419 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index e1b2ddd7964a..fe45060e0a7a 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -34,6 +34,7 @@ #include "u_fs.h" #include "u_f.h" +#include "u_os_desc.h" #include "configfs.h" #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ @@ -1644,11 +1645,19 @@ enum ffs_entity_type { FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT }; +enum ffs_os_desc_type { + FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP +}; + typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, u8 *valuep, struct usb_descriptor_header *desc, void *priv); +typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity, + struct usb_os_desc_header *h, void *data, + unsigned len, void *priv); + static int __must_check ffs_do_single_desc(char *data, unsigned len, ffs_entity_callback entity, void *priv) @@ -1856,11 +1865,191 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, return 0; } +static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, + struct usb_os_desc_header *desc) +{ + u16 bcd_version = le16_to_cpu(desc->bcdVersion); + u16 w_index = le16_to_cpu(desc->wIndex); + + if (bcd_version != 1) { + pr_vdebug("unsupported os descriptors version: %d", + bcd_version); + return -EINVAL; + } + switch (w_index) { + case 0x4: + *next_type = FFS_OS_DESC_EXT_COMPAT; + break; + case 0x5: + *next_type = FFS_OS_DESC_EXT_PROP; + break; + default: + pr_vdebug("unsupported os descriptor type: %d", w_index); + return -EINVAL; + } + + return sizeof(*desc); +} + +/* + * Process all extended compatibility/extended property descriptors + * of a feature descriptor + */ +static int __must_check ffs_do_single_os_desc(char *data, unsigned len, + enum ffs_os_desc_type type, + u16 feature_count, + ffs_os_desc_callback entity, + void *priv, + struct usb_os_desc_header *h) +{ + int ret; + const unsigned _len = len; + + ENTER(); + + /* loop over all ext compat/ext prop descriptors */ + while (feature_count--) { + ret = entity(type, h, data, len, priv); + if (unlikely(ret < 0)) { + pr_debug("bad OS descriptor, type: %d\n", type); + return ret; + } + data += ret; + len -= ret; + } + return _len - len; +} + +/* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */ +static int __must_check ffs_do_os_descs(unsigned count, + char *data, unsigned len, + ffs_os_desc_callback entity, void *priv) +{ + const unsigned _len = len; + unsigned long num = 0; + + ENTER(); + + for (num = 0; num < count; ++num) { + int ret; + enum ffs_os_desc_type type; + u16 feature_count; + struct usb_os_desc_header *desc = (void *)data; + + if (len < sizeof(*desc)) + return -EINVAL; + + /* + * Record "descriptor" entity. + * Process dwLength, bcdVersion, wIndex, get b/wCount. + * Move the data pointer to the beginning of extended + * compatibilities proper or extended properties proper + * portions of the data + */ + if (le32_to_cpu(desc->dwLength) > len) + return -EINVAL; + + ret = __ffs_do_os_desc_header(&type, desc); + if (unlikely(ret < 0)) { + pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n", + num, ret); + return ret; + } + /* + * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??" + */ + feature_count = le16_to_cpu(desc->wCount); + if (type == FFS_OS_DESC_EXT_COMPAT && + (feature_count > 255 || desc->Reserved)) + return -EINVAL; + len -= ret; + data += ret; + + /* + * Process all function/property descriptors + * of this Feature Descriptor + */ + ret = ffs_do_single_os_desc(data, len, type, + feature_count, entity, priv, desc); + if (unlikely(ret < 0)) { + pr_debug("%s returns %d\n", __func__, ret); + return ret; + } + + len -= ret; + data += ret; + } + return _len - len; +} + +/** + * Validate contents of the buffer from userspace related to OS descriptors. + */ +static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, + struct usb_os_desc_header *h, void *data, + unsigned len, void *priv) +{ + struct ffs_data *ffs = priv; + u8 length; + + ENTER(); + + switch (type) { + case FFS_OS_DESC_EXT_COMPAT: { + struct usb_ext_compat_desc *d = data; + int i; + + if (len < sizeof(*d) || + d->bFirstInterfaceNumber >= ffs->interfaces_count || + d->Reserved1) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) + if (d->Reserved2[i]) + return -EINVAL; + + length = sizeof(struct usb_ext_compat_desc); + } + break; + case FFS_OS_DESC_EXT_PROP: { + struct usb_ext_prop_desc *d = data; + u32 type, pdl; + u16 pnl; + + if (len < sizeof(*d) || h->interface >= ffs->interfaces_count) + return -EINVAL; + length = le32_to_cpu(d->dwSize); + type = le32_to_cpu(d->dwPropertyDataType); + if (type < USB_EXT_PROP_UNICODE || + type > USB_EXT_PROP_UNICODE_MULTI) { + pr_vdebug("unsupported os descriptor property type: %d", + type); + return -EINVAL; + } + pnl = le16_to_cpu(d->wPropertyNameLength); + pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl)); + if (length != 14 + pnl + pdl) { + pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n", + length, pnl, pdl, type); + return -EINVAL; + } + ++ffs->ms_os_descs_ext_prop_count; + /* property name reported to the host as "WCHAR"s */ + ffs->ms_os_descs_ext_prop_name_len += pnl * 2; + ffs->ms_os_descs_ext_prop_data_len += pdl; + } + break; + default: + pr_vdebug("unknown descriptor: %d\n", type); + return -EINVAL; + } + return length; +} + static int __ffs_data_got_descs(struct ffs_data *ffs, char *const _data, size_t len) { char *data = _data, *raw_descs; - unsigned counts[3], flags; + unsigned os_descs_count = 0, counts[3], flags; int ret = -EINVAL, i; ENTER(); @@ -1878,7 +2067,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, flags = get_unaligned_le32(data + 8); if (flags & ~(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | - FUNCTIONFS_HAS_SS_DESC)) { + FUNCTIONFS_HAS_SS_DESC | + FUNCTIONFS_HAS_MS_OS_DESC)) { ret = -ENOSYS; goto error; } @@ -1901,6 +2091,11 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, len -= 4; } } + if (flags & (1 << i)) { + os_descs_count = get_unaligned_le32(data); + data += 4; + len -= 4; + }; /* Read descriptors */ raw_descs = data; @@ -1914,6 +2109,14 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, data += ret; len -= ret; } + if (os_descs_count) { + ret = ffs_do_os_descs(os_descs_count, data, len, + __ffs_data_do_os_desc, ffs); + if (ret < 0) + goto error; + data += ret; + len -= ret; + } if (raw_descs == data || len) { ret = -EINVAL; @@ -1926,6 +2129,7 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, ffs->fs_descs_count = counts[0]; ffs->hs_descs_count = counts[1]; ffs->ss_descs_count = counts[2]; + ffs->ms_os_descs_count = os_descs_count; return 0; @@ -2267,6 +2471,85 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, return 0; } +static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type, + struct usb_os_desc_header *h, void *data, + unsigned len, void *priv) +{ + struct ffs_function *func = priv; + u8 length = 0; + + switch (type) { + case FFS_OS_DESC_EXT_COMPAT: { + struct usb_ext_compat_desc *desc = data; + struct usb_os_desc_table *t; + + t = &func->function.os_desc_table[desc->bFirstInterfaceNumber]; + t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber]; + memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID, + ARRAY_SIZE(desc->CompatibleID) + + ARRAY_SIZE(desc->SubCompatibleID)); + length = sizeof(*desc); + } + break; + case FFS_OS_DESC_EXT_PROP: { + struct usb_ext_prop_desc *desc = data; + struct usb_os_desc_table *t; + struct usb_os_desc_ext_prop *ext_prop; + char *ext_prop_name; + char *ext_prop_data; + + t = &func->function.os_desc_table[h->interface]; + t->if_id = func->interfaces_nums[h->interface]; + + ext_prop = func->ffs->ms_os_descs_ext_prop_avail; + func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop); + + ext_prop->type = le32_to_cpu(desc->dwPropertyDataType); + ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength); + ext_prop->data_len = le32_to_cpu(*(u32 *) + usb_ext_prop_data_len_ptr(data, ext_prop->name_len)); + length = ext_prop->name_len + ext_prop->data_len + 14; + + ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail; + func->ffs->ms_os_descs_ext_prop_name_avail += + ext_prop->name_len; + + ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail; + func->ffs->ms_os_descs_ext_prop_data_avail += + ext_prop->data_len; + memcpy(ext_prop_data, + usb_ext_prop_data_ptr(data, ext_prop->name_len), + ext_prop->data_len); + /* unicode data reported to the host as "WCHAR"s */ + switch (ext_prop->type) { + case USB_EXT_PROP_UNICODE: + case USB_EXT_PROP_UNICODE_ENV: + case USB_EXT_PROP_UNICODE_LINK: + case USB_EXT_PROP_UNICODE_MULTI: + ext_prop->data_len *= 2; + break; + } + ext_prop->data = ext_prop_data; + + memcpy(ext_prop_name, usb_ext_prop_name_ptr(data), + ext_prop->name_len); + /* property name reported to the host as "WCHAR"s */ + ext_prop->name_len *= 2; + ext_prop->name = ext_prop_name; + + t->os_desc->ext_prop_len += + ext_prop->name_len + ext_prop->data_len + 14; + ++t->os_desc->ext_prop_count; + list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop); + } + break; + default: + pr_vdebug("unknown descriptor: %d\n", type); + } + + return length; +} + static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, struct usb_configuration *c) { @@ -2328,7 +2611,7 @@ static int _ffs_func_bind(struct usb_configuration *c, const int super = gadget_is_superspeed(func->gadget) && func->ffs->ss_descs_count; - int fs_len, hs_len, ret; + int fs_len, hs_len, ss_len, ret, i; /* Make it a single chunk, less management later on */ vla_group(d); @@ -2340,6 +2623,18 @@ static int _ffs_func_bind(struct usb_configuration *c, vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, super ? ffs->ss_descs_count + 1 : 0); vla_item_with_sz(d, short, inums, ffs->interfaces_count); + vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table, + c->cdev->use_os_string ? ffs->interfaces_count : 0); + vla_item_with_sz(d, char[16], ext_compat, + c->cdev->use_os_string ? ffs->interfaces_count : 0); + vla_item_with_sz(d, struct usb_os_desc, os_desc, + c->cdev->use_os_string ? ffs->interfaces_count : 0); + vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop, + ffs->ms_os_descs_ext_prop_count); + vla_item_with_sz(d, char, ext_prop_name, + ffs->ms_os_descs_ext_prop_name_len); + vla_item_with_sz(d, char, ext_prop_data, + ffs->ms_os_descs_ext_prop_data_len); vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); char *vlabuf; @@ -2350,12 +2645,16 @@ static int _ffs_func_bind(struct usb_configuration *c, return -ENOTSUPP; /* Allocate a single chunk, less management later on */ - vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); + vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL); if (unlikely(!vlabuf)) return -ENOMEM; - /* Zero */ - memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); + ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop); + ffs->ms_os_descs_ext_prop_name_avail = + vla_ptr(vlabuf, d, ext_prop_name); + ffs->ms_os_descs_ext_prop_data_avail = + vla_ptr(vlabuf, d, ext_prop_data); + /* Copy descriptors */ memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, ffs->raw_descs_length); @@ -2409,12 +2708,16 @@ static int _ffs_func_bind(struct usb_configuration *c, if (likely(super)) { func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); - ret = ffs_do_descs(ffs->ss_descs_count, + ss_len = ffs_do_descs(ffs->ss_descs_count, vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, d_raw_descs__sz - fs_len - hs_len, __ffs_func_bind_do_descs, func); - if (unlikely(ret < 0)) + if (unlikely(ss_len < 0)) { + ret = ss_len; goto error; + } + } else { + ss_len = 0; } /* @@ -2430,6 +2733,28 @@ static int _ffs_func_bind(struct usb_configuration *c, if (unlikely(ret < 0)) goto error; + func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table); + if (c->cdev->use_os_string) + for (i = 0; i < ffs->interfaces_count; ++i) { + struct usb_os_desc *desc; + + desc = func->function.os_desc_table[i].os_desc = + vla_ptr(vlabuf, d, os_desc) + + i * sizeof(struct usb_os_desc); + desc->ext_compat_id = + vla_ptr(vlabuf, d, ext_compat) + i * 16; + INIT_LIST_HEAD(&desc->ext_prop); + } + ret = ffs_do_os_descs(ffs->ms_os_descs_count, + vla_ptr(vlabuf, d, raw_descs) + + fs_len + hs_len + ss_len, + d_raw_descs__sz - fs_len - hs_len - ss_len, + __ffs_func_bind_do_os_desc, func); + if (unlikely(ret < 0)) + goto error; + func->function.os_desc_n = + c->cdev->use_os_string ? ffs->interfaces_count : 0; + /* And we're done */ ffs_event_add(ffs, FUNCTIONFS_BIND); return 0; diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index bf0ba375d459..63d6e71569c1 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h @@ -216,6 +216,13 @@ struct ffs_data { unsigned fs_descs_count; unsigned hs_descs_count; unsigned ss_descs_count; + unsigned ms_os_descs_count; + unsigned ms_os_descs_ext_prop_count; + unsigned ms_os_descs_ext_prop_name_len; + unsigned ms_os_descs_ext_prop_data_len; + void *ms_os_descs_ext_prop_avail; + void *ms_os_descs_ext_prop_name_avail; + void *ms_os_descs_ext_prop_data_avail; unsigned short strings_count; unsigned short interfaces_count; diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h index 2a4b4a72a4f9..b66fae77c08c 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h @@ -18,10 +18,9 @@ enum functionfs_flags { FUNCTIONFS_HAS_FS_DESC = 1, FUNCTIONFS_HAS_HS_DESC = 2, FUNCTIONFS_HAS_SS_DESC = 4, + FUNCTIONFS_HAS_MS_OS_DESC = 8, }; -#ifndef __KERNEL__ - /* Descriptor of an non-audio endpoint */ struct usb_endpoint_descriptor_no_audio { __u8 bLength; @@ -33,6 +32,36 @@ struct usb_endpoint_descriptor_no_audio { __u8 bInterval; } __attribute__((packed)); +/* MS OS Descriptor header */ +struct usb_os_desc_header { + __u8 interface; + __le32 dwLength; + __le16 bcdVersion; + __le16 wIndex; + union { + struct { + __u8 bCount; + __u8 Reserved; + }; + __le16 wCount; + }; +} __attribute__((packed)); + +struct usb_ext_compat_desc { + __u8 bFirstInterfaceNumber; + __u8 Reserved1; + __u8 CompatibleID[8]; + __u8 SubCompatibleID[8]; + __u8 Reserved2[6]; +}; + +struct usb_ext_prop_desc { + __le32 dwSize; + __le32 dwPropertyDataType; + __le16 wPropertyNameLength; +} __attribute__((packed)); + +#ifndef __KERNEL__ /* * Descriptors format: @@ -45,9 +74,11 @@ struct usb_endpoint_descriptor_no_audio { * | | fs_count | LE32 | number of full-speed descriptors | * | | hs_count | LE32 | number of high-speed descriptors | * | | ss_count | LE32 | number of super-speed descriptors | + * | | os_count | LE32 | number of MS OS descriptors | * | | fs_descrs | Descriptor[] | list of full-speed descriptors | * | | hs_descrs | Descriptor[] | list of high-speed descriptors | * | | ss_descrs | Descriptor[] | list of super-speed descriptors | + * | | os_descrs | OSDesc[] | list of MS OS descriptors | * * Depending on which flags are set, various fields may be missing in the * structure. Any flags that are not recognised cause the whole block to be @@ -74,6 +105,52 @@ struct usb_endpoint_descriptor_no_audio { * | 0 | bLength | U8 | length of the descriptor | * | 1 | bDescriptorType | U8 | descriptor type | * | 2 | payload | | descriptor's payload | + * + * OSDesc[] is an array of valid MS OS Feature Descriptors which have one of + * the following formats: + * + * | off | name | type | description | + * |-----+-----------------+------+--------------------------| + * | 0 | inteface | U8 | related interface number | + * | 1 | dwLength | U32 | length of the descriptor | + * | 5 | bcdVersion | U16 | currently supported: 1 | + * | 7 | wIndex | U16 | currently supported: 4 | + * | 9 | bCount | U8 | number of ext. compat. | + * | 10 | Reserved | U8 | 0 | + * | 11 | ExtCompat[] | | list of ext. compat. d. | + * + * | off | name | type | description | + * |-----+-----------------+------+--------------------------| + * | 0 | inteface | U8 | related interface number | + * | 1 | dwLength | U32 | length of the descriptor | + * | 5 | bcdVersion | U16 | currently supported: 1 | + * | 7 | wIndex | U16 | currently supported: 5 | + * | 9 | wCount | U16 | number of ext. compat. | + * | 11 | ExtProp[] | | list of ext. prop. d. | + * + * ExtCompat[] is an array of valid Extended Compatiblity descriptors + * which have the following format: + * + * | off | name | type | description | + * |-----+-----------------------+------+-------------------------------------| + * | 0 | bFirstInterfaceNumber | U8 | index of the interface or of the 1st| + * | | | | interface in an IAD group | + * | 1 | Reserved | U8 | 0 | + * | 2 | CompatibleID | U8[8]| compatible ID string | + * | 10 | SubCompatibleID | U8[8]| subcompatible ID string | + * | 18 | Reserved | U8[6]| 0 | + * + * ExtProp[] is an array of valid Extended Properties descriptors + * which have the following format: + * + * | off | name | type | description | + * |-----+-----------------------+------+-------------------------------------| + * | 0 | dwSize | U32 | length of the descriptor | + * | 4 | dwPropertyDataType | U32 | 1..7 | + * | 8 | wPropertyNameLength | U16 | bPropertyName length (NL) | + * | 10 | bPropertyName |U8[NL]| name of this property | + * |10+NL| dwPropertyDataLength | U32 | bPropertyData length (DL) | + * |14+NL| bProperty |U8[DL]| payload of this property | */ struct usb_functionfs_strings_head { From 7ec3ea181d8cffb669982d79664f119ef6a71fc3 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Jul 2014 18:09:55 +0200 Subject: [PATCH 122/211] usb: gadget: Add helper macro for usb_composite_driver boilerplate Introduce the module_usb_composite_driver macro as a convenience macro for USB gadget composite driver modules, similar to module_usb_driver. It is intended to be used by drivers which init/exit section does nothing but calling usb_composite_probe/usb_composite_unrregister. By using this macro it is possible to eliminate a few lines of boilerplate code per USB gadget composite driver. Based on f3a6a4b6 ("USB: Add helper macro for usb_driver boilerplate") which introduced the according macro for USB drivers. Signed-off-by: Tobias Klauser Signed-off-by: Felipe Balbi --- include/linux/usb/composite.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 7373203140e7..c330f5ef42cf 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -386,6 +386,21 @@ struct usb_composite_driver { extern int usb_composite_probe(struct usb_composite_driver *driver); extern void usb_composite_unregister(struct usb_composite_driver *driver); + +/** + * module_usb_composite_driver() - Helper macro for registering a USB gadget + * composite driver + * @__usb_composite_driver: usb_composite_driver struct + * + * Helper macro for USB gadget composite drivers which do not do anything + * special in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces module_init() + * and module_exit() + */ +#define module_usb_composite_driver(__usb_composite_driver) \ + module_driver(__usb_composite_driver, usb_composite_probe, \ + usb_composite_unregister) + extern void usb_composite_setup_continue(struct usb_composite_dev *cdev); extern int composite_dev_prepare(struct usb_composite_driver *composite, struct usb_composite_dev *cdev); From 909346a819c5b81420d861bd53abd1140b26104e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Jul 2014 18:09:56 +0200 Subject: [PATCH 123/211] usb: gadget: Convert drivers to use module_usb_composite_driver() Use the module_usb_composite_driver() macro where applicable to eliminate the module_init/module_exit boilerplate in USB gadget composite drivers. Signed-off-by: Tobias Klauser Signed-off-by: Felipe Balbi --- drivers/usb/gadget/acm_ms.c | 14 ++------------ drivers/usb/gadget/audio.c | 12 +----------- drivers/usb/gadget/cdc2.c | 14 ++------------ drivers/usb/gadget/ether.c | 14 ++------------ drivers/usb/gadget/gmidi.c | 13 +------------ drivers/usb/gadget/multi.c | 13 +------------ drivers/usb/gadget/ncm.c | 14 ++------------ drivers/usb/gadget/nokia.c | 12 +----------- drivers/usb/gadget/webcam.c | 15 +-------------- drivers/usb/gadget/zero.c | 14 ++------------ 10 files changed, 15 insertions(+), 120 deletions(-) diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index a252444cc0a7..c30b7b572465 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -267,18 +267,8 @@ static __refdata struct usb_composite_driver acm_ms_driver = { .unbind = __exit_p(acm_ms_unbind), }; +module_usb_composite_driver(acm_ms_driver); + MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Klaus Schwarzkopf "); MODULE_LICENSE("GPL v2"); - -static int __init init(void) -{ - return usb_composite_probe(&acm_ms_driver); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&acm_ms_driver); -} -module_exit(cleanup); diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index 231b0efe8fdc..6eb695e5e43a 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c @@ -172,17 +172,7 @@ static __refdata struct usb_composite_driver audio_driver = { .unbind = __exit_p(audio_unbind), }; -static int __init init(void) -{ - return usb_composite_probe(&audio_driver); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&audio_driver); -} -module_exit(cleanup); +module_usb_composite_driver(audio_driver); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Bryan Wu "); diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index e126b6b248e6..2e85d9473478 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -231,18 +231,8 @@ static __refdata struct usb_composite_driver cdc_driver = { .unbind = __exit_p(cdc_unbind), }; +module_usb_composite_driver(cdc_driver); + MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("David Brownell"); MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(&cdc_driver); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&cdc_driver); -} -module_exit(cleanup); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index c1c113ef950c..c5fdc61cdc4a 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -475,18 +475,8 @@ static __refdata struct usb_composite_driver eth_driver = { .unbind = __exit_p(eth_unbind), }; +module_usb_composite_driver(eth_driver); + MODULE_DESCRIPTION(PREFIX DRIVER_DESC); MODULE_AUTHOR("David Brownell, Benedikt Spanger"); MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(ð_driver); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(ð_driver); -} -module_exit(cleanup); diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index e879e2c9f461..3d696b86ff76 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -163,15 +163,4 @@ static __refdata struct usb_composite_driver midi_driver = { .unbind = __exit_p(midi_unbind), }; -static int __init midi_init(void) -{ - return usb_composite_probe(&midi_driver); -} -module_init(midi_init); - -static void __exit midi_cleanup(void) -{ - usb_composite_unregister(&midi_driver); -} -module_exit(midi_cleanup); - +module_usb_composite_driver(midi_driver); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 940f6cde8e89..39d27bb343b4 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -507,15 +507,4 @@ static __refdata struct usb_composite_driver multi_driver = { .needs_serial = 1, }; - -static int __init multi_init(void) -{ - return usb_composite_probe(&multi_driver); -} -module_init(multi_init); - -static void __exit multi_exit(void) -{ - usb_composite_unregister(&multi_driver); -} -module_exit(multi_exit); +module_usb_composite_driver(multi_driver); diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c index 81956feca1bd..e90e23db2acb 100644 --- a/drivers/usb/gadget/ncm.c +++ b/drivers/usb/gadget/ncm.c @@ -204,18 +204,8 @@ static __refdata struct usb_composite_driver ncm_driver = { .unbind = __exit_p(gncm_unbind), }; +module_usb_composite_driver(ncm_driver); + MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Yauheni Kaliuta"); MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(&ncm_driver); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&ncm_driver); -} -module_exit(cleanup); diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 3ab386167519..9b8fd701648c 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -347,14 +347,4 @@ static __refdata struct usb_composite_driver nokia_driver = { .unbind = __exit_p(nokia_unbind), }; -static int __init nokia_init(void) -{ - return usb_composite_probe(&nokia_driver); -} -module_init(nokia_init); - -static void __exit nokia_cleanup(void) -{ - usb_composite_unregister(&nokia_driver); -} -module_exit(nokia_cleanup); +module_usb_composite_driver(nokia_driver); diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index 8cef1e658c29..a11d8e420bfe 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -390,20 +390,7 @@ static __refdata struct usb_composite_driver webcam_driver = { .unbind = webcam_unbind, }; -static int __init -webcam_init(void) -{ - return usb_composite_probe(&webcam_driver); -} - -static void __exit -webcam_cleanup(void) -{ - usb_composite_unregister(&webcam_driver); -} - -module_init(webcam_init); -module_exit(webcam_cleanup); +module_usb_composite_driver(webcam_driver); MODULE_AUTHOR("Laurent Pinchart"); MODULE_DESCRIPTION("Webcam Video Gadget"); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 134f354ede62..c3d496828b74 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -411,17 +411,7 @@ static __refdata struct usb_composite_driver zero_driver = { .resume = zero_resume, }; +module_usb_composite_driver(zero_driver); + MODULE_AUTHOR("David Brownell"); MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(&zero_driver); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&zero_driver); -} -module_exit(cleanup); From 1e32cda86d360ade35d2b3328b46ecf6ef5836db Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 8 Jul 2014 20:51:34 +0900 Subject: [PATCH 124/211] usb: phy: am335x: Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro and remove DEV_PM_OPS macro, in order to make the code simpler. Acked-by: Roger Quadros Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 585e50cb1980..b70e05537180 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -122,16 +122,10 @@ static int am335x_phy_resume(struct device *dev) return 0; } - -static const struct dev_pm_ops am335x_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(am335x_phy_suspend, am335x_phy_resume) -}; - -#define DEV_PM_OPS (&am335x_pm_ops) -#else -#define DEV_PM_OPS NULL #endif +static SIMPLE_DEV_PM_OPS(am335x_pm_ops, am335x_phy_suspend, am335x_phy_resume); + static const struct of_device_id am335x_phy_ids[] = { { .compatible = "ti,am335x-usb-phy" }, { } @@ -144,7 +138,7 @@ static struct platform_driver am335x_phy_driver = { .driver = { .name = "am335x-phy-driver", .owner = THIS_MODULE, - .pm = DEV_PM_OPS, + .pm = &am335x_pm_ops, .of_match_table = am335x_phy_ids, }, }; From 029d97ff543219762685805e15d71f7005ad7c5e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 4 Jul 2014 15:00:51 +0900 Subject: [PATCH 125/211] usb: dwc3: gadget: remove unnecessary 'start_new' variable Remove 'start_new' variable from dwc3_endpoint_transfer_complete(), since this variable has not been used. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9d64dd02c57e..d9304a8ceef3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1971,8 +1971,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, } static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, - struct dwc3_ep *dep, const struct dwc3_event_depevt *event, - int start_new) + struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { unsigned status = 0; int clean_busy; @@ -2039,7 +2038,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, return; } - dwc3_endpoint_transfer_complete(dwc, dep, event, 1); + dwc3_endpoint_transfer_complete(dwc, dep, event); break; case DWC3_DEPEVT_XFERINPROGRESS: if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { @@ -2048,7 +2047,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, return; } - dwc3_endpoint_transfer_complete(dwc, dep, event, 0); + dwc3_endpoint_transfer_complete(dwc, dep, event); break; case DWC3_DEPEVT_XFERNOTREADY: if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { From d82aa8aeb0eaa06bad80860a95ca5fdff84e8775 Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Mon, 7 Jul 2014 09:50:14 -0500 Subject: [PATCH 126/211] usb: gadget: fix eem_wrap cloned skb logic Even if the skb is cloned, we still need a ZLP or USB will stall. Signed-off-by: Nathan Sullivan Acked-by: Brad Mouring Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_eem.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index d61c11d765d0..4d8b236ea608 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -355,20 +355,18 @@ static struct sk_buff *eem_wrap(struct gether *port, struct sk_buff *skb) int padlen = 0; u16 len = skb->len; - if (!skb_cloned(skb)) { - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); - /* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0, - * stick two bytes of zero-length EEM packet on the end. - */ - if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0) - padlen += 2; + /* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0, + * stick two bytes of zero-length EEM packet on the end. + */ + if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0) + padlen += 2; - if ((tailroom >= (ETH_FCS_LEN + padlen)) && - (headroom >= EEM_HLEN)) - goto done; - } + if ((tailroom >= (ETH_FCS_LEN + padlen)) && + (headroom >= EEM_HLEN) && !skb_cloned(skb)) + goto done; skb2 = skb_copy_expand(skb, EEM_HLEN, ETH_FCS_LEN + padlen, GFP_ATOMIC); dev_kfree_skb_any(skb); From 370af734dfaf8336b496b386e194648e097e248a Mon Sep 17 00:00:00 2001 From: Jim Baxter Date: Mon, 7 Jul 2014 18:33:17 +0100 Subject: [PATCH 127/211] usb: gadget: NCM: RX function support multiple NDPs The NDP was ignoring the wNextNdpIndex in the NDP which means that NTBs containing multiple NDPs would have missed frames. Signed-off-by: Jim Baxter Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_ncm.c | 144 ++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index a9499fd30792..d0ebbac8845f 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -963,6 +963,7 @@ static int ncm_unwrap_ntb(struct gether *port, struct f_ncm *ncm = func_to_ncm(&port->func); __le16 *tmp = (void *) skb->data; unsigned index, index2; + int ndp_index; unsigned dg_len, dg_len2; unsigned ndp_len; struct sk_buff *skb2; @@ -995,91 +996,100 @@ static int ncm_unwrap_ntb(struct gether *port, goto err; } - index = get_ncm(&tmp, opts->fp_index); - /* NCM 3.2 */ - if (((index % 4) != 0) && (index < opts->nth_size)) { - INFO(port->func.config->cdev, "Bad index: %x\n", - index); - goto err; - } - - /* walk through NDP */ - tmp = ((void *)skb->data) + index; - if (get_unaligned_le32(tmp) != ncm->ndp_sign) { - INFO(port->func.config->cdev, "Wrong NDP SIGN\n"); - goto err; - } - tmp += 2; - - ndp_len = get_unaligned_le16(tmp++); - /* - * NCM 3.3.1 - * entry is 2 items - * item size is 16/32 bits, opts->dgram_item_len * 2 bytes - * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry - */ - if ((ndp_len < opts->ndp_size + 2 * 2 * (opts->dgram_item_len * 2)) - || (ndp_len % opts->ndplen_align != 0)) { - INFO(port->func.config->cdev, "Bad NDP length: %x\n", ndp_len); - goto err; - } - tmp += opts->reserved1; - tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */ - tmp += opts->reserved2; - - ndp_len -= opts->ndp_size; - index2 = get_ncm(&tmp, opts->dgram_item_len); - dg_len2 = get_ncm(&tmp, opts->dgram_item_len); - dgram_counter = 0; + ndp_index = get_ncm(&tmp, opts->fp_index); + /* Run through all the NDP's in the NTB */ do { - index = index2; - dg_len = dg_len2; - if (dg_len < 14 + crc_len) { /* ethernet header + crc */ - INFO(port->func.config->cdev, "Bad dgram length: %x\n", - dg_len); + /* NCM 3.2 */ + if (((ndp_index % 4) != 0) && + (ndp_index < opts->nth_size)) { + INFO(port->func.config->cdev, "Bad index: %#X\n", + ndp_index); goto err; } - if (ncm->is_crc) { - uint32_t crc, crc2; - crc = get_unaligned_le32(skb->data + - index + dg_len - crc_len); - crc2 = ~crc32_le(~0, - skb->data + index, - dg_len - crc_len); - if (crc != crc2) { - INFO(port->func.config->cdev, "Bad CRC\n"); - goto err; - } + /* walk through NDP */ + tmp = (void *)(skb->data + ndp_index); + if (get_unaligned_le32(tmp) != ncm->ndp_sign) { + INFO(port->func.config->cdev, "Wrong NDP SIGN\n"); + goto err; } + tmp += 2; + ndp_len = get_unaligned_le16(tmp++); + /* + * NCM 3.3.1 + * entry is 2 items + * item size is 16/32 bits, opts->dgram_item_len * 2 bytes + * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry + * Each entry is a dgram index and a dgram length. + */ + if ((ndp_len < opts->ndp_size + + 2 * 2 * (opts->dgram_item_len * 2)) + || (ndp_len % opts->ndplen_align != 0)) { + INFO(port->func.config->cdev, "Bad NDP length: %#X\n", + ndp_len); + goto err; + } + tmp += opts->reserved1; + /* Check for another NDP (d)wNextNdpIndex */ + ndp_index = get_ncm(&tmp, opts->next_fp_index); + tmp += opts->reserved2; + + ndp_len -= opts->ndp_size; index2 = get_ncm(&tmp, opts->dgram_item_len); dg_len2 = get_ncm(&tmp, opts->dgram_item_len); + dgram_counter = 0; + + do { + index = index2; + dg_len = dg_len2; + if (dg_len < 14 + crc_len) { /* ethernet hdr + crc */ + INFO(port->func.config->cdev, + "Bad dgram length: %#X\n", dg_len); + goto err; + } + if (ncm->is_crc) { + uint32_t crc, crc2; + + crc = get_unaligned_le32(skb->data + + index + dg_len - + crc_len); + crc2 = ~crc32_le(~0, + skb->data + index, + dg_len - crc_len); + if (crc != crc2) { + INFO(port->func.config->cdev, + "Bad CRC\n"); + goto err; + } + } + + index2 = get_ncm(&tmp, opts->dgram_item_len); + dg_len2 = get_ncm(&tmp, opts->dgram_item_len); - if (index2 == 0 || dg_len2 == 0) { - skb2 = skb; - } else { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) goto err; - } - if (!skb_pull(skb2, index)) { - ret = -EOVERFLOW; - goto err; - } + if (!skb_pull(skb2, index)) { + ret = -EOVERFLOW; + goto err; + } - skb_trim(skb2, dg_len - crc_len); - skb_queue_tail(list, skb2); + skb_trim(skb2, dg_len - crc_len); + skb_queue_tail(list, skb2); - ndp_len -= 2 * (opts->dgram_item_len * 2); + ndp_len -= 2 * (opts->dgram_item_len * 2); - dgram_counter++; + dgram_counter++; - if (index2 == 0 || dg_len2 == 0) - break; - } while (ndp_len > 2 * (opts->dgram_item_len * 2)); /* zero entry */ + if (index2 == 0 || dg_len2 == 0) + break; + } while (ndp_len > 2 * (opts->dgram_item_len * 2)); + } while (ndp_index); + + dev_kfree_skb_any(skb); VDBG(port->func.config->cdev, "Parsed NTB with %d frames\n", dgram_counter); From 6d3865f9d41f15ddbcecaa6722871fc0db21d7ab Mon Sep 17 00:00:00 2001 From: Jim Baxter Date: Mon, 7 Jul 2014 18:33:18 +0100 Subject: [PATCH 128/211] usb: gadget: NCM: Add transmit multi-frame. This adds multi-frame support to the NCM NTB's for the gadget driver. This allows multiple network packets to be put inside a single USB NTB with a maximum size of 16kB. It has a time out of 300ms to ensure that smaller number of packets still maintain a normal latency. Also the .fp_index and .next_fp_index have been changed to .ndp_index and .next_ndp_index to match the latest CDC-NCM specification and help with maintenance. Results transmitting from gadget to host. Before the change: TCP_STREAM Throughput (10^6bits/sec): 22.72 UDP_STREAM Throughput (10^6bits/sec): 25.94 Latency: netperf -H 192.168.1.101 -v2 -l 50 -t TCP_RR -- -r 16384,16384 Trans. RoundTrip Throughput Rate Latency 10^6bits/s per sec usec/Tran Outbound 100.83 9918.116 13.215 After the change: TCP_STREAM Throughput (10^6bits/sec): 124.26 UDP_STREAM Throughput (10^6bits/sec): 227.48 Latency: netperf -H 192.168.1.101 -v2 -l 50 -t TCP_RR -- -r 16384,16384 Trans. RoundTrip Throughput Rate Latency 10^6bits/s per sec usec/Tran Outbound 156.80 6377.730 20.552 Signed-off-by: Jim Baxter Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_ncm.c | 337 ++++++++++++++++++++++++++--------- drivers/usb/gadget/u_ether.c | 19 +- drivers/usb/gadget/u_ether.h | 2 + 3 files changed, 270 insertions(+), 88 deletions(-) diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index d0ebbac8845f..5452fb663762 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -68,6 +68,18 @@ struct f_ncm { * callback and ethernet open/close */ spinlock_t lock; + + struct net_device *netdev; + + /* For multi-frame NDP TX */ + struct sk_buff *skb_tx_data; + struct sk_buff *skb_tx_ndp; + u16 ndp_dgram_count; + bool timer_force_tx; + struct tasklet_struct tx_tasklet; + struct hrtimer task_timer; + + bool timer_stopping; }; static inline struct f_ncm *func_to_ncm(struct usb_function *f) @@ -92,15 +104,20 @@ static inline unsigned ncm_bitrate(struct usb_gadget *g) * If the host can group frames, allow it to do that, 16K is selected, * because it's used by default by the current linux host driver */ -#define NTB_DEFAULT_IN_SIZE USB_CDC_NCM_NTB_MIN_IN_SIZE +#define NTB_DEFAULT_IN_SIZE 16384 #define NTB_OUT_SIZE 16384 -/* - * skbs of size less than that will not be aligned - * to NCM's dwNtbInMaxSize to save bus bandwidth +/* Allocation for storing the NDP, 32 should suffice for a + * 16k packet. This allows a maximum of 32 * 507 Byte packets to + * be transmitted in a single 16kB skb, though when sending full size + * packets this limit will be plenty. + * Smaller packets are not likely to be trying to maximize the + * throughput and will be mstly sending smaller infrequent frames. */ +#define TX_MAX_NUM_DPE 32 -#define MAX_TX_NONFIXED (512 * 3) +/* Delay for the transmit to wait before sending an unfilled NTB frame. */ +#define TX_TIMEOUT_NSECS 300000 #define FORMATS_SUPPORTED (USB_CDC_NCM_NTB16_SUPPORTED | \ USB_CDC_NCM_NTB32_SUPPORTED) @@ -355,14 +372,15 @@ struct ndp_parser_opts { u32 ndp_sign; unsigned nth_size; unsigned ndp_size; + unsigned dpe_size; unsigned ndplen_align; /* sizes in u16 units */ unsigned dgram_item_len; /* index or length */ unsigned block_length; - unsigned fp_index; + unsigned ndp_index; unsigned reserved1; unsigned reserved2; - unsigned next_fp_index; + unsigned next_ndp_index; }; #define INIT_NDP16_OPTS { \ @@ -370,13 +388,14 @@ struct ndp_parser_opts { .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \ .nth_size = sizeof(struct usb_cdc_ncm_nth16), \ .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \ + .dpe_size = sizeof(struct usb_cdc_ncm_dpe16), \ .ndplen_align = 4, \ .dgram_item_len = 1, \ .block_length = 1, \ - .fp_index = 1, \ + .ndp_index = 1, \ .reserved1 = 0, \ .reserved2 = 0, \ - .next_fp_index = 1, \ + .next_ndp_index = 1, \ } @@ -385,13 +404,14 @@ struct ndp_parser_opts { .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \ .nth_size = sizeof(struct usb_cdc_ncm_nth32), \ .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \ + .dpe_size = sizeof(struct usb_cdc_ncm_dpe32), \ .ndplen_align = 8, \ .dgram_item_len = 2, \ .block_length = 2, \ - .fp_index = 2, \ + .ndp_index = 2, \ .reserved1 = 1, \ .reserved2 = 2, \ - .next_fp_index = 2, \ + .next_ndp_index = 2, \ } static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS; @@ -803,6 +823,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (ncm->port.in_ep->driver_data) { DBG(cdev, "reset ncm\n"); + ncm->timer_stopping = true; + ncm->netdev = NULL; gether_disconnect(&ncm->port); ncm_reset_values(ncm); } @@ -839,6 +861,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) net = gether_connect(&ncm->port); if (IS_ERR(net)) return PTR_ERR(net); + ncm->netdev = net; + ncm->timer_stopping = false; } spin_lock(&ncm->lock); @@ -865,95 +889,232 @@ static int ncm_get_alt(struct usb_function *f, unsigned intf) return ncm->port.in_ep->driver_data ? 1 : 0; } +static struct sk_buff *package_for_tx(struct f_ncm *ncm) +{ + __le16 *ntb_iter; + struct sk_buff *skb2 = NULL; + unsigned ndp_pad; + unsigned ndp_index; + unsigned new_len; + + const struct ndp_parser_opts *opts = ncm->parser_opts; + const int ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment); + const int dgram_idx_len = 2 * 2 * opts->dgram_item_len; + + /* Stop the timer */ + hrtimer_try_to_cancel(&ncm->task_timer); + + ndp_pad = ALIGN(ncm->skb_tx_data->len, ndp_align) - + ncm->skb_tx_data->len; + ndp_index = ncm->skb_tx_data->len + ndp_pad; + new_len = ndp_index + dgram_idx_len + ncm->skb_tx_ndp->len; + + /* Set the final BlockLength and wNdpIndex */ + ntb_iter = (void *) ncm->skb_tx_data->data; + /* Increment pointer to BlockLength */ + ntb_iter += 2 + 1 + 1; + put_ncm(&ntb_iter, opts->block_length, new_len); + put_ncm(&ntb_iter, opts->ndp_index, ndp_index); + + /* Set the final NDP wLength */ + new_len = opts->ndp_size + + (ncm->ndp_dgram_count * dgram_idx_len); + ncm->ndp_dgram_count = 0; + /* Increment from start to wLength */ + ntb_iter = (void *) ncm->skb_tx_ndp->data; + ntb_iter += 2; + put_unaligned_le16(new_len, ntb_iter); + + /* Merge the skbs */ + swap(skb2, ncm->skb_tx_data); + if (ncm->skb_tx_data) { + dev_kfree_skb_any(ncm->skb_tx_data); + ncm->skb_tx_data = NULL; + } + + /* Insert NDP alignment. */ + ntb_iter = (void *) skb_put(skb2, ndp_pad); + memset(ntb_iter, 0, ndp_pad); + + /* Copy NTB across. */ + ntb_iter = (void *) skb_put(skb2, ncm->skb_tx_ndp->len); + memcpy(ntb_iter, ncm->skb_tx_ndp->data, ncm->skb_tx_ndp->len); + dev_kfree_skb_any(ncm->skb_tx_ndp); + ncm->skb_tx_ndp = NULL; + + /* Insert zero'd datagram. */ + ntb_iter = (void *) skb_put(skb2, dgram_idx_len); + memset(ntb_iter, 0, dgram_idx_len); + + return skb2; +} + static struct sk_buff *ncm_wrap_ntb(struct gether *port, struct sk_buff *skb) { struct f_ncm *ncm = func_to_ncm(&port->func); - struct sk_buff *skb2; + struct sk_buff *skb2 = NULL; int ncb_len = 0; - __le16 *tmp; - int div; - int rem; - int pad; - int ndp_align; - int ndp_pad; + __le16 *ntb_data; + __le16 *ntb_ndp; + int dgram_pad; + unsigned max_size = ncm->port.fixed_in_len; const struct ndp_parser_opts *opts = ncm->parser_opts; - unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; + const int ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment); + const int div = le16_to_cpu(ntb_parameters.wNdpInDivisor); + const int rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder); + const int dgram_idx_len = 2 * 2 * opts->dgram_item_len; - div = le16_to_cpu(ntb_parameters.wNdpInDivisor); - rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder); - ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment); + if (!skb && !ncm->skb_tx_data) + return NULL; - ncb_len += opts->nth_size; - ndp_pad = ALIGN(ncb_len, ndp_align) - ncb_len; - ncb_len += ndp_pad; - ncb_len += opts->ndp_size; - ncb_len += 2 * 2 * opts->dgram_item_len; /* Datagram entry */ - ncb_len += 2 * 2 * opts->dgram_item_len; /* Zero datagram entry */ - pad = ALIGN(ncb_len, div) + rem - ncb_len; - ncb_len += pad; + if (skb) { + /* Add the CRC if required up front */ + if (ncm->is_crc) { + uint32_t crc; + __le16 *crc_pos; - if (ncb_len + skb->len + crc_len > max_size) { + crc = ~crc32_le(~0, + skb->data, + skb->len); + crc_pos = (void *) skb_put(skb, sizeof(uint32_t)); + put_unaligned_le32(crc, crc_pos); + } + + /* If the new skb is too big for the current NCM NTB then + * set the current stored skb to be sent now and clear it + * ready for new data. + * NOTE: Assume maximum align for speed of calculation. + */ + if (ncm->skb_tx_data + && (ncm->ndp_dgram_count >= TX_MAX_NUM_DPE + || (ncm->skb_tx_data->len + + div + rem + skb->len + + ncm->skb_tx_ndp->len + ndp_align + (2 * dgram_idx_len)) + > max_size)) { + skb2 = package_for_tx(ncm); + if (!skb2) + goto err; + } + + if (!ncm->skb_tx_data) { + ncb_len = opts->nth_size; + dgram_pad = ALIGN(ncb_len, div) + rem - ncb_len; + ncb_len += dgram_pad; + + /* Create a new skb for the NTH and datagrams. */ + ncm->skb_tx_data = alloc_skb(max_size, GFP_ATOMIC); + if (!ncm->skb_tx_data) + goto err; + + ntb_data = (void *) skb_put(ncm->skb_tx_data, ncb_len); + memset(ntb_data, 0, ncb_len); + /* dwSignature */ + put_unaligned_le32(opts->nth_sign, ntb_data); + ntb_data += 2; + /* wHeaderLength */ + put_unaligned_le16(opts->nth_size, ntb_data++); + + /* Allocate an skb for storing the NDP, + * TX_MAX_NUM_DPE should easily suffice for a + * 16k packet. + */ + ncm->skb_tx_ndp = alloc_skb((int)(opts->ndp_size + + opts->dpe_size + * TX_MAX_NUM_DPE), + GFP_ATOMIC); + if (!ncm->skb_tx_ndp) + goto err; + ntb_ndp = (void *) skb_put(ncm->skb_tx_ndp, + opts->ndp_size); + memset(ntb_ndp, 0, ncb_len); + /* dwSignature */ + put_unaligned_le32(ncm->ndp_sign, ntb_ndp); + ntb_ndp += 2; + + /* There is always a zeroed entry */ + ncm->ndp_dgram_count = 1; + + /* Note: we skip opts->next_ndp_index */ + } + + /* Delay the timer. */ + hrtimer_start(&ncm->task_timer, + ktime_set(0, TX_TIMEOUT_NSECS), + HRTIMER_MODE_REL); + + /* Add the datagram position entries */ + ntb_ndp = (void *) skb_put(ncm->skb_tx_ndp, dgram_idx_len); + memset(ntb_ndp, 0, dgram_idx_len); + + ncb_len = ncm->skb_tx_data->len; + dgram_pad = ALIGN(ncb_len, div) + rem - ncb_len; + ncb_len += dgram_pad; + + /* (d)wDatagramIndex */ + put_ncm(&ntb_ndp, opts->dgram_item_len, ncb_len); + /* (d)wDatagramLength */ + put_ncm(&ntb_ndp, opts->dgram_item_len, skb->len); + ncm->ndp_dgram_count++; + + /* Add the new data to the skb */ + ntb_data = (void *) skb_put(ncm->skb_tx_data, dgram_pad); + memset(ntb_data, 0, dgram_pad); + ntb_data = (void *) skb_put(ncm->skb_tx_data, skb->len); + memcpy(ntb_data, skb->data, skb->len); dev_kfree_skb_any(skb); - return NULL; + skb = NULL; + + } else if (ncm->skb_tx_data && ncm->timer_force_tx) { + /* If the tx was requested because of a timeout then send */ + skb2 = package_for_tx(ncm); + if (!skb2) + goto err; } - skb2 = skb_copy_expand(skb, ncb_len, - max_size - skb->len - ncb_len - crc_len, - GFP_ATOMIC); - dev_kfree_skb_any(skb); - if (!skb2) - return NULL; + return skb2; - skb = skb2; +err: + ncm->netdev->stats.tx_dropped++; - tmp = (void *) skb_push(skb, ncb_len); - memset(tmp, 0, ncb_len); + if (skb) + dev_kfree_skb_any(skb); + if (ncm->skb_tx_data) + dev_kfree_skb_any(ncm->skb_tx_data); + if (ncm->skb_tx_ndp) + dev_kfree_skb_any(ncm->skb_tx_ndp); - put_unaligned_le32(opts->nth_sign, tmp); /* dwSignature */ - tmp += 2; - /* wHeaderLength */ - put_unaligned_le16(opts->nth_size, tmp++); - tmp++; /* skip wSequence */ - put_ncm(&tmp, opts->block_length, skb->len); /* (d)wBlockLength */ - /* (d)wFpIndex */ - /* the first pointer is right after the NTH + align */ - put_ncm(&tmp, opts->fp_index, opts->nth_size + ndp_pad); + return NULL; +} - tmp = (void *)tmp + ndp_pad; +/* + * This transmits the NTB if there are frames waiting. + */ +static void ncm_tx_tasklet(unsigned long data) +{ + struct f_ncm *ncm = (void *)data; - /* NDP */ - put_unaligned_le32(ncm->ndp_sign, tmp); /* dwSignature */ - tmp += 2; - /* wLength */ - put_unaligned_le16(ncb_len - opts->nth_size - pad, tmp++); + if (ncm->timer_stopping) + return; - tmp += opts->reserved1; - tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */ - tmp += opts->reserved2; - - if (ncm->is_crc) { - uint32_t crc; - - crc = ~crc32_le(~0, - skb->data + ncb_len, - skb->len - ncb_len); - put_unaligned_le32(crc, skb->data + skb->len); - skb_put(skb, crc_len); + /* Only send if data is available. */ + if (ncm->skb_tx_data) { + ncm->timer_force_tx = true; + ncm->netdev->netdev_ops->ndo_start_xmit(NULL, ncm->netdev); + ncm->timer_force_tx = false; } +} - /* (d)wDatagramIndex[0] */ - put_ncm(&tmp, opts->dgram_item_len, ncb_len); - /* (d)wDatagramLength[0] */ - put_ncm(&tmp, opts->dgram_item_len, skb->len - ncb_len); - /* (d)wDatagramIndex[1] and (d)wDatagramLength[1] already zeroed */ - - if (skb->len > MAX_TX_NONFIXED) - memset(skb_put(skb, max_size - skb->len), - 0, max_size - skb->len); - - return skb; +/* + * The transmit should only be run if no skb data has been sent + * for a certain duration. + */ +static enum hrtimer_restart ncm_tx_timeout(struct hrtimer *data) +{ + struct f_ncm *ncm = container_of(data, struct f_ncm, task_timer); + tasklet_schedule(&ncm->tx_tasklet); + return HRTIMER_NORESTART; } static int ncm_unwrap_ntb(struct gether *port, @@ -996,7 +1157,7 @@ static int ncm_unwrap_ntb(struct gether *port, goto err; } - ndp_index = get_ncm(&tmp, opts->fp_index); + ndp_index = get_ncm(&tmp, opts->ndp_index); /* Run through all the NDP's in the NTB */ do { @@ -1033,7 +1194,7 @@ static int ncm_unwrap_ntb(struct gether *port, } tmp += opts->reserved1; /* Check for another NDP (d)wNextNdpIndex */ - ndp_index = get_ncm(&tmp, opts->next_fp_index); + ndp_index = get_ncm(&tmp, opts->next_ndp_index); tmp += opts->reserved2; ndp_len -= opts->ndp_size; @@ -1107,8 +1268,11 @@ static void ncm_disable(struct usb_function *f) DBG(cdev, "ncm deactivated\n"); - if (ncm->port.in_ep->driver_data) + if (ncm->port.in_ep->driver_data) { + ncm->timer_stopping = true; + ncm->netdev = NULL; gether_disconnect(&ncm->port); + } if (ncm->notify->driver_data) { usb_ep_disable(ncm->notify); @@ -1277,6 +1441,10 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm->port.open = ncm_open; ncm->port.close = ncm_close; + tasklet_init(&ncm->tx_tasklet, ncm_tx_tasklet, (unsigned long) ncm); + hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ncm->task_timer.function = ncm_tx_timeout; + DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", ncm->port.in_ep->name, ncm->port.out_ep->name, @@ -1390,6 +1558,10 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "ncm unbind\n"); + hrtimer_cancel(&ncm->task_timer); + tasklet_kill(&ncm->tx_tasklet); + + ncm_string_defs[0].id = 0; usb_free_all_descriptors(f); kfree(ncm->notify_req->buf); @@ -1426,6 +1598,7 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi) ncm->port.ioport = netdev_priv(opts->net); mutex_unlock(&opts->lock); ncm->port.is_fixed = true; + ncm->port.supports_multi_frame = true; ncm->port.func.name = "cdc_network"; /* descriptors are per-instance copies */ diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 3d78a8844e43..6e6f87656e7b 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -483,7 +483,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { struct eth_dev *dev = netdev_priv(net); - int length = skb->len; + int length = 0; int retval; struct usb_request *req = NULL; unsigned long flags; @@ -500,13 +500,13 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, } spin_unlock_irqrestore(&dev->lock, flags); - if (!in) { + if (skb && !in) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } /* apply outgoing CDC or RNDIS filters */ - if (!is_promisc(cdc_filter)) { + if (skb && !is_promisc(cdc_filter)) { u8 *dest = skb->data; if (is_multicast_ether_addr(dest)) { @@ -557,11 +557,17 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, if (dev->port_usb) skb = dev->wrap(dev->port_usb, skb); spin_unlock_irqrestore(&dev->lock, flags); - if (!skb) + if (!skb) { + /* Multi frame CDC protocols may store the frame for + * later which is not a dropped frame. + */ + if (dev->port_usb->supports_multi_frame) + goto multiframe; goto drop; - - length = skb->len; + } } + + length = skb->len; req->buf = skb->data; req->context = skb; req->complete = tx_complete; @@ -604,6 +610,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev_kfree_skb_any(skb); drop: dev->net->stats.tx_dropped++; +multiframe: spin_lock_irqsave(&dev->req_lock, flags); if (list_empty(&dev->tx_reqs)) netif_start_queue(net); diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index 0f0290acea7e..334b38947916 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "gadget_chips.h" @@ -74,6 +75,7 @@ struct gether { bool is_fixed; u32 fixed_out_len; u32 fixed_in_len; + bool supports_multi_frame; struct sk_buff *(*wrap)(struct gether *port, struct sk_buff *skb); int (*unwrap)(struct gether *port, From 66847062a6e33fa54b98714c7c954353e2596645 Mon Sep 17 00:00:00 2001 From: Jim Baxter Date: Mon, 7 Jul 2014 18:33:19 +0100 Subject: [PATCH 129/211] usb: gadget: NCM: Stop RX TCP Bursts getting dropped. This fixes a problem with dropped packets over 16k CDC-NCM when the connection is being heavily used. The issue was that the extracted frames cloned from the received frame were consuming more memory than necessary resulting in the truesize being ~32KB instead of ~2KB, this meant there was a high chance of reaching the sk_rcvbuf limit. Signed-off-by: Jim Baxter Acked-by: Eric Dumazet Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_ncm.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 5452fb663762..bcdc882cd415 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -1229,16 +1229,17 @@ static int ncm_unwrap_ntb(struct gether *port, index2 = get_ncm(&tmp, opts->dgram_item_len); dg_len2 = get_ncm(&tmp, opts->dgram_item_len); - skb2 = skb_clone(skb, GFP_ATOMIC); + /* + * Copy the data into a new skb. + * This ensures the truesize is correct + */ + skb2 = netdev_alloc_skb_ip_align(ncm->netdev, + dg_len - crc_len); if (skb2 == NULL) goto err; + memcpy(skb_put(skb2, dg_len - crc_len), + skb->data + index, dg_len - crc_len); - if (!skb_pull(skb2, index)) { - ret = -EOVERFLOW; - goto err; - } - - skb_trim(skb2, dg_len - crc_len); skb_queue_tail(list, skb2); ndp_len -= 2 * (opts->dgram_item_len * 2); From ecdc071d02a052c30a3ba9cc574ae1544ea9be15 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 10 Jul 2014 14:22:34 +0900 Subject: [PATCH 130/211] usb: usb3503: add PM functions The usb3503 needs to switch to standby mode while suspending and should switch to hub mode when resumed. Also we can control clock on PM function. Signed-off-by: Joonyoung Shim Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb3503.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 652855b40289..47cb143716a1 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -149,8 +149,6 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) case USB3503_MODE_STANDBY: usb3503_reset(hub, 0); - - hub->mode = mode; dev_info(dev, "switched to STANDBY mode\n"); break; @@ -347,6 +345,37 @@ static int usb3503_platform_probe(struct platform_device *pdev) return usb3503_probe(hub); } +#ifdef CONFIG_PM_SLEEP +static int usb3503_i2c_suspend(struct device *dev) +{ + 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) + clk_disable_unprepare(hub->clk); + + return 0; +} + +static int usb3503_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb3503 *hub = i2c_get_clientdata(client); + + if (hub->clk) + clk_prepare_enable(hub->clk); + + usb3503_switch_mode(hub, hub->mode); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(usb3503_i2c_pm_ops, usb3503_i2c_suspend, + usb3503_i2c_resume); + static const struct i2c_device_id usb3503_id[] = { { USB3503_I2C_NAME, 0 }, { } @@ -365,6 +394,7 @@ MODULE_DEVICE_TABLE(of, usb3503_of_match); static struct i2c_driver usb3503_i2c_driver = { .driver = { .name = USB3503_I2C_NAME, + .pm = &usb3503_i2c_pm_ops, .of_match_table = of_match_ptr(usb3503_of_match), }, .probe = usb3503_i2c_probe, From 526a4045c60fbaede88ec95a69a73059dff02160 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 10 Jul 2014 14:22:35 +0900 Subject: [PATCH 131/211] USB: add reset resume quirk for usb3503 The usb device will autoresume from choose_wakeup() if it is autosuspended with the wrong wakeup setting, but below errors occur because usb3503 misc driver will switch to standby mode when suspended. As add USB_QUIRK_RESET_RESUME, it can stop setting wrong wakeup from autosuspend_check(). [ 7.734717] usb 1-3: reset high-speed USB device number 3 using exynos-ehci [ 7.854658] usb 1-3: device descriptor read/64, error -71 [ 8.079657] usb 1-3: device descriptor read/64, error -71 [ 8.294664] usb 1-3: reset high-speed USB device number 3 using exynos-ehci [ 8.414658] usb 1-3: device descriptor read/64, error -71 [ 8.639657] usb 1-3: device descriptor read/64, error -71 [ 8.854667] usb 1-3: reset high-speed USB device number 3 using exynos-ehci [ 9.264598] usb 1-3: device not accepting address 3, error -71 [ 9.374655] usb 1-3: reset high-speed USB device number 3 using exynos-ehci [ 9.784601] usb 1-3: device not accepting address 3, error -71 [ 9.784838] usb usb1-port3: device 1-3 not suspended yet Signed-off-by: Joonyoung Shim Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 739ee8e8bdfd..2c9ba4077075 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -152,6 +152,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + /* USB3503 */ + { USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ }; From ca632a0d2fec10e62377a78a424d68c90f2e4345 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:37:05 +0530 Subject: [PATCH 132/211] usb: dwc3: omap: remove x_major calculation from revision register Remove the x_major calculation logic from the wrapper revision register to differentiate between OMAP5 and AM437x. This was done to find the register offsets of wrapper register. Now that We do it using dt compatible, remove the whole logic. Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 39 +++++++----------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 4af4c3567656..25a6075ef319 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -77,10 +77,6 @@ #define USBOTGSS_DEV_EBC_EN 0x0110 #define USBOTGSS_DEBUG_OFFSET 0x0600 -/* REVISION REGISTER */ -#define USBOTGSS_REVISION_XMAJOR(reg) ((reg >> 8) & 0x7) -#define USBOTGSS_REVISION_XMAJOR1 1 -#define USBOTGSS_REVISION_XMAJOR2 2 /* SYSCONFIG REGISTER */ #define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16) @@ -129,7 +125,6 @@ struct dwc3_omap { u32 irq_eoi_offset; u32 debug_offset; u32 irq0_offset; - u32 revision; u32 dma_status:1; @@ -397,7 +392,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) int irq; int utmi_mode = 0; - int x_major; u32 reg; @@ -448,32 +442,13 @@ static int dwc3_omap_probe(struct platform_device *pdev) goto err0; } - reg = dwc3_omap_readl(omap->base, USBOTGSS_REVISION); - omap->revision = reg; - x_major = USBOTGSS_REVISION_XMAJOR(reg); - - /* Differentiate between OMAP5 and AM437x */ - switch (x_major) { - case USBOTGSS_REVISION_XMAJOR1: - case USBOTGSS_REVISION_XMAJOR2: - omap->irq_eoi_offset = 0; - omap->irq0_offset = 0; - omap->irqmisc_offset = 0; - omap->utmi_otg_offset = 0; - omap->debug_offset = 0; - break; - default: - /* Default to the latest revision */ - omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET; - omap->irq0_offset = USBOTGSS_IRQ0_OFFSET; - omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET; - omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET; - omap->debug_offset = USBOTGSS_DEBUG_OFFSET; - break; - } - - /* For OMAP5(ES2.0) and AM437x x_major is 2 even though there are - * changes in wrapper registers, Using dt compatible for aegis + /* + * Differentiate between OMAP5 and AM437x. + * + * For OMAP5(ES2.0) and AM437x wrapper revision is same, even + * though there are changes in wrapper register offsets. + * + * Using dt compatible to differentiate AM437x. */ if (of_device_is_compatible(node, "ti,am437x-dwc3")) { From 30fef1a97fb6551abb50b5208993726b878fe40f Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:37:06 +0530 Subject: [PATCH 133/211] usb: dwc3: omap: add dwc3_omap_map_offset() function Move map offset to its own separate function. Improve code readability, decrease the dwc3_probe() size. Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 38 +++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 25a6075ef319..22fca6291ff5 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -378,6 +378,27 @@ static int dwc3_omap_vbus_notifier(struct notifier_block *nb, return NOTIFY_DONE; } +static void dwc3_omap_map_offset(struct dwc3_omap *omap) +{ + struct device_node *node = omap->dev->of_node; + + /* + * Differentiate between OMAP5 and AM437x. + * + * For OMAP5(ES2.0) and AM437x wrapper revision is same, even + * though there are changes in wrapper register offsets. + * + * Using dt compatible to differentiate AM437x. + */ + if (of_device_is_compatible(node, "ti,am437x-dwc3")) { + omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET; + omap->irq0_offset = USBOTGSS_IRQ0_OFFSET; + omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET; + omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET; + omap->debug_offset = USBOTGSS_DEBUG_OFFSET; + } +} + static int dwc3_omap_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -442,22 +463,7 @@ static int dwc3_omap_probe(struct platform_device *pdev) goto err0; } - /* - * Differentiate between OMAP5 and AM437x. - * - * For OMAP5(ES2.0) and AM437x wrapper revision is same, even - * though there are changes in wrapper register offsets. - * - * Using dt compatible to differentiate AM437x. - */ - - if (of_device_is_compatible(node, "ti,am437x-dwc3")) { - omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET; - omap->irq0_offset = USBOTGSS_IRQ0_OFFSET; - omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET; - omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET; - omap->debug_offset = USBOTGSS_DEBUG_OFFSET; - } + dwc3_omap_map_offset(omap); reg = dwc3_omap_read_utmi_status(omap); From d2f0cf89ca2deca59cc4ca0c80c14100831428db Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:37:07 +0530 Subject: [PATCH 134/211] usb: dwc3: omap: add dwc3_omap_set_utmi_mode() function Move find and set the utmi mode to its own separate function. Improve code readability, decrease the dwc3_probe() size. Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 44 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 22fca6291ff5..6a90b96c9d14 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -399,6 +399,30 @@ static void dwc3_omap_map_offset(struct dwc3_omap *omap) } } +static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap) +{ + u32 reg; + struct device_node *node = omap->dev->of_node; + int utmi_mode = 0; + + reg = dwc3_omap_read_utmi_status(omap); + + of_property_read_u32(node, "utmi-mode", &utmi_mode); + + switch (utmi_mode) { + case DWC3_OMAP_UTMI_MODE_SW: + reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + break; + case DWC3_OMAP_UTMI_MODE_HW: + reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + break; + default: + dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode); + } + + dwc3_omap_write_utmi_status(omap, reg); +} + static int dwc3_omap_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -412,8 +436,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) int ret; int irq; - int utmi_mode = 0; - u32 reg; void __iomem *base; @@ -464,23 +486,7 @@ static int dwc3_omap_probe(struct platform_device *pdev) } dwc3_omap_map_offset(omap); - - reg = dwc3_omap_read_utmi_status(omap); - - of_property_read_u32(node, "utmi-mode", &utmi_mode); - - switch (utmi_mode) { - case DWC3_OMAP_UTMI_MODE_SW: - reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; - break; - case DWC3_OMAP_UTMI_MODE_HW: - reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE; - break; - default: - dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode); - } - - dwc3_omap_write_utmi_status(omap, reg); + dwc3_omap_set_utmi_mode(omap); /* check the DMA Status */ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); From 025b431b0ed3d4d3363427661c53ed8b60487a44 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:37:08 +0530 Subject: [PATCH 135/211] usb: dwc3: omap: add dwc3_omap_extcon_register function Move the extcon related code to its own function. Improve code readability, decrease the dwc3_probe() size. Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 65 +++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 6a90b96c9d14..961295d7042f 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -423,6 +423,42 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap) dwc3_omap_write_utmi_status(omap, reg); } +static int dwc3_omap_extcon_register(struct dwc3_omap *omap) +{ + u32 ret; + struct device_node *node = omap->dev->of_node; + struct extcon_dev *edev; + + if (of_property_read_bool(node, "extcon")) { + edev = extcon_get_edev_by_phandle(omap->dev, 0); + if (IS_ERR(edev)) { + dev_vdbg(omap->dev, "couldn't get extcon device\n"); + return -EPROBE_DEFER; + } + + omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; + ret = extcon_register_interest(&omap->extcon_vbus_dev, + edev->name, "USB", + &omap->vbus_nb); + if (ret < 0) + dev_vdbg(omap->dev, "failed to register notifier for USB\n"); + + omap->id_nb.notifier_call = dwc3_omap_id_notifier; + ret = extcon_register_interest(&omap->extcon_id_dev, + edev->name, "USB-HOST", + &omap->id_nb); + if (ret < 0) + dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n"); + + if (extcon_get_cable_state(edev, "USB") == true) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); + if (extcon_get_cable_state(edev, "USB-HOST") == true) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); + } + + return 0; +} + static int dwc3_omap_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -430,7 +466,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) struct dwc3_omap *omap; struct resource *res; struct device *dev = &pdev->dev; - struct extcon_dev *edev; struct regulator *vbus_reg = NULL; int ret; @@ -502,31 +537,9 @@ static int dwc3_omap_probe(struct platform_device *pdev) dwc3_omap_enable_irqs(omap); - if (of_property_read_bool(node, "extcon")) { - edev = extcon_get_edev_by_phandle(dev, 0); - if (IS_ERR(edev)) { - dev_vdbg(dev, "couldn't get extcon device\n"); - ret = -EPROBE_DEFER; - goto err2; - } - - omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; - ret = extcon_register_interest(&omap->extcon_vbus_dev, - edev->name, "USB", &omap->vbus_nb); - if (ret < 0) - dev_vdbg(dev, "failed to register notifier for USB\n"); - omap->id_nb.notifier_call = dwc3_omap_id_notifier; - ret = extcon_register_interest(&omap->extcon_id_dev, edev->name, - "USB-HOST", &omap->id_nb); - if (ret < 0) - dev_vdbg(dev, - "failed to register notifier for USB-HOST\n"); - - if (extcon_get_cable_state(edev, "USB") == true) - dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); - if (extcon_get_cable_state(edev, "USB-HOST") == true) - dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); - } + ret = dwc3_omap_extcon_register(omap); + if (ret < 0) + goto err2; ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { From 97b4129e0562c74e6d75ff081e93202c71aecaa3 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:22:09 +0530 Subject: [PATCH 136/211] usb: musb: core: Handle Babble condition only in HOST mode BABBLE and RESET share the same interrupt. The interrupt is considered to be RESET if MUSB is in peripheral mode and as a BABBLE if MUSB is in HOST mode. Handle babble condition iff MUSB is in HOST mode. Signed-off-by: George Cherian Tested-by: Bin Liu Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 3c6043c1b8ac..0ad9551ffad1 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -849,7 +849,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } /* handle babble condition */ - if (int_usb & MUSB_INTR_BABBLE) + if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) schedule_work(&musb->recover_work); #if 0 From 675ae7631150a54eac81806ccb1bf16aba2bead8 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:22:10 +0530 Subject: [PATCH 137/211] usb: musb: core: Convert babble recover work to delayed work During babble condition both first disconnect of devices are initiated. Make sure MUSB controller is reset and re-initialized after all disconnects. To acheive this schedule a delayed work for babble recovery. While at that convert udelay to usleep_range. Refer Documentation/timers/timers-howto.txt Signed-off-by: George Cherian Tested-by: Bin Liu Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 15 ++++++++------- drivers/usb/musb/musb_core.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 0ad9551ffad1..c0ce09f8fdcd 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -850,7 +850,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, /* handle babble condition */ if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) - schedule_work(&musb->recover_work); + schedule_delayed_work(&musb->recover_work, + msecs_to_jiffies(100)); #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or @@ -1751,16 +1752,16 @@ static void musb_irq_work(struct work_struct *data) /* Recover from babble interrupt conditions */ static void musb_recover_work(struct work_struct *data) { - struct musb *musb = container_of(data, struct musb, recover_work); + struct musb *musb = container_of(data, struct musb, recover_work.work); int status; musb_platform_reset(musb); usb_phy_vbus_off(musb->xceiv); - udelay(100); + usleep_range(100, 200); usb_phy_vbus_on(musb->xceiv); - udelay(100); + usleep_range(100, 200); /* * When a babble condition occurs, the musb controller removes the @@ -1943,7 +1944,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* Init IRQ workqueue before request_irq */ INIT_WORK(&musb->irq_work, musb_irq_work); - INIT_WORK(&musb->recover_work, musb_recover_work); + INIT_DELAYED_WORK(&musb->recover_work, musb_recover_work); INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); @@ -2039,7 +2040,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) fail3: cancel_work_sync(&musb->irq_work); - cancel_work_sync(&musb->recover_work); + cancel_delayed_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); if (musb->dma_controller) @@ -2105,7 +2106,7 @@ static int musb_remove(struct platform_device *pdev) dma_controller_destroy(musb->dma_controller); cancel_work_sync(&musb->irq_work); - cancel_work_sync(&musb->recover_work); + cancel_delayed_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); musb_free(musb); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index d155a156f240..9241025f6965 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -297,7 +297,7 @@ struct musb { irqreturn_t (*isr)(int, void *); struct work_struct irq_work; - struct work_struct recover_work; + struct delayed_work recover_work; struct delayed_work deassert_reset_work; struct delayed_work finish_resume_work; u16 hwvers; From d871c622e202efc663f953a4fcbd2cba6a28a24f Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:22:11 +0530 Subject: [PATCH 138/211] usb: musb: core: Convert the musb_platform_reset to have a return value. Currently musb_platform_reset() is only used by dsps. In case of BABBLE interrupt for other platforms the musb_platform_reset() is a NOP. In such situations no need to re-initialize the endpoints. Also in the latest silicon revision of AM335x, we do have a babble recovery mechanism without resetting the IP block. In preperation to add that support its better to have a rest_done return for musb_platform_reset(). Signed-off-by: George Cherian Tested-by: Bin Liu Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 10 ++++++---- drivers/usb/musb/musb_core.h | 10 ++++++---- drivers/usb/musb/musb_dsps.c | 3 ++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index c0ce09f8fdcd..b841ee0bff06 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1753,9 +1753,11 @@ static void musb_irq_work(struct work_struct *data) static void musb_recover_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, recover_work.work); - int status; + int status, ret; - musb_platform_reset(musb); + ret = musb_platform_reset(musb); + if (ret) + return; usb_phy_vbus_off(musb->xceiv); usleep_range(100, 200); @@ -1764,8 +1766,8 @@ static void musb_recover_work(struct work_struct *data) usleep_range(100, 200); /* - * When a babble condition occurs, the musb controller removes the - * session bit and the endpoint config is lost. + * When a babble condition occurs, the musb controller + * removes the session bit and the endpoint config is lost. */ if (musb->dyn_fifo) status = ep_config_from_table(musb); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 9241025f6965..414e57a984bb 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -192,7 +192,7 @@ struct musb_platform_ops { int (*set_mode)(struct musb *musb, u8 mode); void (*try_idle)(struct musb *musb, unsigned long timeout); - void (*reset)(struct musb *musb); + int (*reset)(struct musb *musb); int (*vbus_status)(struct musb *musb); void (*set_vbus)(struct musb *musb, int on); @@ -555,10 +555,12 @@ static inline void musb_platform_try_idle(struct musb *musb, musb->ops->try_idle(musb, timeout); } -static inline void musb_platform_reset(struct musb *musb) +static inline int musb_platform_reset(struct musb *musb) { - if (musb->ops->reset) - musb->ops->reset(musb); + if (!musb->ops->reset) + return -EINVAL; + + return musb->ops->reset(musb); } static inline int musb_platform_get_vbus_status(struct musb *musb) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index b29f59f718bb..53a4351aef97 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -544,7 +544,7 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) return 0; } -static void dsps_musb_reset(struct musb *musb) +static int dsps_musb_reset(struct musb *musb) { struct device *dev = musb->controller; struct dsps_glue *glue = dev_get_drvdata(dev->parent); @@ -556,6 +556,7 @@ static void dsps_musb_reset(struct musb *musb) usleep_range(100, 200); usb_phy_init(musb->xceiv); + return 0; } static struct musb_platform_ops dsps_ops = { From 371254ce462fcea2d09ffa30e20f01538b833080 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 Jul 2014 18:22:12 +0530 Subject: [PATCH 139/211] usb: musb: dsps: Add the sw_babble_control() and Enable for newer silicon Add sw_babble_control() logic to differentiate between transient babble and real babble condition. Also add the SW babble control register definitions. Babble control register logic is implemented in the latest revision of AM335x. Find whether we are running on newer silicon. The babble control register reads 0x4 by default in newer silicon as opposed to 0 in old versions of AM335x. Based on this enable the sw babble control logic. Signed-off-by: George Cherian Tested-by: Bin Liu Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 89 +++++++++++++++++++++++++++++++++--- drivers/usb/musb/musb_regs.h | 7 +++ 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 53a4351aef97..f119a62140ef 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -144,6 +144,7 @@ struct dsps_glue { const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ struct timer_list timer; /* otg_workaround timer */ unsigned long last_timer; /* last timer data for each instance */ + bool sw_babble_enabled; struct dsps_context context; struct debugfs_regset32 regset; @@ -477,6 +478,19 @@ static int dsps_musb_init(struct musb *musb) val &= ~(1 << wrp->otg_disable); dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); + /* + * Check whether the dsps version has babble control enabled. + * In latest silicon revision the babble control logic is enabled. + * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control + * logic enabled. + */ + val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + if (val == MUSB_BABBLE_RCV_DISABLE) { + glue->sw_babble_enabled = true; + val |= MUSB_BABBLE_SW_SESSION_CTRL; + dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); + } + ret = dsps_musb_dbg_init(musb, glue); if (ret) return ret; @@ -544,19 +558,82 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) return 0; } +static bool sw_babble_control(struct musb *musb) +{ + u8 babble_ctl; + bool session_restart = false; + + babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", + babble_ctl); + /* + * check line monitor flag to check whether babble is + * due to noise + */ + dev_dbg(musb->controller, "STUCK_J is %s\n", + babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset"); + + if (babble_ctl & MUSB_BABBLE_STUCK_J) { + int timeout = 10; + + /* + * babble is due to noise, then set transmit idle (d7 bit) + * to resume normal operation + */ + babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; + dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); + + /* wait till line monitor flag cleared */ + dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); + do { + babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + udelay(1); + } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); + + /* check whether stuck_at_j bit cleared */ + if (babble_ctl & MUSB_BABBLE_STUCK_J) { + /* + * real babble condition has occurred + * restart the controller to start the + * session again + */ + dev_dbg(musb->controller, "J not cleared, misc (%x)\n", + babble_ctl); + session_restart = true; + } + } else { + session_restart = true; + } + + return session_restart; +} + static int dsps_musb_reset(struct musb *musb) { struct device *dev = musb->controller; struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; + int session_restart = 0; - dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); - usleep_range(100, 200); - usb_phy_shutdown(musb->xceiv); - usleep_range(100, 200); - usb_phy_init(musb->xceiv); + if (glue->sw_babble_enabled) + session_restart = sw_babble_control(musb); + /* + * In case of new silicon version babble condition can be recovered + * without resetting the MUSB. But for older silicon versions, MUSB + * reset is needed + */ + if (session_restart || !glue->sw_babble_enabled) { + dev_info(musb->controller, "Restarting MUSB to recover from Babble\n"); + dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); + usleep_range(100, 200); + usb_phy_shutdown(musb->xceiv); + usleep_range(100, 200); + usb_phy_init(musb->xceiv); + session_restart = 1; + } - return 0; + return !session_restart; } static struct musb_platform_ops dsps_ops = { diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 03f2655af290..b9bcda5e3945 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -72,6 +72,12 @@ #define MUSB_DEVCTL_HR 0x02 #define MUSB_DEVCTL_SESSION 0x01 +/* BABBLE_CTL */ +#define MUSB_BABBLE_FORCE_TXIDLE 0x80 +#define MUSB_BABBLE_SW_SESSION_CTRL 0x40 +#define MUSB_BABBLE_STUCK_J 0x20 +#define MUSB_BABBLE_RCV_DISABLE 0x04 + /* MUSB ULPI VBUSCONTROL */ #define MUSB_ULPI_USE_EXTVBUS 0x01 #define MUSB_ULPI_USE_EXTVBUSIND 0x02 @@ -246,6 +252,7 @@ */ #define MUSB_DEVCTL 0x60 /* 8 bit */ +#define MUSB_BABBLE_CTL 0x61 /* 8 bit */ /* These are always controlled through the INDEX register */ #define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */ From f2267089ea17fa97b796b1b4247e3f8957655df3 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Tue, 15 Jul 2014 22:07:40 +0800 Subject: [PATCH 140/211] usb: gadget: composite: dequeue cdev->req before free it in composite_dev_cleanup This patch try to dequeue the cdev->req to guarantee the request is not queued before free it. Signed-off-by: Li Jun Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f80151932053..6935a822ce2b 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1956,6 +1956,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) } if (cdev->req) { kfree(cdev->req->buf); + usb_ep_dequeue(cdev->gadget->ep0, cdev->req); usb_ep_free_request(cdev->gadget->ep0, cdev->req); } cdev->next_string_id = 0; From 8ecef00fe1f33658ee36e902dba6850b51312073 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 10 Jul 2014 09:53:59 +0200 Subject: [PATCH 141/211] usb: renesas_usbhs: add R-Car Gen. 2 init and power control In preparation for DT conversion to reduce reliance on platform device callbacks. Signed-off-by: Ulrich Hecht Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/Makefile | 2 +- drivers/usb/renesas_usbhs/common.c | 66 +++++++++++++++++++++++-- drivers/usb/renesas_usbhs/common.h | 2 + drivers/usb/renesas_usbhs/rcar2.c | 77 ++++++++++++++++++++++++++++++ drivers/usb/renesas_usbhs/rcar2.h | 4 ++ include/linux/usb/renesas_usbhs.h | 6 +++ 6 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 drivers/usb/renesas_usbhs/rcar2.c create mode 100644 drivers/usb/renesas_usbhs/rcar2.h diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile index bc8aef4311a1..9e47f477b6d2 100644 --- a/drivers/usb/renesas_usbhs/Makefile +++ b/drivers/usb/renesas_usbhs/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o -renesas_usbhs-y := common.o mod.o pipe.o fifo.o +renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),) renesas_usbhs-y += mod_host.o diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 17267b0a2e95..1b9bf8d83235 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -15,12 +15,14 @@ * */ #include +#include #include #include #include #include #include #include "common.h" +#include "rcar2.h" /* * image of renesas_usbhs @@ -284,6 +286,8 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv) /* * platform default param */ + +/* commonly used on old SH-Mobile SoCs */ static u32 usbhsc_default_pipe_type[] = { USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, @@ -297,6 +301,26 @@ static u32 usbhsc_default_pipe_type[] = { USB_ENDPOINT_XFER_INT, }; +/* commonly used on newer SH-Mobile and R-Car SoCs */ +static u32 usbhsc_new_pipe_type[] = { + USB_ENDPOINT_XFER_CONTROL, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, +}; + /* * power control */ @@ -423,8 +447,7 @@ static int usbhs_probe(struct platform_device *pdev) int ret; /* check platform information */ - if (!info || - !info->platform_callback.get_id) { + if (!info) { dev_err(&pdev->dev, "no platform information\n"); return -EINVAL; } @@ -451,13 +474,32 @@ static int usbhs_probe(struct platform_device *pdev) /* * care platform info */ - memcpy(&priv->pfunc, - &info->platform_callback, - sizeof(struct renesas_usbhs_platform_callback)); + memcpy(&priv->dparam, &info->driver_param, sizeof(struct renesas_usbhs_driver_param)); + switch (priv->dparam.type) { + case USBHS_TYPE_R8A7790: + case USBHS_TYPE_R8A7791: + priv->pfunc = usbhs_rcar2_ops; + if (!priv->dparam.pipe_type) { + priv->dparam.pipe_type = usbhsc_new_pipe_type; + priv->dparam.pipe_size = + ARRAY_SIZE(usbhsc_new_pipe_type); + } + break; + default: + if (!info->platform_callback.get_id) { + dev_err(&pdev->dev, "no platform callbacks"); + return -EINVAL; + } + memcpy(&priv->pfunc, + &info->platform_callback, + sizeof(struct renesas_usbhs_platform_callback)); + break; + } + /* set driver callback functions for platform */ dfunc = &info->driver_callback; dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug; @@ -507,6 +549,20 @@ static int usbhs_probe(struct platform_device *pdev) */ usbhs_sys_clock_ctrl(priv, 0); + /* check GPIO determining if USB function should be enabled */ + if (priv->dparam.enable_gpio) { + gpio_request_one(priv->dparam.enable_gpio, GPIOF_IN, NULL); + ret = !gpio_get_value(priv->dparam.enable_gpio); + gpio_free(priv->dparam.enable_gpio); + if (ret) { + dev_warn(&pdev->dev, + "USB function not selected (GPIO %d)\n", + priv->dparam.enable_gpio); + ret = -ENOTSUPP; + goto probe_end_mod_exit; + } + } + /* * platform call * diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index c69dd2fba360..a7996da6a1bd 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -268,6 +268,8 @@ struct usbhs_priv { * fifo control */ struct usbhs_fifo_info fifo_info; + + struct usb_phy *phy; }; /* diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c new file mode 100644 index 000000000000..e6b9dcc1c289 --- /dev/null +++ b/drivers/usb/renesas_usbhs/rcar2.c @@ -0,0 +1,77 @@ +/* + * Renesas USB driver R-Car Gen. 2 initialization and power control + * + * Copyright (C) 2014 Ulrich Hecht + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include "common.h" +#include "rcar2.h" + +static int usbhs_rcar2_hardware_init(struct platform_device *pdev) +{ + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + struct usb_phy *phy; + + phy = usb_get_phy_dev(&pdev->dev, 0); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + priv->phy = phy; + return 0; +} + +static int usbhs_rcar2_hardware_exit(struct platform_device *pdev) +{ + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + + if (!priv->phy) + return 0; + + usb_put_phy(priv->phy); + priv->phy = NULL; + + return 0; +} + +static int usbhs_rcar2_power_ctrl(struct platform_device *pdev, + void __iomem *base, int enable) +{ + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + + if (!priv->phy) + return -ENODEV; + + if (enable) { + int retval = usb_phy_init(priv->phy); + + if (!retval) + retval = usb_phy_set_suspend(priv->phy, 0); + return retval; + } + + usb_phy_set_suspend(priv->phy, 1); + usb_phy_shutdown(priv->phy); + return 0; +} + +static int usbhs_rcar2_get_id(struct platform_device *pdev) +{ + return USBHS_GADGET; +} + +const struct renesas_usbhs_platform_callback usbhs_rcar2_ops = { + .hardware_init = usbhs_rcar2_hardware_init, + .hardware_exit = usbhs_rcar2_hardware_exit, + .power_ctrl = usbhs_rcar2_power_ctrl, + .get_id = usbhs_rcar2_get_id, +}; diff --git a/drivers/usb/renesas_usbhs/rcar2.h b/drivers/usb/renesas_usbhs/rcar2.h new file mode 100644 index 000000000000..f07f10d9b3b2 --- /dev/null +++ b/drivers/usb/renesas_usbhs/rcar2.h @@ -0,0 +1,4 @@ +#include "common.h" + +extern const struct renesas_usbhs_platform_callback + usbhs_rcar2_ops; diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index e452ba6ec6bd..d5952bb66752 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -153,6 +153,9 @@ struct renesas_usbhs_driver_param { */ int pio_dma_border; /* default is 64byte */ + u32 type; + u32 enable_gpio; + /* * option: */ @@ -160,6 +163,9 @@ struct renesas_usbhs_driver_param { u32 has_sudmac:1; /* for SUDMAC */ }; +#define USBHS_TYPE_R8A7790 1 +#define USBHS_TYPE_R8A7791 2 + /* * option: * From 8443f2d2b7782fef35fe579bf1eb612c24951486 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 15 Jul 2014 13:09:44 +0200 Subject: [PATCH 142/211] usb: gadget: Gadget directory cleanup - group legacy gadgets The drivers/usb/gadget directory contains many files. Files which are related can be distributed into separate directories. This patch moves the legacy gadgets (i.e. those not using configfs) into a separate directory. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 461 +---------------- drivers/usb/gadget/Makefile | 44 +- drivers/usb/gadget/legacy/Kconfig | 475 ++++++++++++++++++ drivers/usb/gadget/legacy/Makefile | 42 ++ drivers/usb/gadget/{ => legacy}/acm_ms.c | 0 drivers/usb/gadget/{ => legacy}/audio.c | 0 drivers/usb/gadget/{ => legacy}/cdc2.c | 0 drivers/usb/gadget/{ => legacy}/dbgp.c | 0 drivers/usb/gadget/{ => legacy}/ether.c | 0 drivers/usb/gadget/{ => legacy}/g_ffs.c | 0 drivers/usb/gadget/{ => legacy}/gmidi.c | 0 drivers/usb/gadget/{ => legacy}/hid.c | 0 drivers/usb/gadget/{ => legacy}/inode.c | 0 .../usb/gadget/{ => legacy}/mass_storage.c | 0 drivers/usb/gadget/{ => legacy}/multi.c | 0 drivers/usb/gadget/{ => legacy}/ncm.c | 0 drivers/usb/gadget/{ => legacy}/nokia.c | 0 drivers/usb/gadget/{ => legacy}/printer.c | 0 drivers/usb/gadget/{ => legacy}/serial.c | 0 .../usb/gadget/{ => legacy}/tcm_usb_gadget.c | 0 .../usb/gadget/{ => legacy}/tcm_usb_gadget.h | 0 drivers/usb/gadget/{ => legacy}/webcam.c | 0 drivers/usb/gadget/{ => legacy}/zero.c | 0 23 files changed, 521 insertions(+), 501 deletions(-) create mode 100644 drivers/usb/gadget/legacy/Kconfig create mode 100644 drivers/usb/gadget/legacy/Makefile rename drivers/usb/gadget/{ => legacy}/acm_ms.c (100%) rename drivers/usb/gadget/{ => legacy}/audio.c (100%) rename drivers/usb/gadget/{ => legacy}/cdc2.c (100%) rename drivers/usb/gadget/{ => legacy}/dbgp.c (100%) rename drivers/usb/gadget/{ => legacy}/ether.c (100%) rename drivers/usb/gadget/{ => legacy}/g_ffs.c (100%) rename drivers/usb/gadget/{ => legacy}/gmidi.c (100%) rename drivers/usb/gadget/{ => legacy}/hid.c (100%) rename drivers/usb/gadget/{ => legacy}/inode.c (100%) rename drivers/usb/gadget/{ => legacy}/mass_storage.c (100%) rename drivers/usb/gadget/{ => legacy}/multi.c (100%) rename drivers/usb/gadget/{ => legacy}/ncm.c (100%) rename drivers/usb/gadget/{ => legacy}/nokia.c (100%) rename drivers/usb/gadget/{ => legacy}/printer.c (100%) rename drivers/usb/gadget/{ => legacy}/serial.c (100%) rename drivers/usb/gadget/{ => legacy}/tcm_usb_gadget.c (100%) rename drivers/usb/gadget/{ => legacy}/tcm_usb_gadget.h (100%) rename drivers/usb/gadget/{ => legacy}/webcam.c (100%) rename drivers/usb/gadget/{ => legacy}/zero.c (100%) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 49e434ec527d..2986a4369df4 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -722,466 +722,7 @@ config USB_CONFIGFS_F_FS implemented in kernel space (for instance Ethernet, serial or mass storage) and other are implemented in user space. -config USB_ZERO - tristate "Gadget Zero (DEVELOPMENT)" - select USB_LIBCOMPOSITE - select USB_F_SS_LB - help - Gadget Zero is a two-configuration device. It either sinks and - sources bulk data; or it loops back a configurable number of - transfers. It also implements control requests, for "chapter 9" - conformance. The driver needs only two bulk-capable endpoints, so - it can work on top of most device-side usb controllers. It's - useful for testing, and is also a working example showing how - USB "gadget drivers" can be written. - - Make this be the first driver you try using on top of any new - USB peripheral controller driver. Then you can use host-side - test software, like the "usbtest" driver, to put your hardware - and its driver through a basic set of functional tests. - - Gadget Zero also works with the host-side "usb-skeleton" driver, - and with many kinds of host-side test software. You may need - to tweak product and vendor IDs before host software knows about - this device, and arrange to select an appropriate configuration. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_zero". - -config USB_ZERO_HNPTEST - boolean "HNP Test Device" - depends on USB_ZERO && USB_OTG - help - You can configure this device to enumerate using the device - identifiers of the USB-OTG test device. That means that when - this gadget connects to another OTG device, with this one using - the "B-Peripheral" role, that device will use HNP to let this - one serve as the USB host instead (in the "B-Host" role). - -config USB_AUDIO - tristate "Audio Gadget" - depends on SND - select USB_LIBCOMPOSITE - select SND_PCM - help - This Gadget Audio driver is compatible with USB Audio Class - specification 2.0. It implements 1 AudioControl interface, - 1 AudioStreaming Interface each for USB-OUT and USB-IN. - Number of channels, sample rate and sample size can be - specified as module parameters. - This driver doesn't expect any real Audio codec to be present - on the device - the audio streams are simply sinked to and - sourced from a virtual ALSA sound card created. The user-space - application may choose to do whatever it wants with the data - received from the USB Host and choose to provide whatever it - wants as audio data to the USB Host. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_audio". - -config GADGET_UAC1 - bool "UAC 1.0 (Legacy)" - depends on USB_AUDIO - help - If you instead want older UAC Spec-1.0 driver that also has audio - paths hardwired to the Audio codec chip on-board and doesn't work - without one. - -config USB_ETH - tristate "Ethernet Gadget (with CDC Ethernet support)" - depends on NET - select USB_LIBCOMPOSITE - select USB_U_ETHER - select USB_F_ECM - select USB_F_SUBSET - select CRC32 - help - This driver implements Ethernet style communication, in one of - several ways: - - - The "Communication Device Class" (CDC) Ethernet Control Model. - That protocol is often avoided with pure Ethernet adapters, in - favor of simpler vendor-specific hardware, but is widely - supported by firmware for smart network devices. - - - On hardware can't implement that protocol, a simple CDC subset - is used, placing fewer demands on USB. - - - CDC Ethernet Emulation Model (EEM) is a newer standard that has - a simpler interface that can be used by more USB hardware. - - RNDIS support is an additional option, more demanding than than - subset. - - Within the USB device, this gadget driver exposes a network device - "usbX", where X depends on what other networking devices you have. - Treat it like a two-node Ethernet link: host, and gadget. - - The Linux-USB host-side "usbnet" driver interoperates with this - driver, so that deep I/O queues can be supported. On 2.4 kernels, - use "CDCEther" instead, if you're using the CDC option. That CDC - mode should also interoperate with standard CDC Ethernet class - drivers on other host operating systems. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_ether". - -config USB_ETH_RNDIS - bool "RNDIS support" - depends on USB_ETH - select USB_LIBCOMPOSITE - select USB_F_RNDIS - default y - help - Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, - and Microsoft provides redistributable binary RNDIS drivers for - older versions of Windows. - - If you say "y" here, the Ethernet gadget driver will try to provide - a second device configuration, supporting RNDIS to talk to such - Microsoft USB hosts. - - To make MS-Windows work with this, use Documentation/usb/linux.inf - as the "driver info file". For versions of MS-Windows older than - XP, you'll need to download drivers from Microsoft's website; a URL - is given in comments found in that info file. - -config USB_ETH_EEM - bool "Ethernet Emulation Model (EEM) support" - depends on USB_ETH - select USB_LIBCOMPOSITE - select USB_F_EEM - default n - help - CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM - and therefore can be supported by more hardware. Technically ECM and - EEM are designed for different applications. The ECM model extends - the network interface to the target (e.g. a USB cable modem), and the - EEM model is for mobile devices to communicate with hosts using - ethernet over USB. For Linux gadgets, however, the interface with - the host is the same (a usbX device), so the differences are minimal. - - If you say "y" here, the Ethernet gadget driver will use the EEM - protocol rather than ECM. If unsure, say "n". - -config USB_G_NCM - tristate "Network Control Model (NCM) support" - depends on NET - select USB_LIBCOMPOSITE - select USB_U_ETHER - select USB_F_NCM - select CRC32 - help - This driver implements USB CDC NCM subclass standard. NCM is - an advanced protocol for Ethernet encapsulation, allows grouping - of several ethernet frames into one USB transfer and different - alignment possibilities. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_ncm". - -config USB_GADGETFS - tristate "Gadget Filesystem" - help - This driver provides a filesystem based API that lets user mode - programs implement a single-configuration USB device, including - endpoint I/O and control requests that don't relate to enumeration. - All endpoints, transfer speeds, and transfer types supported by - the hardware are available, through read() and write() calls. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "gadgetfs". - -config USB_FUNCTIONFS - tristate "Function Filesystem" - select USB_LIBCOMPOSITE - select USB_F_FS - select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS) - help - The Function Filesystem (FunctionFS) lets one create USB - composite functions in user space in the same way GadgetFS - lets one create USB gadgets in user space. This allows creation - of composite gadgets such that some of the functions are - implemented in kernel space (for instance Ethernet, serial or - mass storage) and other are implemented in user space. - - If you say "y" or "m" here you will be able what kind of - configurations the gadget will provide. - - Say "y" to link the driver statically, or "m" to build - a dynamically linked module called "g_ffs". - -config USB_FUNCTIONFS_ETH - bool "Include configuration with CDC ECM (Ethernet)" - depends on USB_FUNCTIONFS && NET - select USB_U_ETHER - select USB_F_ECM - select USB_F_SUBSET - help - Include a configuration with CDC ECM function (Ethernet) and the - Function Filesystem. - -config USB_FUNCTIONFS_RNDIS - bool "Include configuration with RNDIS (Ethernet)" - depends on USB_FUNCTIONFS && NET - select USB_U_ETHER - select USB_F_RNDIS - help - Include a configuration with RNDIS function (Ethernet) and the Filesystem. - -config USB_FUNCTIONFS_GENERIC - bool "Include 'pure' configuration" - depends on USB_FUNCTIONFS - help - Include a configuration with the Function Filesystem alone with - no Ethernet interface. - -config USB_MASS_STORAGE - tristate "Mass Storage Gadget" - depends on BLOCK - select USB_LIBCOMPOSITE - select USB_F_MASS_STORAGE - help - The Mass Storage Gadget acts as a USB Mass Storage disk drive. - As its storage repository it can use a regular file or a block - device (in much the same way as the "loop" device driver), - specified as a module parameter or sysfs option. - - This driver is a replacement for now removed File-backed - Storage Gadget (g_file_storage). - - Say "y" to link the driver statically, or "m" to build - a dynamically linked module called "g_mass_storage". - -config USB_GADGET_TARGET - tristate "USB Gadget Target Fabric Module" - depends on TARGET_CORE - select USB_LIBCOMPOSITE - help - This fabric is an USB gadget. Two USB protocols are supported that is - BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is - advertised on alternative interface 0 (primary) and UAS is on - alternative interface 1. Both protocols can work on USB2.0 and USB3.0. - UAS utilizes the USB 3.0 feature called streams support. - -config USB_G_SERIAL - tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" - depends on TTY - select USB_U_SERIAL - select USB_F_ACM - select USB_F_SERIAL - select USB_F_OBEX - select USB_LIBCOMPOSITE - help - The Serial Gadget talks to the Linux-USB generic serial driver. - This driver supports a CDC-ACM module option, which can be used - to interoperate with MS-Windows hosts or with the Linux-USB - "cdc-acm" driver. - - This driver also supports a CDC-OBEX option. You will need a - user space OBEX server talking to /dev/ttyGS*, since the kernel - itself doesn't implement the OBEX protocol. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_serial". - - For more information, see Documentation/usb/gadget_serial.txt - which includes instructions and a "driver info file" needed to - make MS-Windows work with CDC ACM. - -config USB_MIDI_GADGET - tristate "MIDI Gadget" - depends on SND - select USB_LIBCOMPOSITE - select SND_RAWMIDI - help - The MIDI Gadget acts as a USB Audio device, with one MIDI - input and one MIDI output. These MIDI jacks appear as - a sound "card" in the ALSA sound system. Other MIDI - connections can then be made on the gadget system, using - ALSA's aconnect utility etc. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_midi". - -config USB_G_PRINTER - tristate "Printer Gadget" - select USB_LIBCOMPOSITE - help - The Printer Gadget channels data between the USB host and a - userspace program driving the print engine. The user space - program reads and writes the device file /dev/g_printer to - receive or send printer data. It can use ioctl calls to - the device file to get or set printer status. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_printer". - - For more information, see Documentation/usb/gadget_printer.txt - which includes sample code for accessing the device file. - -if TTY - -config USB_CDC_COMPOSITE - tristate "CDC Composite Device (Ethernet and ACM)" - depends on NET - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_U_ETHER - select USB_F_ACM - select USB_F_ECM - help - This driver provides two functions in one configuration: - a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link. - - This driver requires four bulk and two interrupt endpoints, - plus the ability to handle altsettings. Not all peripheral - controllers are that capable. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module. - -config USB_G_NOKIA - tristate "Nokia composite gadget" - depends on PHONET - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_U_ETHER - select USB_F_ACM - select USB_F_OBEX - select USB_F_PHONET - select USB_F_ECM - help - The Nokia composite gadget provides support for acm, obex - and phonet in only one composite gadget driver. - - It's only really useful for N900 hardware. If you're building - a kernel for N900, say Y or M here. If unsure, say N. - -config USB_G_ACM_MS - tristate "CDC Composite Device (ACM and mass storage)" - depends on BLOCK - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_F_ACM - select USB_F_MASS_STORAGE - help - This driver provides two functions in one configuration: - a mass storage, and a CDC ACM (serial port) link. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_acm_ms". - -config USB_G_MULTI - tristate "Multifunction Composite Gadget" - depends on BLOCK && NET - select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_U_ETHER - select USB_F_ACM - select USB_F_MASS_STORAGE - help - The Multifunction Composite Gadget provides Ethernet (RNDIS - and/or CDC Ethernet), mass storage and ACM serial link - interfaces. - - You will be asked to choose which of the two configurations is - to be available in the gadget. At least one configuration must - be chosen to make the gadget usable. Selecting more than one - configuration will prevent Windows from automatically detecting - the gadget as a composite gadget, so an INF file will be needed to - use the gadget. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_multi". - -config USB_G_MULTI_RNDIS - bool "RNDIS + CDC Serial + Storage configuration" - depends on USB_G_MULTI - select USB_F_RNDIS - default y - help - This option enables a configuration with RNDIS, CDC Serial and - Mass Storage functions available in the Multifunction Composite - Gadget. This is the configuration dedicated for Windows since RNDIS - is Microsoft's protocol. - - If unsure, say "y". - -config USB_G_MULTI_CDC - bool "CDC Ethernet + CDC Serial + Storage configuration" - depends on USB_G_MULTI - default n - select USB_F_ECM - help - This option enables a configuration with CDC Ethernet (ECM), CDC - Serial and Mass Storage functions available in the Multifunction - Composite Gadget. - - If unsure, say "y". - -endif # TTY - -config USB_G_HID - tristate "HID Gadget" - select USB_LIBCOMPOSITE - help - The HID gadget driver provides generic emulation of USB - Human Interface Devices (HID). - - For more information, see Documentation/usb/gadget_hid.txt which - includes sample code for accessing the device files. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_hid". - -# Standalone / single function gadgets -config USB_G_DBGP - tristate "EHCI Debug Device Gadget" - depends on TTY - select USB_LIBCOMPOSITE - help - This gadget emulates an EHCI Debug device. This is useful when you want - to interact with an EHCI Debug Port. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_dbgp". - -if USB_G_DBGP -choice - prompt "EHCI Debug Device mode" - default USB_G_DBGP_SERIAL - -config USB_G_DBGP_PRINTK - depends on USB_G_DBGP - bool "printk" - help - Directly printk() received data. No interaction. - -config USB_G_DBGP_SERIAL - depends on USB_G_DBGP - select USB_U_SERIAL - bool "serial" - help - Userland can interact using /dev/ttyGSxxx. -endchoice -endif - -# put drivers that need isochronous transfer support (for audio -# or video class gadget drivers), or specific hardware, here. -config USB_G_WEBCAM - tristate "USB Webcam Gadget" - depends on VIDEO_DEV - select USB_LIBCOMPOSITE - select VIDEOBUF2_VMALLOC - help - The Webcam Gadget acts as a composite USB Audio and Video Class - device. It provides a userspace API to process UVC control requests - and stream video data to the host. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_webcam". +source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 49514ea60a98..61d2503ef561 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -1,8 +1,8 @@ # # USB peripheral controller drivers # -ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG -ccflags-$(CONFIG_USB_GADGET_VERBOSE) += -DVERBOSE_DEBUG +subdir-ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG +subdir-ccflags-$(CONFIG_USB_GADGET_VERBOSE) += -DVERBOSE_DEBUG obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o @@ -64,42 +64,4 @@ obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o -# -# USB gadget drivers -# -g_zero-y := zero.o -g_audio-y := audio.o -g_ether-y := ether.o -g_serial-y := serial.o -g_midi-y := gmidi.o -gadgetfs-y := inode.o -g_mass_storage-y := mass_storage.o -g_printer-y := printer.o -g_cdc-y := cdc2.o -g_multi-y := multi.o -g_hid-y := hid.o -g_dbgp-y := dbgp.o -g_nokia-y := nokia.o -g_webcam-y := webcam.o -g_ncm-y := ncm.o -g_acm_ms-y := acm_ms.o -g_tcm_usb_gadget-y := tcm_usb_gadget.o - -obj-$(CONFIG_USB_ZERO) += g_zero.o -obj-$(CONFIG_USB_AUDIO) += g_audio.o -obj-$(CONFIG_USB_ETH) += g_ether.o -obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o -obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o -obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o -obj-$(CONFIG_USB_G_SERIAL) += g_serial.o -obj-$(CONFIG_USB_G_PRINTER) += g_printer.o -obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o -obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o -obj-$(CONFIG_USB_G_HID) += g_hid.o -obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o -obj-$(CONFIG_USB_G_MULTI) += g_multi.o -obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o -obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o -obj-$(CONFIG_USB_G_NCM) += g_ncm.o -obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o -obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o +obj-$(CONFIG_USB_GADGET) += legacy/ diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig new file mode 100644 index 000000000000..aa376f006333 --- /dev/null +++ b/drivers/usb/gadget/legacy/Kconfig @@ -0,0 +1,475 @@ +# +# USB Gadget support on a system involves +# (a) a peripheral controller, and +# (b) the gadget driver using it. +# +# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! +# +# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). +# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). +# - Some systems have both kinds of controllers. +# +# With help from a special transceiver and a "Mini-AB" jack, systems with +# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). +# + +config USB_ZERO + tristate "Gadget Zero (DEVELOPMENT)" + select USB_LIBCOMPOSITE + select USB_F_SS_LB + help + Gadget Zero is a two-configuration device. It either sinks and + sources bulk data; or it loops back a configurable number of + transfers. It also implements control requests, for "chapter 9" + conformance. The driver needs only two bulk-capable endpoints, so + it can work on top of most device-side usb controllers. It's + useful for testing, and is also a working example showing how + USB "gadget drivers" can be written. + + Make this be the first driver you try using on top of any new + USB peripheral controller driver. Then you can use host-side + test software, like the "usbtest" driver, to put your hardware + and its driver through a basic set of functional tests. + + Gadget Zero also works with the host-side "usb-skeleton" driver, + and with many kinds of host-side test software. You may need + to tweak product and vendor IDs before host software knows about + this device, and arrange to select an appropriate configuration. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_zero". + +config USB_ZERO_HNPTEST + boolean "HNP Test Device" + depends on USB_ZERO && USB_OTG + help + You can configure this device to enumerate using the device + identifiers of the USB-OTG test device. That means that when + this gadget connects to another OTG device, with this one using + the "B-Peripheral" role, that device will use HNP to let this + one serve as the USB host instead (in the "B-Host" role). + +config USB_AUDIO + tristate "Audio Gadget" + depends on SND + select USB_LIBCOMPOSITE + select SND_PCM + help + This Gadget Audio driver is compatible with USB Audio Class + specification 2.0. It implements 1 AudioControl interface, + 1 AudioStreaming Interface each for USB-OUT and USB-IN. + Number of channels, sample rate and sample size can be + specified as module parameters. + This driver doesn't expect any real Audio codec to be present + on the device - the audio streams are simply sinked to and + sourced from a virtual ALSA sound card created. The user-space + application may choose to do whatever it wants with the data + received from the USB Host and choose to provide whatever it + wants as audio data to the USB Host. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_audio". + +config GADGET_UAC1 + bool "UAC 1.0 (Legacy)" + depends on USB_AUDIO + help + If you instead want older UAC Spec-1.0 driver that also has audio + paths hardwired to the Audio codec chip on-board and doesn't work + without one. + +config USB_ETH + tristate "Ethernet Gadget (with CDC Ethernet support)" + depends on NET + select USB_LIBCOMPOSITE + select USB_U_ETHER + select USB_F_ECM + select USB_F_SUBSET + select CRC32 + help + This driver implements Ethernet style communication, in one of + several ways: + + - The "Communication Device Class" (CDC) Ethernet Control Model. + That protocol is often avoided with pure Ethernet adapters, in + favor of simpler vendor-specific hardware, but is widely + supported by firmware for smart network devices. + + - On hardware can't implement that protocol, a simple CDC subset + is used, placing fewer demands on USB. + + - CDC Ethernet Emulation Model (EEM) is a newer standard that has + a simpler interface that can be used by more USB hardware. + + RNDIS support is an additional option, more demanding than than + subset. + + Within the USB device, this gadget driver exposes a network device + "usbX", where X depends on what other networking devices you have. + Treat it like a two-node Ethernet link: host, and gadget. + + The Linux-USB host-side "usbnet" driver interoperates with this + driver, so that deep I/O queues can be supported. On 2.4 kernels, + use "CDCEther" instead, if you're using the CDC option. That CDC + mode should also interoperate with standard CDC Ethernet class + drivers on other host operating systems. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_ether". + +config USB_ETH_RNDIS + bool "RNDIS support" + depends on USB_ETH + select USB_LIBCOMPOSITE + select USB_F_RNDIS + default y + help + Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, + and Microsoft provides redistributable binary RNDIS drivers for + older versions of Windows. + + If you say "y" here, the Ethernet gadget driver will try to provide + a second device configuration, supporting RNDIS to talk to such + Microsoft USB hosts. + + To make MS-Windows work with this, use Documentation/usb/linux.inf + as the "driver info file". For versions of MS-Windows older than + XP, you'll need to download drivers from Microsoft's website; a URL + is given in comments found in that info file. + +config USB_ETH_EEM + bool "Ethernet Emulation Model (EEM) support" + depends on USB_ETH + select USB_LIBCOMPOSITE + select USB_F_EEM + default n + help + CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM + and therefore can be supported by more hardware. Technically ECM and + EEM are designed for different applications. The ECM model extends + the network interface to the target (e.g. a USB cable modem), and the + EEM model is for mobile devices to communicate with hosts using + ethernet over USB. For Linux gadgets, however, the interface with + the host is the same (a usbX device), so the differences are minimal. + + If you say "y" here, the Ethernet gadget driver will use the EEM + protocol rather than ECM. If unsure, say "n". + +config USB_G_NCM + tristate "Network Control Model (NCM) support" + depends on NET + select USB_LIBCOMPOSITE + select USB_U_ETHER + select USB_F_NCM + select CRC32 + help + This driver implements USB CDC NCM subclass standard. NCM is + an advanced protocol for Ethernet encapsulation, allows grouping + of several ethernet frames into one USB transfer and different + alignment possibilities. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_ncm". + +config USB_GADGETFS + tristate "Gadget Filesystem" + help + This driver provides a filesystem based API that lets user mode + programs implement a single-configuration USB device, including + endpoint I/O and control requests that don't relate to enumeration. + All endpoints, transfer speeds, and transfer types supported by + the hardware are available, through read() and write() calls. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "gadgetfs". + +config USB_FUNCTIONFS + tristate "Function Filesystem" + select USB_LIBCOMPOSITE + select USB_F_FS + select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS) + help + The Function Filesystem (FunctionFS) lets one create USB + composite functions in user space in the same way GadgetFS + lets one create USB gadgets in user space. This allows creation + of composite gadgets such that some of the functions are + implemented in kernel space (for instance Ethernet, serial or + mass storage) and other are implemented in user space. + + If you say "y" or "m" here you will be able what kind of + configurations the gadget will provide. + + Say "y" to link the driver statically, or "m" to build + a dynamically linked module called "g_ffs". + +config USB_FUNCTIONFS_ETH + bool "Include configuration with CDC ECM (Ethernet)" + depends on USB_FUNCTIONFS && NET + select USB_U_ETHER + select USB_F_ECM + select USB_F_SUBSET + help + Include a configuration with CDC ECM function (Ethernet) and the + Function Filesystem. + +config USB_FUNCTIONFS_RNDIS + bool "Include configuration with RNDIS (Ethernet)" + depends on USB_FUNCTIONFS && NET + select USB_U_ETHER + select USB_F_RNDIS + help + Include a configuration with RNDIS function (Ethernet) and the Filesystem. + +config USB_FUNCTIONFS_GENERIC + bool "Include 'pure' configuration" + depends on USB_FUNCTIONFS + help + Include a configuration with the Function Filesystem alone with + no Ethernet interface. + +config USB_MASS_STORAGE + tristate "Mass Storage Gadget" + depends on BLOCK + select USB_LIBCOMPOSITE + select USB_F_MASS_STORAGE + help + The Mass Storage Gadget acts as a USB Mass Storage disk drive. + As its storage repository it can use a regular file or a block + device (in much the same way as the "loop" device driver), + specified as a module parameter or sysfs option. + + This driver is a replacement for now removed File-backed + Storage Gadget (g_file_storage). + + Say "y" to link the driver statically, or "m" to build + a dynamically linked module called "g_mass_storage". + +config USB_GADGET_TARGET + tristate "USB Gadget Target Fabric Module" + depends on TARGET_CORE + select USB_LIBCOMPOSITE + help + This fabric is an USB gadget. Two USB protocols are supported that is + BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is + advertised on alternative interface 0 (primary) and UAS is on + alternative interface 1. Both protocols can work on USB2.0 and USB3.0. + UAS utilizes the USB 3.0 feature called streams support. + +config USB_G_SERIAL + tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" + depends on TTY + select USB_U_SERIAL + select USB_F_ACM + select USB_F_SERIAL + select USB_F_OBEX + select USB_LIBCOMPOSITE + help + The Serial Gadget talks to the Linux-USB generic serial driver. + This driver supports a CDC-ACM module option, which can be used + to interoperate with MS-Windows hosts or with the Linux-USB + "cdc-acm" driver. + + This driver also supports a CDC-OBEX option. You will need a + user space OBEX server talking to /dev/ttyGS*, since the kernel + itself doesn't implement the OBEX protocol. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_serial". + + For more information, see Documentation/usb/gadget_serial.txt + which includes instructions and a "driver info file" needed to + make MS-Windows work with CDC ACM. + +config USB_MIDI_GADGET + tristate "MIDI Gadget" + depends on SND + select USB_LIBCOMPOSITE + select SND_RAWMIDI + help + The MIDI Gadget acts as a USB Audio device, with one MIDI + input and one MIDI output. These MIDI jacks appear as + a sound "card" in the ALSA sound system. Other MIDI + connections can then be made on the gadget system, using + ALSA's aconnect utility etc. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_midi". + +config USB_G_PRINTER + tristate "Printer Gadget" + select USB_LIBCOMPOSITE + help + The Printer Gadget channels data between the USB host and a + userspace program driving the print engine. The user space + program reads and writes the device file /dev/g_printer to + receive or send printer data. It can use ioctl calls to + the device file to get or set printer status. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_printer". + + For more information, see Documentation/usb/gadget_printer.txt + which includes sample code for accessing the device file. + +if TTY + +config USB_CDC_COMPOSITE + tristate "CDC Composite Device (Ethernet and ACM)" + depends on NET + select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_U_ETHER + select USB_F_ACM + select USB_F_ECM + help + This driver provides two functions in one configuration: + a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link. + + This driver requires four bulk and two interrupt endpoints, + plus the ability to handle altsettings. Not all peripheral + controllers are that capable. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module. + +config USB_G_NOKIA + tristate "Nokia composite gadget" + depends on PHONET + select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_U_ETHER + select USB_F_ACM + select USB_F_OBEX + select USB_F_PHONET + select USB_F_ECM + help + The Nokia composite gadget provides support for acm, obex + and phonet in only one composite gadget driver. + + It's only really useful for N900 hardware. If you're building + a kernel for N900, say Y or M here. If unsure, say N. + +config USB_G_ACM_MS + tristate "CDC Composite Device (ACM and mass storage)" + depends on BLOCK + select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_F_ACM + select USB_F_MASS_STORAGE + help + This driver provides two functions in one configuration: + a mass storage, and a CDC ACM (serial port) link. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_acm_ms". + +config USB_G_MULTI + tristate "Multifunction Composite Gadget" + depends on BLOCK && NET + select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS + select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_U_ETHER + select USB_F_ACM + select USB_F_MASS_STORAGE + help + The Multifunction Composite Gadget provides Ethernet (RNDIS + and/or CDC Ethernet), mass storage and ACM serial link + interfaces. + + You will be asked to choose which of the two configurations is + to be available in the gadget. At least one configuration must + be chosen to make the gadget usable. Selecting more than one + configuration will prevent Windows from automatically detecting + the gadget as a composite gadget, so an INF file will be needed to + use the gadget. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_multi". + +config USB_G_MULTI_RNDIS + bool "RNDIS + CDC Serial + Storage configuration" + depends on USB_G_MULTI + select USB_F_RNDIS + default y + help + This option enables a configuration with RNDIS, CDC Serial and + Mass Storage functions available in the Multifunction Composite + Gadget. This is the configuration dedicated for Windows since RNDIS + is Microsoft's protocol. + + If unsure, say "y". + +config USB_G_MULTI_CDC + bool "CDC Ethernet + CDC Serial + Storage configuration" + depends on USB_G_MULTI + default n + select USB_F_ECM + help + This option enables a configuration with CDC Ethernet (ECM), CDC + Serial and Mass Storage functions available in the Multifunction + Composite Gadget. + + If unsure, say "y". + +endif # TTY + +config USB_G_HID + tristate "HID Gadget" + select USB_LIBCOMPOSITE + help + The HID gadget driver provides generic emulation of USB + Human Interface Devices (HID). + + For more information, see Documentation/usb/gadget_hid.txt which + includes sample code for accessing the device files. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_hid". + +# Standalone / single function gadgets +config USB_G_DBGP + tristate "EHCI Debug Device Gadget" + depends on TTY + select USB_LIBCOMPOSITE + help + This gadget emulates an EHCI Debug device. This is useful when you want + to interact with an EHCI Debug Port. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_dbgp". + +if USB_G_DBGP +choice + prompt "EHCI Debug Device mode" + default USB_G_DBGP_SERIAL + +config USB_G_DBGP_PRINTK + depends on USB_G_DBGP + bool "printk" + help + Directly printk() received data. No interaction. + +config USB_G_DBGP_SERIAL + depends on USB_G_DBGP + select USB_U_SERIAL + bool "serial" + help + Userland can interact using /dev/ttyGSxxx. +endchoice +endif + +# put drivers that need isochronous transfer support (for audio +# or video class gadget drivers), or specific hardware, here. +config USB_G_WEBCAM + tristate "USB Webcam Gadget" + depends on VIDEO_DEV + select USB_LIBCOMPOSITE + select VIDEOBUF2_VMALLOC + help + The Webcam Gadget acts as a composite USB Audio and Video Class + device. It provides a userspace API to process UVC control requests + and stream video data to the host. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_webcam". diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile new file mode 100644 index 000000000000..fbb32aa6f690 --- /dev/null +++ b/drivers/usb/gadget/legacy/Makefile @@ -0,0 +1,42 @@ +# +# USB gadget drivers +# + +ccflags-y := -I$(PWD)/drivers/usb/gadget/ + +g_zero-y := zero.o +g_audio-y := audio.o +g_ether-y := ether.o +g_serial-y := serial.o +g_midi-y := gmidi.o +gadgetfs-y := inode.o +g_mass_storage-y := mass_storage.o +g_printer-y := printer.o +g_cdc-y := cdc2.o +g_multi-y := multi.o +g_hid-y := hid.o +g_dbgp-y := dbgp.o +g_nokia-y := nokia.o +g_webcam-y := webcam.o +g_ncm-y := ncm.o +g_acm_ms-y := acm_ms.o +g_tcm_usb_gadget-y := tcm_usb_gadget.o + +obj-$(CONFIG_USB_ZERO) += g_zero.o +obj-$(CONFIG_USB_AUDIO) += g_audio.o +obj-$(CONFIG_USB_ETH) += g_ether.o +obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o +obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o +obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o +obj-$(CONFIG_USB_G_SERIAL) += g_serial.o +obj-$(CONFIG_USB_G_PRINTER) += g_printer.o +obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o +obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o +obj-$(CONFIG_USB_G_HID) += g_hid.o +obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o +obj-$(CONFIG_USB_G_MULTI) += g_multi.o +obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o +obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o +obj-$(CONFIG_USB_G_NCM) += g_ncm.o +obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o +obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c similarity index 100% rename from drivers/usb/gadget/acm_ms.c rename to drivers/usb/gadget/legacy/acm_ms.c diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/legacy/audio.c similarity index 100% rename from drivers/usb/gadget/audio.c rename to drivers/usb/gadget/legacy/audio.c diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c similarity index 100% rename from drivers/usb/gadget/cdc2.c rename to drivers/usb/gadget/legacy/cdc2.c diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c similarity index 100% rename from drivers/usb/gadget/dbgp.c rename to drivers/usb/gadget/legacy/dbgp.c diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/legacy/ether.c similarity index 100% rename from drivers/usb/gadget/ether.c rename to drivers/usb/gadget/legacy/ether.c diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c similarity index 100% rename from drivers/usb/gadget/g_ffs.c rename to drivers/usb/gadget/legacy/g_ffs.c diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c similarity index 100% rename from drivers/usb/gadget/gmidi.c rename to drivers/usb/gadget/legacy/gmidi.c diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/legacy/hid.c similarity index 100% rename from drivers/usb/gadget/hid.c rename to drivers/usb/gadget/legacy/hid.c diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/legacy/inode.c similarity index 100% rename from drivers/usb/gadget/inode.c rename to drivers/usb/gadget/legacy/inode.c diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c similarity index 100% rename from drivers/usb/gadget/mass_storage.c rename to drivers/usb/gadget/legacy/mass_storage.c diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/legacy/multi.c similarity index 100% rename from drivers/usb/gadget/multi.c rename to drivers/usb/gadget/legacy/multi.c diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/legacy/ncm.c similarity index 100% rename from drivers/usb/gadget/ncm.c rename to drivers/usb/gadget/legacy/ncm.c diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/legacy/nokia.c similarity index 100% rename from drivers/usb/gadget/nokia.c rename to drivers/usb/gadget/legacy/nokia.c diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/legacy/printer.c similarity index 100% rename from drivers/usb/gadget/printer.c rename to drivers/usb/gadget/legacy/printer.c diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/legacy/serial.c similarity index 100% rename from drivers/usb/gadget/serial.c rename to drivers/usb/gadget/legacy/serial.c diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c similarity index 100% rename from drivers/usb/gadget/tcm_usb_gadget.c rename to drivers/usb/gadget/legacy/tcm_usb_gadget.c diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/legacy/tcm_usb_gadget.h similarity index 100% rename from drivers/usb/gadget/tcm_usb_gadget.h rename to drivers/usb/gadget/legacy/tcm_usb_gadget.h diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/legacy/webcam.c similarity index 100% rename from drivers/usb/gadget/webcam.c rename to drivers/usb/gadget/legacy/webcam.c diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/legacy/zero.c similarity index 100% rename from drivers/usb/gadget/zero.c rename to drivers/usb/gadget/legacy/zero.c From 90fccb529d241b55829701cfb9eb3086570f38b8 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 15 Jul 2014 13:09:45 +0200 Subject: [PATCH 143/211] usb: gadget: Gadget directory cleanup - group UDC drivers The drivers/usb/gadget directory contains many files. Files which are related can be distributed into separate directories. This patch moves the UDC drivers into a separate directory. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 371 +---------------- drivers/usb/gadget/Makefile | 31 +- drivers/usb/gadget/legacy/Makefile | 1 + drivers/usb/gadget/udc/Kconfig | 385 ++++++++++++++++++ drivers/usb/gadget/udc/Makefile | 31 ++ drivers/usb/gadget/{ => udc}/amd5536udc.c | 0 drivers/usb/gadget/{ => udc}/amd5536udc.h | 0 drivers/usb/gadget/{ => udc}/at91_udc.c | 0 drivers/usb/gadget/{ => udc}/at91_udc.h | 0 drivers/usb/gadget/{ => udc}/atmel_usba_udc.c | 0 drivers/usb/gadget/{ => udc}/atmel_usba_udc.h | 0 drivers/usb/gadget/{ => udc}/bcm63xx_udc.c | 0 drivers/usb/gadget/{ => udc}/dummy_hcd.c | 0 drivers/usb/gadget/{ => udc}/fotg210-udc.c | 0 drivers/usb/gadget/{ => udc}/fotg210.h | 0 drivers/usb/gadget/{ => udc}/fsl_mxc_udc.c | 0 drivers/usb/gadget/{ => udc}/fsl_qe_udc.c | 0 drivers/usb/gadget/{ => udc}/fsl_qe_udc.h | 0 drivers/usb/gadget/{ => udc}/fsl_udc_core.c | 0 drivers/usb/gadget/{ => udc}/fsl_usb2_udc.h | 0 drivers/usb/gadget/{ => udc}/fusb300_udc.c | 0 drivers/usb/gadget/{ => udc}/fusb300_udc.h | 0 drivers/usb/gadget/{ => udc}/gadget_chips.h | 0 drivers/usb/gadget/{ => udc}/goku_udc.c | 0 drivers/usb/gadget/{ => udc}/goku_udc.h | 0 drivers/usb/gadget/{ => udc}/gr_udc.c | 0 drivers/usb/gadget/{ => udc}/gr_udc.h | 0 drivers/usb/gadget/{ => udc}/lpc32xx_udc.c | 0 drivers/usb/gadget/{ => udc}/m66592-udc.c | 0 drivers/usb/gadget/{ => udc}/m66592-udc.h | 0 drivers/usb/gadget/{ => udc}/mv_u3d.h | 0 drivers/usb/gadget/{ => udc}/mv_u3d_core.c | 0 drivers/usb/gadget/{ => udc}/mv_udc.h | 0 drivers/usb/gadget/{ => udc}/mv_udc_core.c | 0 drivers/usb/gadget/{ => udc}/net2272.c | 0 drivers/usb/gadget/{ => udc}/net2272.h | 0 drivers/usb/gadget/{ => udc}/net2280.c | 0 drivers/usb/gadget/{ => udc}/net2280.h | 0 drivers/usb/gadget/{ => udc}/omap_udc.c | 0 drivers/usb/gadget/{ => udc}/omap_udc.h | 0 drivers/usb/gadget/{ => udc}/pch_udc.c | 0 drivers/usb/gadget/{ => udc}/pxa25x_udc.c | 0 drivers/usb/gadget/{ => udc}/pxa25x_udc.h | 0 drivers/usb/gadget/{ => udc}/pxa27x_udc.c | 0 drivers/usb/gadget/{ => udc}/pxa27x_udc.h | 0 drivers/usb/gadget/{ => udc}/r8a66597-udc.c | 0 drivers/usb/gadget/{ => udc}/r8a66597-udc.h | 0 drivers/usb/gadget/{ => udc}/s3c-hsudc.c | 0 drivers/usb/gadget/{ => udc}/s3c2410_udc.c | 0 drivers/usb/gadget/{ => udc}/s3c2410_udc.h | 0 drivers/usb/gadget/{ => udc}/udc-core.c | 0 51 files changed, 420 insertions(+), 399 deletions(-) create mode 100644 drivers/usb/gadget/udc/Kconfig create mode 100644 drivers/usb/gadget/udc/Makefile rename drivers/usb/gadget/{ => udc}/amd5536udc.c (100%) rename drivers/usb/gadget/{ => udc}/amd5536udc.h (100%) rename drivers/usb/gadget/{ => udc}/at91_udc.c (100%) rename drivers/usb/gadget/{ => udc}/at91_udc.h (100%) rename drivers/usb/gadget/{ => udc}/atmel_usba_udc.c (100%) rename drivers/usb/gadget/{ => udc}/atmel_usba_udc.h (100%) rename drivers/usb/gadget/{ => udc}/bcm63xx_udc.c (100%) rename drivers/usb/gadget/{ => udc}/dummy_hcd.c (100%) rename drivers/usb/gadget/{ => udc}/fotg210-udc.c (100%) rename drivers/usb/gadget/{ => udc}/fotg210.h (100%) rename drivers/usb/gadget/{ => udc}/fsl_mxc_udc.c (100%) rename drivers/usb/gadget/{ => udc}/fsl_qe_udc.c (100%) rename drivers/usb/gadget/{ => udc}/fsl_qe_udc.h (100%) rename drivers/usb/gadget/{ => udc}/fsl_udc_core.c (100%) rename drivers/usb/gadget/{ => udc}/fsl_usb2_udc.h (100%) rename drivers/usb/gadget/{ => udc}/fusb300_udc.c (100%) rename drivers/usb/gadget/{ => udc}/fusb300_udc.h (100%) rename drivers/usb/gadget/{ => udc}/gadget_chips.h (100%) rename drivers/usb/gadget/{ => udc}/goku_udc.c (100%) rename drivers/usb/gadget/{ => udc}/goku_udc.h (100%) rename drivers/usb/gadget/{ => udc}/gr_udc.c (100%) rename drivers/usb/gadget/{ => udc}/gr_udc.h (100%) rename drivers/usb/gadget/{ => udc}/lpc32xx_udc.c (100%) rename drivers/usb/gadget/{ => udc}/m66592-udc.c (100%) rename drivers/usb/gadget/{ => udc}/m66592-udc.h (100%) rename drivers/usb/gadget/{ => udc}/mv_u3d.h (100%) rename drivers/usb/gadget/{ => udc}/mv_u3d_core.c (100%) rename drivers/usb/gadget/{ => udc}/mv_udc.h (100%) rename drivers/usb/gadget/{ => udc}/mv_udc_core.c (100%) rename drivers/usb/gadget/{ => udc}/net2272.c (100%) rename drivers/usb/gadget/{ => udc}/net2272.h (100%) rename drivers/usb/gadget/{ => udc}/net2280.c (100%) rename drivers/usb/gadget/{ => udc}/net2280.h (100%) rename drivers/usb/gadget/{ => udc}/omap_udc.c (100%) rename drivers/usb/gadget/{ => udc}/omap_udc.h (100%) rename drivers/usb/gadget/{ => udc}/pch_udc.c (100%) rename drivers/usb/gadget/{ => udc}/pxa25x_udc.c (100%) rename drivers/usb/gadget/{ => udc}/pxa25x_udc.h (100%) rename drivers/usb/gadget/{ => udc}/pxa27x_udc.c (100%) rename drivers/usb/gadget/{ => udc}/pxa27x_udc.h (100%) rename drivers/usb/gadget/{ => udc}/r8a66597-udc.c (100%) rename drivers/usb/gadget/{ => udc}/r8a66597-udc.h (100%) rename drivers/usb/gadget/{ => udc}/s3c-hsudc.c (100%) rename drivers/usb/gadget/{ => udc}/s3c2410_udc.c (100%) rename drivers/usb/gadget/{ => udc}/s3c2410_udc.h (100%) rename drivers/usb/gadget/{ => udc}/udc-core.c (100%) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2986a4369df4..5c822afb6d70 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,376 +127,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. -# -# USB Peripheral Controller Support -# -# The order here is alphabetical, except that integrated controllers go -# before discrete ones so they will be the initial/default value: -# - integrated/SOC controllers first -# - licensed IP used in both SOC and discrete versions -# - discrete ones (including all PCI-only controllers) -# - debug/dummy gadget+hcd is last. -# -menu "USB Peripheral Controller" - -# -# Integrated controllers -# - -config USB_AT91 - tristate "Atmel AT91 USB Device Port" - depends on ARCH_AT91 - help - Many Atmel AT91 processors (such as the AT91RM2000) have a - full speed USB Device Port with support for five configurable - endpoints (plus endpoint zero). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "at91_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_LPC32XX - tristate "LPC32XX USB Peripheral Controller" - depends on ARCH_LPC32XX && I2C - select USB_ISP1301 - help - This option selects the USB device controller in the LPC32xx SoC. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "lpc32xx_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_ATMEL_USBA - tristate "Atmel USBA" - depends on AVR32 || ARCH_AT91 - help - USBA is the integrated high-speed USB Device controller on - the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. - -config USB_BCM63XX_UDC - tristate "Broadcom BCM63xx Peripheral Controller" - depends on BCM63XX - help - Many Broadcom BCM63xx chipsets (such as the BCM6328) have a - high speed USB Device Port with support for four fixed endpoints - (plus endpoint zero). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "bcm63xx_udc". - -config USB_FSL_USB2 - tristate "Freescale Highspeed USB DR Peripheral Controller" - depends on FSL_SOC || ARCH_MXC - select USB_FSL_MPH_DR_OF if OF - help - Some of Freescale PowerPC and i.MX processors have a High Speed - Dual-Role(DR) USB controller, which supports device mode. - - The number of programmable endpoints is different through - SOC revisions. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "fsl_usb2_udc" and force - all gadget drivers to also be dynamically linked. - -config USB_FUSB300 - tristate "Faraday FUSB300 USB Peripheral Controller" - depends on !PHYS_ADDR_T_64BIT && HAS_DMA - help - Faraday usb device controller FUSB300 driver - -config USB_FOTG210_UDC - depends on HAS_DMA - tristate "Faraday FOTG210 USB Peripheral Controller" - help - Faraday USB2.0 OTG controller which can be configured as - high speed or full speed USB device. This driver supppors - Bulk Transfer so far. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "fotg210_udc". - -config USB_GR_UDC - tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" - depends on HAS_DMA - help - Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB - VHDL IP core library. - -config USB_OMAP - tristate "OMAP USB Device Controller" - depends on ARCH_OMAP1 - depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) - help - Many Texas Instruments OMAP processors have flexible full - speed USB device controllers, with support for up to 30 - endpoints (plus endpoint zero). This driver supports the - controller in the OMAP 1611, and should work with controllers - in other OMAP processors too, given minor tweaks. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "omap_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_PXA25X - tristate "PXA 25x or IXP 4xx" - depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX - help - Intel's PXA 25x series XScale ARM-5TE processors include - an integrated full speed USB 1.1 device controller. The - controller in the IXP 4xx series is register-compatible. - - It has fifteen fixed-function endpoints, as well as endpoint - zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "pxa25x_udc" and force all - gadget drivers to also be dynamically linked. - -# if there's only one gadget driver, using only two bulk endpoints, -# don't waste memory for the other endpoints -config USB_PXA25X_SMALL - depends on USB_PXA25X - bool - default n if USB_ETH_RNDIS - default y if USB_ZERO - default y if USB_ETH - default y if USB_G_SERIAL - -config USB_R8A66597 - tristate "Renesas R8A66597 USB Peripheral Controller" - depends on HAS_DMA - help - R8A66597 is a discrete USB host and peripheral controller chip that - supports both full and high speed USB 2.0 data transfers. - It has nine configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "r8a66597_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_RENESAS_USBHS_UDC - tristate 'Renesas USBHS controller' - depends on USB_RENESAS_USBHS - help - Renesas USBHS is a discrete USB host and peripheral controller chip - that supports both full and high speed USB 2.0 data transfers. - It has nine or more configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "renesas_usbhs" and force all - gadget drivers to also be dynamically linked. - -config USB_PXA27X - tristate "PXA 27x" - help - Intel's PXA 27x series XScale ARM v5TE processors include - an integrated full speed USB 1.1 device controller. - - It has up to 23 endpoints, as well as endpoint zero (for - control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "pxa27x_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_S3C2410 - tristate "S3C2410 USB Device Controller" - depends on ARCH_S3C24XX - help - Samsung's S3C2410 is an ARM-4 processor with an integrated - full speed USB 1.1 device controller. It has 4 configurable - endpoints, as well as endpoint zero (for control transfers). - - This driver has been tested on the S3C2410, S3C2412, and - S3C2440 processors. - -config USB_S3C2410_DEBUG - boolean "S3C2410 udc debug messages" - depends on USB_S3C2410 - -config USB_S3C_HSUDC - tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller" - depends on ARCH_S3C24XX - help - Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC - integrated with dual speed USB 2.0 device controller. It has - 8 endpoints, as well as endpoint zero. - - This driver has been tested on S3C2416 and S3C2450 processors. - -config USB_MV_UDC - tristate "Marvell USB2.0 Device Controller" - depends on HAS_DMA - help - Marvell Socs (including PXA and MMP series) include a high speed - USB2.0 OTG controller, which can be configured as high speed or - full speed USB peripheral. - -config USB_MV_U3D - depends on HAS_DMA - tristate "MARVELL PXA2128 USB 3.0 controller" - help - MARVELL PXA2128 Processor series include a super speed USB3.0 device - controller, which support super speed USB peripheral. - -# -# Controllers available in both integrated and discrete versions -# - -config USB_M66592 - tristate "Renesas M66592 USB Peripheral Controller" - help - M66592 is a discrete USB peripheral controller chip that - supports both full and high speed USB 2.0 data transfers. - It has seven configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "m66592_udc" and force all - gadget drivers to also be dynamically linked. - -# -# Controllers available only in discrete form (and all PCI controllers) -# - -config USB_AMD5536UDC - tristate "AMD5536 UDC" - depends on PCI - help - The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. - It is a USB Highspeed DMA capable USB device controller. Beside ep0 - it provides 4 IN and 4 OUT endpoints (bulk or interrupt type). - The UDC port supports OTG operation, and may be used as a host port - if it's not being used to implement peripheral or OTG roles. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "amd5536udc" and force all - gadget drivers to also be dynamically linked. - -config USB_FSL_QE - tristate "Freescale QE/CPM USB Device Controller" - depends on FSL_SOC && (QUICC_ENGINE || CPM) - help - Some of Freescale PowerPC processors have a Full Speed - QE/CPM2 USB controller, which support device mode with 4 - programmable endpoints. This driver supports the - controller in the MPC8360 and MPC8272, and should work with - controllers having QE or CPM2, given minor tweaks. - - Set CONFIG_USB_GADGET to "m" to build this driver as a - dynamically linked module called "fsl_qe_udc". - -config USB_NET2272 - tristate "PLX NET2272" - help - PLX NET2272 is a USB peripheral controller which supports - both full and high speed USB 2.0 data transfers. - - It has three configurable endpoints, as well as endpoint zero - (for control transfer). - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "net2272" and force all - gadget drivers to also be dynamically linked. - -config USB_NET2272_DMA - boolean "Support external DMA controller" - depends on USB_NET2272 && HAS_DMA - help - The NET2272 part can optionally support an external DMA - controller, but your board has to have support in the - driver itself. - - If unsure, say "N" here. The driver works fine in PIO mode. - -config USB_NET2280 - tristate "NetChip 228x / PLX USB338x" - depends on PCI - help - NetChip 2280 / 2282 is a PCI based USB peripheral controller which - supports both full and high speed USB 2.0 data transfers. - - It has six configurable endpoints, as well as endpoint zero - (for control transfers) and several endpoints with dedicated - functions. - - PLX 3380 / 3382 is a PCIe based USB peripheral controller which - supports full, high speed USB 2.0 and super speed USB 3.0 - data transfers. - - It has eight configurable endpoints, as well as endpoint zero - (for control transfers) and several endpoints with dedicated - functions. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "net2280" and force all - gadget drivers to also be dynamically linked. - -config USB_GOKU - tristate "Toshiba TC86C001 'Goku-S'" - depends on PCI - help - The Toshiba TC86C001 is a PCI device which includes controllers - for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI). - - The device controller has three configurable (bulk or interrupt) - endpoints, plus endpoint zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "goku_udc" and to force all - gadget drivers to also be dynamically linked. - -config USB_EG20T - tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" - depends on PCI - help - This is a USB device driver for EG20T PCH. - EG20T PCH is the platform controller hub that is used in Intel's - general embedded platform. EG20T PCH has USB device interface. - Using this interface, it is able to access system devices connected - to USB device. - This driver enables USB device function. - USB device is a USB peripheral controller which - supports both full and high speed USB 2.0 data transfers. - This driver supports both control transfer and bulk transfer modes. - This driver dose not support interrupt transfer or isochronous - transfer modes. - - This driver also can be used for LAPIS Semiconductor's ML7213 which is - for IVI(In-Vehicle Infotainment) use. - ML7831 is for general purpose use. - ML7213/ML7831 is companion chip for Intel Atom E6xx series. - ML7213/ML7831 is completely compatible for Intel EG20T PCH. - -# -# LAST -- dummy/emulated controller -# - -config USB_DUMMY_HCD - tristate "Dummy HCD (DEVELOPMENT)" - depends on USB=y || (USB=m && USB_GADGET=m) - help - This host controller driver emulates USB, looping all data transfer - requests back to a USB "gadget driver" in the same host. The host - side is the master; the gadget side is the slave. Gadget drivers - can be high, full, or low speed; and they have access to endpoints - like those from NET2280, PXA2xx, or SA1100 hardware. - - This may help in some stages of creating a driver to embed in a - Linux device, since it lets you debug several parts of the gadget - driver without its hardware or drivers being involved. - - Since such a gadget side driver needs to interoperate with a host - side Linux-USB device driver, this may help to debug both sides - of a USB protocol stack. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "dummy_hcd" and force all - gadget drivers to also be dynamically linked. - -# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears -# first and will be selected by default. - -endmenu +source "drivers/usb/gadget/udc/Kconfig" # # USB Gadget Drivers diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 61d2503ef561..c144102ea793 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -3,38 +3,11 @@ # subdir-ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG subdir-ccflags-$(CONFIG_USB_GADGET_VERBOSE) += -DVERBOSE_DEBUG +ccflags-y += -I$(PWD)/drivers/usb/gadget/udc -obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o libcomposite-y := usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o -obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o -obj-$(CONFIG_USB_NET2272) += net2272.o -obj-$(CONFIG_USB_NET2280) += net2280.o -obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o -obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o -obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o -obj-$(CONFIG_USB_GOKU) += goku_udc.o -obj-$(CONFIG_USB_OMAP) += omap_udc.o -obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o -obj-$(CONFIG_USB_AT91) += at91_udc.o -obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o -obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o -obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o -fsl_usb2_udc-y := fsl_udc_core.o -fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o -obj-$(CONFIG_USB_M66592) += m66592-udc.o -obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o -obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o -obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o -obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o -obj-$(CONFIG_USB_EG20T) += pch_udc.o -obj-$(CONFIG_USB_MV_UDC) += mv_udc.o -mv_udc-y := mv_udc_core.o -obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o -obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o -obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o -obj-$(CONFIG_USB_GR_UDC) += gr_udc.o # USB Functions usb_f_acm-y := f_acm.o @@ -64,4 +37,4 @@ obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o -obj-$(CONFIG_USB_GADGET) += legacy/ +obj-$(CONFIG_USB_GADGET) += udc/ legacy/ diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile index fbb32aa6f690..d4570744e106 100644 --- a/drivers/usb/gadget/legacy/Makefile +++ b/drivers/usb/gadget/legacy/Makefile @@ -3,6 +3,7 @@ # ccflags-y := -I$(PWD)/drivers/usb/gadget/ +ccflags-y += -I$(PWD)/drivers/usb/gadget/udc/ g_zero-y := zero.o g_audio-y := audio.o diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig new file mode 100644 index 000000000000..5151f947a4f5 --- /dev/null +++ b/drivers/usb/gadget/udc/Kconfig @@ -0,0 +1,385 @@ +# +# USB Gadget support on a system involves +# (a) a peripheral controller, and +# (b) the gadget driver using it. +# +# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! +# +# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). +# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). +# - Some systems have both kinds of controllers. +# +# With help from a special transceiver and a "Mini-AB" jack, systems with +# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). +# + +# +# USB Peripheral Controller Support +# +# The order here is alphabetical, except that integrated controllers go +# before discrete ones so they will be the initial/default value: +# - integrated/SOC controllers first +# - licensed IP used in both SOC and discrete versions +# - discrete ones (including all PCI-only controllers) +# - debug/dummy gadget+hcd is last. +# +menu "USB Peripheral Controller" + +# +# Integrated controllers +# + +config USB_AT91 + tristate "Atmel AT91 USB Device Port" + depends on ARCH_AT91 + help + Many Atmel AT91 processors (such as the AT91RM2000) have a + full speed USB Device Port with support for five configurable + endpoints (plus endpoint zero). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "at91_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_LPC32XX + tristate "LPC32XX USB Peripheral Controller" + depends on ARCH_LPC32XX && I2C + select USB_ISP1301 + help + This option selects the USB device controller in the LPC32xx SoC. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "lpc32xx_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_ATMEL_USBA + tristate "Atmel USBA" + depends on AVR32 || ARCH_AT91 + help + USBA is the integrated high-speed USB Device controller on + the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. + +config USB_BCM63XX_UDC + tristate "Broadcom BCM63xx Peripheral Controller" + depends on BCM63XX + help + Many Broadcom BCM63xx chipsets (such as the BCM6328) have a + high speed USB Device Port with support for four fixed endpoints + (plus endpoint zero). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "bcm63xx_udc". + +config USB_FSL_USB2 + tristate "Freescale Highspeed USB DR Peripheral Controller" + depends on FSL_SOC || ARCH_MXC + select USB_FSL_MPH_DR_OF if OF + help + Some of Freescale PowerPC and i.MX processors have a High Speed + Dual-Role(DR) USB controller, which supports device mode. + + The number of programmable endpoints is different through + SOC revisions. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "fsl_usb2_udc" and force + all gadget drivers to also be dynamically linked. + +config USB_FUSB300 + tristate "Faraday FUSB300 USB Peripheral Controller" + depends on !PHYS_ADDR_T_64BIT && HAS_DMA + help + Faraday usb device controller FUSB300 driver + +config USB_FOTG210_UDC + depends on HAS_DMA + tristate "Faraday FOTG210 USB Peripheral Controller" + help + Faraday USB2.0 OTG controller which can be configured as + high speed or full speed USB device. This driver supppors + Bulk Transfer so far. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "fotg210_udc". + +config USB_GR_UDC + tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" + depends on HAS_DMA + help + Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB + VHDL IP core library. + +config USB_OMAP + tristate "OMAP USB Device Controller" + depends on ARCH_OMAP1 + depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) + help + Many Texas Instruments OMAP processors have flexible full + speed USB device controllers, with support for up to 30 + endpoints (plus endpoint zero). This driver supports the + controller in the OMAP 1611, and should work with controllers + in other OMAP processors too, given minor tweaks. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "omap_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_PXA25X + tristate "PXA 25x or IXP 4xx" + depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX + help + Intel's PXA 25x series XScale ARM-5TE processors include + an integrated full speed USB 1.1 device controller. The + controller in the IXP 4xx series is register-compatible. + + It has fifteen fixed-function endpoints, as well as endpoint + zero (for control transfers). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "pxa25x_udc" and force all + gadget drivers to also be dynamically linked. + +# if there's only one gadget driver, using only two bulk endpoints, +# don't waste memory for the other endpoints +config USB_PXA25X_SMALL + depends on USB_PXA25X + bool + default n if USB_ETH_RNDIS + default y if USB_ZERO + default y if USB_ETH + default y if USB_G_SERIAL + +config USB_R8A66597 + tristate "Renesas R8A66597 USB Peripheral Controller" + depends on HAS_DMA + help + R8A66597 is a discrete USB host and peripheral controller chip that + supports both full and high speed USB 2.0 data transfers. + It has nine configurable endpoints, and endpoint zero. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "r8a66597_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_RENESAS_USBHS_UDC + tristate 'Renesas USBHS controller' + depends on USB_RENESAS_USBHS + help + Renesas USBHS is a discrete USB host and peripheral controller chip + that supports both full and high speed USB 2.0 data transfers. + It has nine or more configurable endpoints, and endpoint zero. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "renesas_usbhs" and force all + gadget drivers to also be dynamically linked. + +config USB_PXA27X + tristate "PXA 27x" + help + Intel's PXA 27x series XScale ARM v5TE processors include + an integrated full speed USB 1.1 device controller. + + It has up to 23 endpoints, as well as endpoint zero (for + control transfers). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "pxa27x_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_S3C2410 + tristate "S3C2410 USB Device Controller" + depends on ARCH_S3C24XX + help + Samsung's S3C2410 is an ARM-4 processor with an integrated + full speed USB 1.1 device controller. It has 4 configurable + endpoints, as well as endpoint zero (for control transfers). + + This driver has been tested on the S3C2410, S3C2412, and + S3C2440 processors. + +config USB_S3C2410_DEBUG + boolean "S3C2410 udc debug messages" + depends on USB_S3C2410 + +config USB_S3C_HSUDC + tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller" + depends on ARCH_S3C24XX + help + Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC + integrated with dual speed USB 2.0 device controller. It has + 8 endpoints, as well as endpoint zero. + + This driver has been tested on S3C2416 and S3C2450 processors. + +config USB_MV_UDC + tristate "Marvell USB2.0 Device Controller" + depends on HAS_DMA + help + Marvell Socs (including PXA and MMP series) include a high speed + USB2.0 OTG controller, which can be configured as high speed or + full speed USB peripheral. + +config USB_MV_U3D + depends on HAS_DMA + tristate "MARVELL PXA2128 USB 3.0 controller" + help + MARVELL PXA2128 Processor series include a super speed USB3.0 device + controller, which support super speed USB peripheral. + +# +# Controllers available in both integrated and discrete versions +# + +config USB_M66592 + tristate "Renesas M66592 USB Peripheral Controller" + help + M66592 is a discrete USB peripheral controller chip that + supports both full and high speed USB 2.0 data transfers. + It has seven configurable endpoints, and endpoint zero. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "m66592_udc" and force all + gadget drivers to also be dynamically linked. + +# +# Controllers available only in discrete form (and all PCI controllers) +# + +config USB_AMD5536UDC + tristate "AMD5536 UDC" + depends on PCI + help + The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. + It is a USB Highspeed DMA capable USB device controller. Beside ep0 + it provides 4 IN and 4 OUT endpoints (bulk or interrupt type). + The UDC port supports OTG operation, and may be used as a host port + if it's not being used to implement peripheral or OTG roles. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "amd5536udc" and force all + gadget drivers to also be dynamically linked. + +config USB_FSL_QE + tristate "Freescale QE/CPM USB Device Controller" + depends on FSL_SOC && (QUICC_ENGINE || CPM) + help + Some of Freescale PowerPC processors have a Full Speed + QE/CPM2 USB controller, which support device mode with 4 + programmable endpoints. This driver supports the + controller in the MPC8360 and MPC8272, and should work with + controllers having QE or CPM2, given minor tweaks. + + Set CONFIG_USB_GADGET to "m" to build this driver as a + dynamically linked module called "fsl_qe_udc". + +config USB_NET2272 + tristate "PLX NET2272" + help + PLX NET2272 is a USB peripheral controller which supports + both full and high speed USB 2.0 data transfers. + + It has three configurable endpoints, as well as endpoint zero + (for control transfer). + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "net2272" and force all + gadget drivers to also be dynamically linked. + +config USB_NET2272_DMA + boolean "Support external DMA controller" + depends on USB_NET2272 && HAS_DMA + help + The NET2272 part can optionally support an external DMA + controller, but your board has to have support in the + driver itself. + + If unsure, say "N" here. The driver works fine in PIO mode. + +config USB_NET2280 + tristate "NetChip 228x / PLX USB338x" + depends on PCI + help + NetChip 2280 / 2282 is a PCI based USB peripheral controller which + supports both full and high speed USB 2.0 data transfers. + + It has six configurable endpoints, as well as endpoint zero + (for control transfers) and several endpoints with dedicated + functions. + + PLX 3380 / 3382 is a PCIe based USB peripheral controller which + supports full, high speed USB 2.0 and super speed USB 3.0 + data transfers. + + It has eight configurable endpoints, as well as endpoint zero + (for control transfers) and several endpoints with dedicated + functions. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "net2280" and force all + gadget drivers to also be dynamically linked. + +config USB_GOKU + tristate "Toshiba TC86C001 'Goku-S'" + depends on PCI + help + The Toshiba TC86C001 is a PCI device which includes controllers + for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI). + + The device controller has three configurable (bulk or interrupt) + endpoints, plus endpoint zero (for control transfers). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "goku_udc" and to force all + gadget drivers to also be dynamically linked. + +config USB_EG20T + tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" + depends on PCI + help + This is a USB device driver for EG20T PCH. + EG20T PCH is the platform controller hub that is used in Intel's + general embedded platform. EG20T PCH has USB device interface. + Using this interface, it is able to access system devices connected + to USB device. + This driver enables USB device function. + USB device is a USB peripheral controller which + supports both full and high speed USB 2.0 data transfers. + This driver supports both control transfer and bulk transfer modes. + This driver dose not support interrupt transfer or isochronous + transfer modes. + + This driver also can be used for LAPIS Semiconductor's ML7213 which is + for IVI(In-Vehicle Infotainment) use. + ML7831 is for general purpose use. + ML7213/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7831 is completely compatible for Intel EG20T PCH. + +# +# LAST -- dummy/emulated controller +# + +config USB_DUMMY_HCD + tristate "Dummy HCD (DEVELOPMENT)" + depends on USB=y || (USB=m && USB_GADGET=m) + help + This host controller driver emulates USB, looping all data transfer + requests back to a USB "gadget driver" in the same host. The host + side is the master; the gadget side is the slave. Gadget drivers + can be high, full, or low speed; and they have access to endpoints + like those from NET2280, PXA2xx, or SA1100 hardware. + + This may help in some stages of creating a driver to embed in a + Linux device, since it lets you debug several parts of the gadget + driver without its hardware or drivers being involved. + + Since such a gadget side driver needs to interoperate with a host + side Linux-USB device driver, this may help to debug both sides + of a USB protocol stack. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "dummy_hcd" and force all + gadget drivers to also be dynamically linked. + +# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears +# first and will be selected by default. + +endmenu diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile new file mode 100644 index 000000000000..4096122bb283 --- /dev/null +++ b/drivers/usb/gadget/udc/Makefile @@ -0,0 +1,31 @@ +# +# USB peripheral controller drivers +# +obj-$(CONFIG_USB_GADGET) += udc-core.o +obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o +obj-$(CONFIG_USB_NET2272) += net2272.o +obj-$(CONFIG_USB_NET2280) += net2280.o +obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o +obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o +obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o +obj-$(CONFIG_USB_GOKU) += goku_udc.o +obj-$(CONFIG_USB_OMAP) += omap_udc.o +obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o +obj-$(CONFIG_USB_AT91) += at91_udc.o +obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o +obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o +obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o +fsl_usb2_udc-y := fsl_udc_core.o +fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o +obj-$(CONFIG_USB_M66592) += m66592-udc.o +obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o +obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o +obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o +obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o +obj-$(CONFIG_USB_EG20T) += pch_udc.o +obj-$(CONFIG_USB_MV_UDC) += mv_udc.o +mv_udc-y := mv_udc_core.o +obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o +obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o +obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o +obj-$(CONFIG_USB_GR_UDC) += gr_udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c similarity index 100% rename from drivers/usb/gadget/amd5536udc.c rename to drivers/usb/gadget/udc/amd5536udc.c diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/udc/amd5536udc.h similarity index 100% rename from drivers/usb/gadget/amd5536udc.h rename to drivers/usb/gadget/udc/amd5536udc.h diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c similarity index 100% rename from drivers/usb/gadget/at91_udc.c rename to drivers/usb/gadget/udc/at91_udc.c diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h similarity index 100% rename from drivers/usb/gadget/at91_udc.h rename to drivers/usb/gadget/udc/at91_udc.h diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c similarity index 100% rename from drivers/usb/gadget/atmel_usba_udc.c rename to drivers/usb/gadget/udc/atmel_usba_udc.c diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h similarity index 100% rename from drivers/usb/gadget/atmel_usba_udc.h rename to drivers/usb/gadget/udc/atmel_usba_udc.h diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c similarity index 100% rename from drivers/usb/gadget/bcm63xx_udc.c rename to drivers/usb/gadget/udc/bcm63xx_udc.c diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c similarity index 100% rename from drivers/usb/gadget/dummy_hcd.c rename to drivers/usb/gadget/udc/dummy_hcd.c diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c similarity index 100% rename from drivers/usb/gadget/fotg210-udc.c rename to drivers/usb/gadget/udc/fotg210-udc.c diff --git a/drivers/usb/gadget/fotg210.h b/drivers/usb/gadget/udc/fotg210.h similarity index 100% rename from drivers/usb/gadget/fotg210.h rename to drivers/usb/gadget/udc/fotg210.h diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/udc/fsl_mxc_udc.c similarity index 100% rename from drivers/usb/gadget/fsl_mxc_udc.c rename to drivers/usb/gadget/udc/fsl_mxc_udc.c diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c similarity index 100% rename from drivers/usb/gadget/fsl_qe_udc.c rename to drivers/usb/gadget/udc/fsl_qe_udc.c diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/udc/fsl_qe_udc.h similarity index 100% rename from drivers/usb/gadget/fsl_qe_udc.h rename to drivers/usb/gadget/udc/fsl_qe_udc.h diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c similarity index 100% rename from drivers/usb/gadget/fsl_udc_core.c rename to drivers/usb/gadget/udc/fsl_udc_core.c diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h similarity index 100% rename from drivers/usb/gadget/fsl_usb2_udc.h rename to drivers/usb/gadget/udc/fsl_usb2_udc.h diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c similarity index 100% rename from drivers/usb/gadget/fusb300_udc.c rename to drivers/usb/gadget/udc/fusb300_udc.c diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/udc/fusb300_udc.h similarity index 100% rename from drivers/usb/gadget/fusb300_udc.h rename to drivers/usb/gadget/udc/fusb300_udc.h diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/udc/gadget_chips.h similarity index 100% rename from drivers/usb/gadget/gadget_chips.h rename to drivers/usb/gadget/udc/gadget_chips.h diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c similarity index 100% rename from drivers/usb/gadget/goku_udc.c rename to drivers/usb/gadget/udc/goku_udc.c diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/udc/goku_udc.h similarity index 100% rename from drivers/usb/gadget/goku_udc.h rename to drivers/usb/gadget/udc/goku_udc.h diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c similarity index 100% rename from drivers/usb/gadget/gr_udc.c rename to drivers/usb/gadget/udc/gr_udc.c diff --git a/drivers/usb/gadget/gr_udc.h b/drivers/usb/gadget/udc/gr_udc.h similarity index 100% rename from drivers/usb/gadget/gr_udc.h rename to drivers/usb/gadget/udc/gr_udc.h diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c similarity index 100% rename from drivers/usb/gadget/lpc32xx_udc.c rename to drivers/usb/gadget/udc/lpc32xx_udc.c diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c similarity index 100% rename from drivers/usb/gadget/m66592-udc.c rename to drivers/usb/gadget/udc/m66592-udc.c diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/udc/m66592-udc.h similarity index 100% rename from drivers/usb/gadget/m66592-udc.h rename to drivers/usb/gadget/udc/m66592-udc.h diff --git a/drivers/usb/gadget/mv_u3d.h b/drivers/usb/gadget/udc/mv_u3d.h similarity index 100% rename from drivers/usb/gadget/mv_u3d.h rename to drivers/usb/gadget/udc/mv_u3d.h diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c similarity index 100% rename from drivers/usb/gadget/mv_u3d_core.c rename to drivers/usb/gadget/udc/mv_u3d_core.c diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/udc/mv_udc.h similarity index 100% rename from drivers/usb/gadget/mv_udc.h rename to drivers/usb/gadget/udc/mv_udc.h diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c similarity index 100% rename from drivers/usb/gadget/mv_udc_core.c rename to drivers/usb/gadget/udc/mv_udc_core.c diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/udc/net2272.c similarity index 100% rename from drivers/usb/gadget/net2272.c rename to drivers/usb/gadget/udc/net2272.c diff --git a/drivers/usb/gadget/net2272.h b/drivers/usb/gadget/udc/net2272.h similarity index 100% rename from drivers/usb/gadget/net2272.h rename to drivers/usb/gadget/udc/net2272.h diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/udc/net2280.c similarity index 100% rename from drivers/usb/gadget/net2280.c rename to drivers/usb/gadget/udc/net2280.c diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/udc/net2280.h similarity index 100% rename from drivers/usb/gadget/net2280.h rename to drivers/usb/gadget/udc/net2280.h diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c similarity index 100% rename from drivers/usb/gadget/omap_udc.c rename to drivers/usb/gadget/udc/omap_udc.c diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/udc/omap_udc.h similarity index 100% rename from drivers/usb/gadget/omap_udc.h rename to drivers/usb/gadget/udc/omap_udc.h diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c similarity index 100% rename from drivers/usb/gadget/pch_udc.c rename to drivers/usb/gadget/udc/pch_udc.c diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c similarity index 100% rename from drivers/usb/gadget/pxa25x_udc.c rename to drivers/usb/gadget/udc/pxa25x_udc.c diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/udc/pxa25x_udc.h similarity index 100% rename from drivers/usb/gadget/pxa25x_udc.h rename to drivers/usb/gadget/udc/pxa25x_udc.h diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c similarity index 100% rename from drivers/usb/gadget/pxa27x_udc.c rename to drivers/usb/gadget/udc/pxa27x_udc.c diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h similarity index 100% rename from drivers/usb/gadget/pxa27x_udc.h rename to drivers/usb/gadget/udc/pxa27x_udc.h diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c similarity index 100% rename from drivers/usb/gadget/r8a66597-udc.c rename to drivers/usb/gadget/udc/r8a66597-udc.c diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/udc/r8a66597-udc.h similarity index 100% rename from drivers/usb/gadget/r8a66597-udc.h rename to drivers/usb/gadget/udc/r8a66597-udc.h diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c similarity index 100% rename from drivers/usb/gadget/s3c-hsudc.c rename to drivers/usb/gadget/udc/s3c-hsudc.c diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c similarity index 100% rename from drivers/usb/gadget/s3c2410_udc.c rename to drivers/usb/gadget/udc/s3c2410_udc.c diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h similarity index 100% rename from drivers/usb/gadget/s3c2410_udc.h rename to drivers/usb/gadget/udc/s3c2410_udc.h diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc/udc-core.c similarity index 100% rename from drivers/usb/gadget/udc-core.c rename to drivers/usb/gadget/udc/udc-core.c From 00a2430ff07d4e0e0e7e24e02fd8adede333b797 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 15 Jul 2014 13:09:46 +0200 Subject: [PATCH 144/211] usb: gadget: Gadget directory cleanup - group usb functions The drivers/usb/gadget directory contains many files. Files which are related can be distributed into separate directories. This patch moves the USB functions implementations into a separate directory. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Makefile | 30 +--------------- drivers/usb/gadget/function/Makefile | 34 +++++++++++++++++++ drivers/usb/gadget/{ => function}/f_acm.c | 0 drivers/usb/gadget/{ => function}/f_ecm.c | 0 drivers/usb/gadget/{ => function}/f_eem.c | 0 drivers/usb/gadget/{ => function}/f_fs.c | 0 drivers/usb/gadget/{ => function}/f_hid.c | 0 .../usb/gadget/{ => function}/f_loopback.c | 0 .../gadget/{ => function}/f_mass_storage.c | 0 .../gadget/{ => function}/f_mass_storage.h | 0 drivers/usb/gadget/{ => function}/f_midi.c | 0 drivers/usb/gadget/{ => function}/f_ncm.c | 0 drivers/usb/gadget/{ => function}/f_obex.c | 0 drivers/usb/gadget/{ => function}/f_phonet.c | 0 drivers/usb/gadget/{ => function}/f_rndis.c | 0 drivers/usb/gadget/{ => function}/f_serial.c | 0 .../usb/gadget/{ => function}/f_sourcesink.c | 0 drivers/usb/gadget/{ => function}/f_subset.c | 0 drivers/usb/gadget/{ => function}/f_uac1.c | 0 drivers/usb/gadget/{ => function}/f_uac2.c | 0 drivers/usb/gadget/{ => function}/f_uvc.c | 0 drivers/usb/gadget/{ => function}/f_uvc.h | 0 drivers/usb/gadget/{ => function}/g_zero.h | 0 drivers/usb/gadget/{ => function}/ndis.h | 0 drivers/usb/gadget/{ => function}/rndis.c | 0 drivers/usb/gadget/{ => function}/rndis.h | 0 .../gadget/{ => function}/storage_common.c | 0 .../gadget/{ => function}/storage_common.h | 0 drivers/usb/gadget/{ => function}/u_ecm.h | 0 drivers/usb/gadget/{ => function}/u_eem.h | 0 drivers/usb/gadget/{ => function}/u_ether.c | 0 drivers/usb/gadget/{ => function}/u_ether.h | 0 .../gadget/{ => function}/u_ether_configfs.h | 0 drivers/usb/gadget/{ => function}/u_fs.h | 0 drivers/usb/gadget/{ => function}/u_gether.h | 0 drivers/usb/gadget/{ => function}/u_ncm.h | 0 drivers/usb/gadget/{ => function}/u_phonet.h | 0 drivers/usb/gadget/{ => function}/u_rndis.h | 0 drivers/usb/gadget/{ => function}/u_serial.c | 0 drivers/usb/gadget/{ => function}/u_serial.h | 0 drivers/usb/gadget/{ => function}/u_uac1.c | 0 drivers/usb/gadget/{ => function}/u_uac1.h | 0 drivers/usb/gadget/{ => function}/uvc.h | 0 drivers/usb/gadget/{ => function}/uvc_queue.c | 0 drivers/usb/gadget/{ => function}/uvc_queue.h | 0 drivers/usb/gadget/{ => function}/uvc_v4l2.c | 0 drivers/usb/gadget/{ => function}/uvc_video.c | 0 drivers/usb/gadget/legacy/Makefile | 1 + 48 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 drivers/usb/gadget/function/Makefile rename drivers/usb/gadget/{ => function}/f_acm.c (100%) rename drivers/usb/gadget/{ => function}/f_ecm.c (100%) rename drivers/usb/gadget/{ => function}/f_eem.c (100%) rename drivers/usb/gadget/{ => function}/f_fs.c (100%) rename drivers/usb/gadget/{ => function}/f_hid.c (100%) rename drivers/usb/gadget/{ => function}/f_loopback.c (100%) rename drivers/usb/gadget/{ => function}/f_mass_storage.c (100%) rename drivers/usb/gadget/{ => function}/f_mass_storage.h (100%) rename drivers/usb/gadget/{ => function}/f_midi.c (100%) rename drivers/usb/gadget/{ => function}/f_ncm.c (100%) rename drivers/usb/gadget/{ => function}/f_obex.c (100%) rename drivers/usb/gadget/{ => function}/f_phonet.c (100%) rename drivers/usb/gadget/{ => function}/f_rndis.c (100%) rename drivers/usb/gadget/{ => function}/f_serial.c (100%) rename drivers/usb/gadget/{ => function}/f_sourcesink.c (100%) rename drivers/usb/gadget/{ => function}/f_subset.c (100%) rename drivers/usb/gadget/{ => function}/f_uac1.c (100%) rename drivers/usb/gadget/{ => function}/f_uac2.c (100%) rename drivers/usb/gadget/{ => function}/f_uvc.c (100%) rename drivers/usb/gadget/{ => function}/f_uvc.h (100%) rename drivers/usb/gadget/{ => function}/g_zero.h (100%) rename drivers/usb/gadget/{ => function}/ndis.h (100%) rename drivers/usb/gadget/{ => function}/rndis.c (100%) rename drivers/usb/gadget/{ => function}/rndis.h (100%) rename drivers/usb/gadget/{ => function}/storage_common.c (100%) rename drivers/usb/gadget/{ => function}/storage_common.h (100%) rename drivers/usb/gadget/{ => function}/u_ecm.h (100%) rename drivers/usb/gadget/{ => function}/u_eem.h (100%) rename drivers/usb/gadget/{ => function}/u_ether.c (100%) rename drivers/usb/gadget/{ => function}/u_ether.h (100%) rename drivers/usb/gadget/{ => function}/u_ether_configfs.h (100%) rename drivers/usb/gadget/{ => function}/u_fs.h (100%) rename drivers/usb/gadget/{ => function}/u_gether.h (100%) rename drivers/usb/gadget/{ => function}/u_ncm.h (100%) rename drivers/usb/gadget/{ => function}/u_phonet.h (100%) rename drivers/usb/gadget/{ => function}/u_rndis.h (100%) rename drivers/usb/gadget/{ => function}/u_serial.c (100%) rename drivers/usb/gadget/{ => function}/u_serial.h (100%) rename drivers/usb/gadget/{ => function}/u_uac1.c (100%) rename drivers/usb/gadget/{ => function}/u_uac1.h (100%) rename drivers/usb/gadget/{ => function}/uvc.h (100%) rename drivers/usb/gadget/{ => function}/uvc_queue.c (100%) rename drivers/usb/gadget/{ => function}/uvc_queue.h (100%) rename drivers/usb/gadget/{ => function}/uvc_v4l2.c (100%) rename drivers/usb/gadget/{ => function}/uvc_video.c (100%) diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index c144102ea793..a186afeaa700 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -9,32 +9,4 @@ obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o libcomposite-y := usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o -# USB Functions -usb_f_acm-y := f_acm.o -obj-$(CONFIG_USB_F_ACM) += usb_f_acm.o -usb_f_ss_lb-y := f_loopback.o f_sourcesink.o -obj-$(CONFIG_USB_F_SS_LB) += usb_f_ss_lb.o -obj-$(CONFIG_USB_U_SERIAL) += u_serial.o -usb_f_serial-y := f_serial.o -obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o -usb_f_obex-y := f_obex.o -obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o -obj-$(CONFIG_USB_U_ETHER) += u_ether.o -usb_f_ncm-y := f_ncm.o -obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o -usb_f_ecm-y := f_ecm.o -obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o -usb_f_phonet-y := f_phonet.o -obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o -usb_f_eem-y := f_eem.o -obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o -usb_f_ecm_subset-y := f_subset.o -obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o -usb_f_rndis-y := f_rndis.o rndis.o -obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o -usb_f_mass_storage-y := f_mass_storage.o storage_common.o -obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o -usb_f_fs-y := f_fs.o -obj-$(CONFIG_USB_F_FS) += usb_f_fs.o - -obj-$(CONFIG_USB_GADGET) += udc/ legacy/ +obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile new file mode 100644 index 000000000000..6d91f21b52a6 --- /dev/null +++ b/drivers/usb/gadget/function/Makefile @@ -0,0 +1,34 @@ +# +# USB peripheral controller drivers +# + +ccflags-y := -I$(PWD)/drivers/usb/gadget/ +ccflags-y += -I$(PWD)/drivers/usb/gadget/udc/ + +# USB Functions +usb_f_acm-y := f_acm.o +obj-$(CONFIG_USB_F_ACM) += usb_f_acm.o +usb_f_ss_lb-y := f_loopback.o f_sourcesink.o +obj-$(CONFIG_USB_F_SS_LB) += usb_f_ss_lb.o +obj-$(CONFIG_USB_U_SERIAL) += u_serial.o +usb_f_serial-y := f_serial.o +obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o +usb_f_obex-y := f_obex.o +obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o +obj-$(CONFIG_USB_U_ETHER) += u_ether.o +usb_f_ncm-y := f_ncm.o +obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o +usb_f_ecm-y := f_ecm.o +obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o +usb_f_phonet-y := f_phonet.o +obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o +usb_f_eem-y := f_eem.o +obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o +usb_f_ecm_subset-y := f_subset.o +obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o +usb_f_rndis-y := f_rndis.o rndis.o +obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o +usb_f_mass_storage-y := f_mass_storage.o storage_common.o +obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o +usb_f_fs-y := f_fs.o +obj-$(CONFIG_USB_F_FS) += usb_f_fs.o diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/function/f_acm.c similarity index 100% rename from drivers/usb/gadget/f_acm.c rename to drivers/usb/gadget/function/f_acm.c diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c similarity index 100% rename from drivers/usb/gadget/f_ecm.c rename to drivers/usb/gadget/function/f_ecm.c diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/function/f_eem.c similarity index 100% rename from drivers/usb/gadget/f_eem.c rename to drivers/usb/gadget/function/f_eem.c diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/function/f_fs.c similarity index 100% rename from drivers/usb/gadget/f_fs.c rename to drivers/usb/gadget/function/f_fs.c diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/function/f_hid.c similarity index 100% rename from drivers/usb/gadget/f_hid.c rename to drivers/usb/gadget/function/f_hid.c diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c similarity index 100% rename from drivers/usb/gadget/f_loopback.c rename to drivers/usb/gadget/function/f_loopback.c diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c similarity index 100% rename from drivers/usb/gadget/f_mass_storage.c rename to drivers/usb/gadget/function/f_mass_storage.c diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h similarity index 100% rename from drivers/usb/gadget/f_mass_storage.h rename to drivers/usb/gadget/function/f_mass_storage.h diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/function/f_midi.c similarity index 100% rename from drivers/usb/gadget/f_midi.c rename to drivers/usb/gadget/function/f_midi.c diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c similarity index 100% rename from drivers/usb/gadget/f_ncm.c rename to drivers/usb/gadget/function/f_ncm.c diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/function/f_obex.c similarity index 100% rename from drivers/usb/gadget/f_obex.c rename to drivers/usb/gadget/function/f_obex.c diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c similarity index 100% rename from drivers/usb/gadget/f_phonet.c rename to drivers/usb/gadget/function/f_phonet.c diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c similarity index 100% rename from drivers/usb/gadget/f_rndis.c rename to drivers/usb/gadget/function/f_rndis.c diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/function/f_serial.c similarity index 100% rename from drivers/usb/gadget/f_serial.c rename to drivers/usb/gadget/function/f_serial.c diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c similarity index 100% rename from drivers/usb/gadget/f_sourcesink.c rename to drivers/usb/gadget/function/f_sourcesink.c diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/function/f_subset.c similarity index 100% rename from drivers/usb/gadget/f_subset.c rename to drivers/usb/gadget/function/f_subset.c diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c similarity index 100% rename from drivers/usb/gadget/f_uac1.c rename to drivers/usb/gadget/function/f_uac1.c diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c similarity index 100% rename from drivers/usb/gadget/f_uac2.c rename to drivers/usb/gadget/function/f_uac2.c diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c similarity index 100% rename from drivers/usb/gadget/f_uvc.c rename to drivers/usb/gadget/function/f_uvc.c diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/function/f_uvc.h similarity index 100% rename from drivers/usb/gadget/f_uvc.h rename to drivers/usb/gadget/function/f_uvc.h diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/function/g_zero.h similarity index 100% rename from drivers/usb/gadget/g_zero.h rename to drivers/usb/gadget/function/g_zero.h diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/function/ndis.h similarity index 100% rename from drivers/usb/gadget/ndis.h rename to drivers/usb/gadget/function/ndis.h diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/function/rndis.c similarity index 100% rename from drivers/usb/gadget/rndis.c rename to drivers/usb/gadget/function/rndis.c diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/function/rndis.h similarity index 100% rename from drivers/usb/gadget/rndis.h rename to drivers/usb/gadget/function/rndis.h diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/function/storage_common.c similarity index 100% rename from drivers/usb/gadget/storage_common.c rename to drivers/usb/gadget/function/storage_common.c diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/function/storage_common.h similarity index 100% rename from drivers/usb/gadget/storage_common.h rename to drivers/usb/gadget/function/storage_common.h diff --git a/drivers/usb/gadget/u_ecm.h b/drivers/usb/gadget/function/u_ecm.h similarity index 100% rename from drivers/usb/gadget/u_ecm.h rename to drivers/usb/gadget/function/u_ecm.h diff --git a/drivers/usb/gadget/u_eem.h b/drivers/usb/gadget/function/u_eem.h similarity index 100% rename from drivers/usb/gadget/u_eem.h rename to drivers/usb/gadget/function/u_eem.h diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/function/u_ether.c similarity index 100% rename from drivers/usb/gadget/u_ether.c rename to drivers/usb/gadget/function/u_ether.c diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/function/u_ether.h similarity index 100% rename from drivers/usb/gadget/u_ether.h rename to drivers/usb/gadget/function/u_ether.h diff --git a/drivers/usb/gadget/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h similarity index 100% rename from drivers/usb/gadget/u_ether_configfs.h rename to drivers/usb/gadget/function/u_ether_configfs.h diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/function/u_fs.h similarity index 100% rename from drivers/usb/gadget/u_fs.h rename to drivers/usb/gadget/function/u_fs.h diff --git a/drivers/usb/gadget/u_gether.h b/drivers/usb/gadget/function/u_gether.h similarity index 100% rename from drivers/usb/gadget/u_gether.h rename to drivers/usb/gadget/function/u_gether.h diff --git a/drivers/usb/gadget/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h similarity index 100% rename from drivers/usb/gadget/u_ncm.h rename to drivers/usb/gadget/function/u_ncm.h diff --git a/drivers/usb/gadget/u_phonet.h b/drivers/usb/gadget/function/u_phonet.h similarity index 100% rename from drivers/usb/gadget/u_phonet.h rename to drivers/usb/gadget/function/u_phonet.h diff --git a/drivers/usb/gadget/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h similarity index 100% rename from drivers/usb/gadget/u_rndis.h rename to drivers/usb/gadget/function/u_rndis.h diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/function/u_serial.c similarity index 100% rename from drivers/usb/gadget/u_serial.c rename to drivers/usb/gadget/function/u_serial.c diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/function/u_serial.h similarity index 100% rename from drivers/usb/gadget/u_serial.h rename to drivers/usb/gadget/function/u_serial.h diff --git a/drivers/usb/gadget/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c similarity index 100% rename from drivers/usb/gadget/u_uac1.c rename to drivers/usb/gadget/function/u_uac1.c diff --git a/drivers/usb/gadget/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h similarity index 100% rename from drivers/usb/gadget/u_uac1.h rename to drivers/usb/gadget/function/u_uac1.h diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/function/uvc.h similarity index 100% rename from drivers/usb/gadget/uvc.h rename to drivers/usb/gadget/function/uvc.h diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c similarity index 100% rename from drivers/usb/gadget/uvc_queue.c rename to drivers/usb/gadget/function/uvc_queue.c diff --git a/drivers/usb/gadget/uvc_queue.h b/drivers/usb/gadget/function/uvc_queue.h similarity index 100% rename from drivers/usb/gadget/uvc_queue.h rename to drivers/usb/gadget/function/uvc_queue.h diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c similarity index 100% rename from drivers/usb/gadget/uvc_v4l2.c rename to drivers/usb/gadget/function/uvc_v4l2.c diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c similarity index 100% rename from drivers/usb/gadget/uvc_video.c rename to drivers/usb/gadget/function/uvc_video.c diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile index d4570744e106..a11aad5635df 100644 --- a/drivers/usb/gadget/legacy/Makefile +++ b/drivers/usb/gadget/legacy/Makefile @@ -4,6 +4,7 @@ ccflags-y := -I$(PWD)/drivers/usb/gadget/ ccflags-y += -I$(PWD)/drivers/usb/gadget/udc/ +ccflags-y += -I$(PWD)/drivers/usb/gadget/function/ g_zero-y := zero.o g_audio-y := audio.o From bbb9f94cf9e9e1cd120ef757944f0304a89aac95 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Jul 2014 12:19:12 -0500 Subject: [PATCH 145/211] usb: gadget: udc: fsl_udc_core: fix sparse errors No functional changes, just fixing some easy to spot sparse errors. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_udc_core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 57944ee8ad90..75b23ea077a7 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -59,9 +59,9 @@ static const char driver_name[] = "fsl-usb2-udc"; static const char driver_desc[] = DRIVER_DESC; -static struct usb_dr_device *dr_regs; +static struct usb_dr_device __iomem *dr_regs; -static struct usb_sys_interface *usb_sys_regs; +static struct usb_sys_interface __iomem *usb_sys_regs; /* it is initialized in probe() */ static struct fsl_udc *udc_controller = NULL; @@ -159,6 +159,8 @@ static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) {} * request is still in progress. *--------------------------------------------------------------*/ static void done(struct fsl_ep *ep, struct fsl_req *req, int status) +__releases(ep->udc->lock) +__acquires(ep->udc->lock) { struct fsl_udc *udc = NULL; unsigned char stopped = ep->stopped; @@ -1392,6 +1394,8 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, static void setup_received_irq(struct fsl_udc *udc, struct usb_ctrlrequest *setup) +__releases(udc->lock) +__acquires(udc->lock) { u16 wValue = le16_to_cpu(setup->wValue); u16 wIndex = le16_to_cpu(setup->wIndex); @@ -1957,7 +1961,7 @@ static int fsl_udc_start(struct usb_gadget *g, &udc_controller->gadget); if (retval < 0) { ERR("can't bind to transceiver\n"); - udc_controller->driver = 0; + udc_controller->driver = NULL; return retval; } } @@ -2379,7 +2383,7 @@ static int fsl_udc_probe(struct platform_device *pdev) goto err_release_mem_region; } - pdata->regs = (void *)dr_regs; + pdata->regs = (void __iomem *)dr_regs; /* * do platform specific init: check the clock, grab/config pins, etc. From c43e97b2c5e038bbec525fecb33fde4800631a55 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Jul 2014 12:20:25 -0500 Subject: [PATCH 146/211] usb: gadget: udc: net2280: fix sparse error No functional changes, just fixing one easy to spot sparse error. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 248dccb3e542..f4eac113690e 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -2159,7 +2159,7 @@ static void usb_reinit_338x(struct net2280 *dev) if (dev->enhanced_mode) { ep->cfg = &dev->epregs[ne[i]]; ep->regs = (struct net2280_ep_regs __iomem *) - (((void *)&dev->epregs[ne[i]]) + + (((void __iomem *)&dev->epregs[ne[i]]) + ep_reg_addr[i]); ep->fiforegs = &dev->fiforegs[i]; } else { From c9d872592611b98d3481e978f93b90a5fa194252 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Jul 2014 12:23:55 -0500 Subject: [PATCH 147/211] usb: gadget: udc: fsl_mxc_udc: fix sparse error No functional changes, just fixing one easy to spot sparse error. While fixing that sparse error, I had to add two includes to a header to avoid a build error. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_mxc_udc.c | 2 ++ drivers/usb/gadget/udc/fsl_usb2_udc.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/gadget/udc/fsl_mxc_udc.c b/drivers/usb/gadget/udc/fsl_mxc_udc.c index 9b140fc4d3bc..f16e149c5b3e 100644 --- a/drivers/usb/gadget/udc/fsl_mxc_udc.c +++ b/drivers/usb/gadget/udc/fsl_mxc_udc.c @@ -18,6 +18,8 @@ #include #include +#include "fsl_usb2_udc.h" + static struct clk *mxc_ahb_clk; static struct clk *mxc_per_clk; static struct clk *mxc_ipg_clk; diff --git a/drivers/usb/gadget/udc/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h index c6703bb07b23..84715625b2b3 100644 --- a/drivers/usb/gadget/udc/fsl_usb2_udc.h +++ b/drivers/usb/gadget/udc/fsl_usb2_udc.h @@ -12,6 +12,9 @@ #ifndef __FSL_USB2_UDC_H #define __FSL_USB2_UDC_H +#include +#include + /* ### define USB registers here */ #define USB_MAX_CTRL_PAYLOAD 64 From 55f7840ac4c6224263d88014b69f8cd35fa66817 Mon Sep 17 00:00:00 2001 From: Sebastian Reimers Date: Thu, 3 Jul 2014 20:15:28 +0200 Subject: [PATCH 148/211] usb: gadget: f_uac2: Fix pcm sample size selection The pcm playback and capture sample size format was fixed SNDRV_PCM_FMTBIT_S16_LE. This patch respects also 16, 24 and 32 bit p_ssize and c_ssize values. Reviewed-by: Takashi Iwai Signed-off-by: Sebastian Reimers Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 6261db4a9910..3ed89ecc8d6d 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -348,14 +348,34 @@ static int uac2_pcm_open(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { spin_lock_init(&uac2->p_prm.lock); runtime->hw.rate_min = p_srate; - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! p_ssize ! */ + switch (p_ssize) { + case 3: + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_3LE; + break; + case 4: + runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + break; + } runtime->hw.channels_min = num_channels(p_chmask); runtime->hw.period_bytes_min = 2 * uac2->p_prm.max_psize / runtime->hw.periods_min; } else { spin_lock_init(&uac2->c_prm.lock); runtime->hw.rate_min = c_srate; - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! c_ssize ! */ + switch (c_ssize) { + case 3: + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_3LE; + break; + case 4: + runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + break; + } runtime->hw.channels_min = num_channels(c_chmask); runtime->hw.period_bytes_min = 2 * uac2->c_prm.max_psize / runtime->hw.periods_min; From 4546527350c3c508554dff53e9086e9d3de0b97b Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 1 Jul 2014 15:47:47 +0200 Subject: [PATCH 149/211] usb: gadget: f_rndis: fix interface id for OS descriptors f->os_desc_table[0].if_id is zero by default. If the actual id happens to be different then no Feature Descriptors will be returned to the host for this interface, so assign if_id as soon as it is known. Cc: # v3.16 Acked-by: Michal Nazarewicz Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_rndis.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index eed3ad878047..a7b6bbbd697d 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -727,6 +727,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_control_intf.bInterfaceNumber = status; rndis_union_desc.bMasterInterface0 = status; + if (cdev->use_os_string) + f->os_desc_table[0].if_id = + rndis_iad_descriptor.bFirstInterface; + status = usb_interface_id(c, f); if (status < 0) goto fail; From 8346b33fad01cfe93f0fd0e64cd32ff40bd4ba41 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 17 Jul 2014 16:41:29 +0200 Subject: [PATCH 150/211] Documentation: DocBook: elieminate doc build break Gadget function files have been moved to a "function" subdirectory. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- Documentation/DocBook/gadget.tmpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl index 4017f147ba2f..1197165b8f28 100644 --- a/Documentation/DocBook/gadget.tmpl +++ b/Documentation/DocBook/gadget.tmpl @@ -556,11 +556,11 @@ been converted to this framework. Near-term plans include converting all of them, except for "gadgetfs". -!Edrivers/usb/gadget/f_acm.c -!Edrivers/usb/gadget/f_ecm.c -!Edrivers/usb/gadget/f_subset.c -!Edrivers/usb/gadget/f_obex.c -!Edrivers/usb/gadget/f_serial.c +!Edrivers/usb/gadget/function/f_acm.c +!Edrivers/usb/gadget/function/f_ecm.c +!Edrivers/usb/gadget/function/f_subset.c +!Edrivers/usb/gadget/function/f_obex.c +!Edrivers/usb/gadget/function/f_serial.c From 1299cff9fa39811cd1b3f1731527b062425f0541 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jul 2014 15:40:57 -0400 Subject: [PATCH 151/211] USB: shutdown all URBs after controller death When a host controller dies, we don't need to wait for a driver to time out. We can shut down its URBs immediately. Without this change, we can end up waiting 30 seconds for a mass-storage transfer to time out. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 4aeb10034de7..9bffd26cea05 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -417,10 +417,11 @@ static int usb_unbind_interface(struct device *dev) */ lpm_disable_error = usb_unlocked_disable_lpm(udev); - /* Terminate all URBs for this interface unless the driver - * supports "soft" unbinding. + /* + * Terminate all URBs for this interface unless the driver + * supports "soft" unbinding and the device is still present. */ - if (!driver->soft_unbind) + if (!driver->soft_unbind || udev->state == USB_STATE_NOTATTACHED) usb_disable_interface(udev, intf, false); driver->disconnect(intf); From 6f65126c76e38e671c64ec171acff8a99c4de749 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jul 2014 16:30:01 -0400 Subject: [PATCH 152/211] USB: OHCI: add SG support Apparently nobody ever remembered to add Scatter-Gather support to ohci-hcd. This patch adds it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 38 +++++++++++++++++++++----- drivers/usb/host/ohci-q.c | 54 ++++++++++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6f8ec52c7e0c..7f94c586c5dc 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -109,6 +109,33 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); /*-------------------------------------------------------------------------*/ +static int number_of_tds(struct urb *urb) +{ + int len, i, num, this_sg_len; + struct scatterlist *sg; + + len = urb->transfer_buffer_length; + i = urb->num_mapped_sgs; + + if (len > 0 && i > 0) { /* Scatter-gather transfer */ + num = 0; + sg = urb->sg; + for (;;) { + this_sg_len = min_t(int, sg_dma_len(sg), len); + num += DIV_ROUND_UP(this_sg_len, 4096); + len -= this_sg_len; + if (--i <= 0 || len <= 0) + break; + sg = sg_next(sg); + } + + } else { /* Non-SG transfer */ + /* one TD for every 4096 Bytes (could be up to 8K) */ + num = DIV_ROUND_UP(len, 4096); + } + return num; +} + /* * queue up an urb for anything except the root hub */ @@ -142,12 +169,8 @@ static int ohci_urb_enqueue ( // case PIPE_INTERRUPT: // case PIPE_BULK: default: - /* one TD for every 4096 Bytes (can be up to 8K) */ - size += urb->transfer_buffer_length / 4096; - /* ... and for any remaining bytes ... */ - if ((urb->transfer_buffer_length % 4096) != 0) - size++; - /* ... and maybe a zero length packet to wrap it up */ + size += number_of_tds(urb); + /* maybe a zero-length packet to wrap it up */ if (size == 0) size++; else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 @@ -506,6 +529,9 @@ static int ohci_init (struct ohci_hcd *ohci) int ret; struct usb_hcd *hcd = ohci_to_hcd(ohci); + /* Accept arbitrarily long scatter-gather lists */ + hcd->self.sg_tablesize = ~0; + if (distrust_firmware) ohci->flags |= OHCI_QUIRK_HUB_POWER; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index d4253e319428..517d04d5c150 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -602,6 +602,8 @@ static void td_submit_urb ( u32 info = 0; int is_out = usb_pipeout (urb->pipe); int periodic = 0; + int i, this_sg_len, n; + struct scatterlist *sg; /* OHCI handles the bulk/interrupt data toggles itself. We just * use the device toggle bits for resetting, and rely on the fact @@ -615,10 +617,24 @@ static void td_submit_urb ( list_add (&urb_priv->pending, &ohci->pending); - if (data_len) - data = urb->transfer_dma; - else - data = 0; + i = urb->num_mapped_sgs; + if (data_len > 0 && i > 0) { + sg = urb->sg; + data = sg_dma_address(sg); + + /* + * urb->transfer_buffer_length may be smaller than the + * size of the scatterlist (or vice versa) + */ + this_sg_len = min_t(int, sg_dma_len(sg), data_len); + } else { + sg = NULL; + if (data_len) + data = urb->transfer_dma; + else + data = 0; + this_sg_len = data_len; + } /* NOTE: TD_CC is set so we can tell which TDs the HC processed by * using TD_CC_GET, as well as by seeing them on the done list. @@ -639,17 +655,29 @@ static void td_submit_urb ( ? TD_T_TOGGLE | TD_CC | TD_DP_OUT : TD_T_TOGGLE | TD_CC | TD_DP_IN; /* TDs _could_ transfer up to 8K each */ - while (data_len > 4096) { - td_fill (ohci, info, data, 4096, urb, cnt); - data += 4096; - data_len -= 4096; + for (;;) { + n = min(this_sg_len, 4096); + + /* maybe avoid ED halt on final TD short read */ + if (n >= data_len || (i == 1 && n >= this_sg_len)) { + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + info |= TD_R; + } + td_fill(ohci, info, data, n, urb, cnt); + this_sg_len -= n; + data_len -= n; + data += n; cnt++; + + if (this_sg_len <= 0) { + if (--i <= 0 || data_len <= 0) + break; + sg = sg_next(sg); + data = sg_dma_address(sg); + this_sg_len = min_t(int, sg_dma_len(sg), + data_len); + } } - /* maybe avoid ED halt on final TD short read */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - info |= TD_R; - td_fill (ohci, info, data, data_len, urb, cnt); - cnt++; if ((urb->transfer_flags & URB_ZERO_PACKET) && cnt < urb_priv->length) { td_fill (ohci, info, 0, 0, urb, cnt); From 256dbcd80f1ccf8abf421c1d72ba79a4e29941dd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jul 2014 16:32:26 -0400 Subject: [PATCH 153/211] USB: OHCI: fix bugs in debug routines The debug routine fill_async_buffer() in ohci-hcd is buggy: It never produces any output because it forgets to initialize the output buffer size. Also, the debug routine ohci_dump() has an unused argument. This patch adds the correct initialization and removes the unused argument. Signed-off-by: Alan Stern CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-dbg.c | 9 +++++---- drivers/usb/host/ohci-hcd.c | 10 +++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 45032e933e18..04f2186939d2 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -236,7 +236,7 @@ ohci_dump_roothub ( } } -static void ohci_dump (struct ohci_hcd *controller, int verbose) +static void ohci_dump(struct ohci_hcd *controller) { ohci_dbg (controller, "OHCI controller state\n"); @@ -464,15 +464,16 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) static ssize_t fill_async_buffer(struct debug_buffer *buf) { struct ohci_hcd *ohci; - size_t temp; + size_t temp, size; unsigned long flags; ohci = buf->ohci; + size = PAGE_SIZE; /* display control and bulk lists together, for simplicity */ spin_lock_irqsave (&ohci->lock, flags); - temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail); - temp += show_list(ohci, buf->page + temp, buf->count - temp, + temp = show_list(ohci, buf->page, size, ohci->ed_controltail); + temp += show_list(ohci, buf->page + temp, size - temp, ohci->ed_bulktail); spin_unlock_irqrestore (&ohci->lock, flags); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 7f94c586c5dc..7570098b1cfa 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -76,8 +76,8 @@ static const char hcd_name [] = "ohci_hcd"; #include "ohci.h" #include "pci-quirks.h" -static void ohci_dump (struct ohci_hcd *ohci, int verbose); -static void ohci_stop (struct usb_hcd *hcd); +static void ohci_dump(struct ohci_hcd *ohci); +static void ohci_stop(struct usb_hcd *hcd); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -770,7 +770,7 @@ static int ohci_run (struct ohci_hcd *ohci) ohci->ed_to_check = NULL; } - ohci_dump (ohci, 1); + ohci_dump(ohci); return 0; } @@ -851,7 +851,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) usb_hc_died(hcd); } - ohci_dump (ohci, 1); + ohci_dump(ohci); ohci_usb_reset (ohci); } @@ -951,7 +951,7 @@ static void ohci_stop (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - ohci_dump (ohci, 1); + ohci_dump(ohci); if (quirk_nec(ohci)) flush_work(&ohci->nec_work); From 977dcfdc60311e7aa571cabf6f39c36dde13339e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jul 2014 16:34:29 -0400 Subject: [PATCH 154/211] USB: OHCI: don't lose track of EDs when a controller dies This patch fixes a bug in ohci-hcd. When an URB is unlinked, the corresponding Endpoint Descriptor is added to the ed_rm_list and taken off the hardware schedule. Once the ED is no longer visible to the hardware, finish_unlinks() handles the URBs that were unlinked or have completed. If any URBs remain attached to the ED, the ED is added back to the hardware schedule -- but only if the controller is running. This fails when a controller dies. A non-empty ED does not get added back to the hardware schedule and does not remain on the ed_rm_list; ohci-hcd loses track of it. The remaining URBs cannot be unlinked, which causes the USB stack to hang. The patch changes finish_unlinks() so that non-empty EDs remain on the ed_rm_list if the controller isn't running. This requires moving some of the existing code around, to avoid modifying the ED's hardware fields more than once. Signed-off-by: Alan Stern CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-q.c | 46 ++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 517d04d5c150..a6376f3e55cb 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -311,8 +311,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) * - ED_OPER: when there's any request queued, the ED gets rescheduled * immediately. HC should be working on them. * - * - ED_IDLE: when there's no TD queue. there's no reason for the HC - * to care about this ED; safe to disable the endpoint. + * - ED_IDLE: when there's no TD queue or the HC isn't running. * * When finish_unlinks() runs later, after SOF interrupt, it will often * complete one or more URB unlinks before making that state change. @@ -954,6 +953,10 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) int completed, modified; __hc32 *prev; + /* Is this ED already invisible to the hardware? */ + if (ed->state == ED_IDLE) + goto ed_idle; + /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs */ @@ -983,12 +986,20 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) } } + /* ED's now officially unlinked, hc doesn't see */ + ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; + ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); + ed->hwNextED = 0; + wmb(); + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE); +ed_idle: + /* reentrancy: if we drop the schedule lock, someone might * have modified this list. normally it's just prepending * entries (which we'd ignore), but paranoia won't hurt. */ - *last = ed->ed_next; - ed->ed_next = NULL; modified = 0; /* unlink urbs as requested, but rescan the list after @@ -1046,19 +1057,20 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) if (completed && !list_empty (&ed->td_list)) goto rescan_this; - /* ED's now officially unlinked, hc doesn't see */ - ed->state = ED_IDLE; - if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) - ohci->eds_scheduled--; - ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); - ed->hwNextED = 0; - wmb (); - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE); - - /* but if there's work queued, reschedule */ - if (!list_empty (&ed->td_list)) { - if (ohci->rh_state == OHCI_RH_RUNNING) - ed_schedule (ohci, ed); + /* + * If no TDs are queued, take ED off the ed_rm_list. + * Otherwise, if the HC is running, reschedule. + * If not, leave it on the list for further dequeues. + */ + if (list_empty(&ed->td_list)) { + *last = ed->ed_next; + ed->ed_next = NULL; + } else if (ohci->rh_state == OHCI_RH_RUNNING) { + *last = ed->ed_next; + ed->ed_next = NULL; + ed_schedule(ohci, ed); + } else { + last = &ed->ed_next; } if (modified) From caa67a5ec8926188adcbece0df2ae60ceff534ae Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 14 Jul 2014 19:27:48 +0530 Subject: [PATCH 155/211] USB: Add EXPORT_SYMBOL for usb_alloc_dev usb_alloc_dev is used by lvstest driver now which can be built as module. Therefore export usb_alloc_dev symbol. Signed-off-by: Pratyush Anand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4d1144990d4c..2dd2362198d2 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -501,6 +501,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, } return dev; } +EXPORT_SYMBOL_GPL(usb_alloc_dev); /** * usb_get_dev - increments the reference count of the usb device structure From ce21bfe603b3401c258c415456c915634998e133 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 14 Jul 2014 19:27:49 +0530 Subject: [PATCH 156/211] USB: Add LVS Test device driver OTG3 and EH Compliance Plan 1.0 talks about Super Speed OTG Verification system (SS-OVS) which consists of an excersizer and analyzer. USB Compliance Suite from Lecroy or Ellisys can act as such SS-OVS for Link Layer Validation (LVS). Some modifications are needed for an embedded Linux USB host to pass all these tests. Most of these tests require just Link to be in U0. They do not work with default Linux USB stack since, default stack does port reset and then starts sending setup packet, which is not expected by Link Layer Validation (LVS) device of Lecroy Compliance Suit. Then, There are many Link Layer Tests which need host to generate specific traffic. This patch supports specific traffic generation cases. As of now all the host Lecroy Link Layer-USBIF tests (except TD7.26) passes with this patch for single run using Lecroy USB Compliance Suite Version 1.98 Build 239 and Lecroy USB Protocol Analyzer version 4.80 Build 1603. Therefore patch seems to be a good candidate for inclusion. Further modification can be done on top of it. lvstest driver will not bind to any device by default. It can bind manually to a super speed USB host controller root hub. Therefore, regular hub driver must be unbound before this driver is bound. For example, if 2-0:1.0 is the xhci root hub, then execute following to unbind hub driver. echo 2-0:1.0 > /sys/bus/usb/drivers/hub/unbind Then write Linux Foundation's vendor ID which is used by root hubs and SS root hub's device ID into new_id file. Writing IDs into new_id file will also bind the lvs driver with any available SS root hub interfaces. echo "1D6B 3" > /sys/bus/usb/drivers/lvs/new_id Now connect LVS device with root hub port. Test case specific traffic can be generated as follows whenever needed: 1. To issue "Get Device descriptor" command for TD.7.06: echo > /sys/bus/usb/devices/2-0\:1.0/get_dev_desc 2. To set U1 timeout to 127 for TD.7.18 echo 127 > /sys/bus/usb/devices/2-0\:1.0/u1_timeout 3. To set U2 timeout to 0 for TD.7.18 echo 0 > /sys/bus/usb/devices/2-0\:1.0/u2_timeout 4. To issue "Hot Reset" for TD.7.29 echo > /sys/bus/usb/devices/2-0\:1.0/hot_reset 5. To issue "U3 Entry" for TD.7.35 echo > /sys/bus/usb/devices/2-0\:1.0/u3_entry 6. To issue "U3 Exit" for TD.7.36 echo > /sys/bus/usb/devices/2-0\:1.0/u3_exit Signed-off-by: Pratyush Anand Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-usb-lvstest | 47 ++ drivers/usb/misc/Kconfig | 7 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/lvstest.c | 460 ++++++++++++++++++ 4 files changed, 515 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-usb-lvstest create mode 100644 drivers/usb/misc/lvstest.c diff --git a/Documentation/ABI/testing/sysfs-bus-usb-lvstest b/Documentation/ABI/testing/sysfs-bus-usb-lvstest new file mode 100644 index 000000000000..aae68fc2d842 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-usb-lvstest @@ -0,0 +1,47 @@ +Link Layer Validation Device is a standard device for testing of Super +Speed Link Layer tests. These nodes are available in sysfs only when lvs +driver is bound with root hub device. + +What: /sys/bus/usb/devices/.../get_dev_desc +Date: March 2014 +Contact: Pratyush Anand +Description: + Write to this node to issue "Get Device Descriptor" + for Link Layer Validation device. It is needed for TD.7.06. + +What: /sys/bus/usb/devices/.../u1_timeout +Date: March 2014 +Contact: Pratyush Anand +Description: + Set "U1 timeout" for the downstream port where Link Layer + Validation device is connected. Timeout value must be between 0 + and 127. It is needed for TD.7.18, TD.7.19, TD.7.20 and TD.7.21. + +What: /sys/bus/usb/devices/.../u2_timeout +Date: March 2014 +Contact: Pratyush Anand +Description: + Set "U2 timeout" for the downstream port where Link Layer + Validation device is connected. Timeout value must be between 0 + and 127. It is needed for TD.7.18, TD.7.19, TD.7.20 and TD.7.21. + +What: /sys/bus/usb/devices/.../hot_reset +Date: March 2014 +Contact: Pratyush Anand +Description: + Write to this node to issue "Reset" for Link Layer Validation + device. It is needed for TD.7.29, TD.7.31, TD.7.34 and TD.7.35. + +What: /sys/bus/usb/devices/.../u3_entry +Date: March 2014 +Contact: Pratyush Anand +Description: + Write to this node to issue "U3 entry" for Link Layer + Validation device. It is needed for TD.7.35 and TD.7.36. + +What: /sys/bus/usb/devices/.../u3_exit +Date: March 2014 +Contact: Pratyush Anand +Description: + Write to this node to issue "U3 exit" for Link Layer + Validation device. It is needed for TD.7.36. diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 1bca274dc3b5..76d77206e011 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -248,3 +248,10 @@ config USB_HSIC_USB3503 select REGMAP_I2C help This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. + +config USB_LINK_LAYER_TEST + tristate "USB Link Layer Test driver" + help + This driver is for generating specific traffic for Super Speed Link + Layer Test Device. Say Y only when you want to conduct USB Super Speed + Link Layer Test for host controllers. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index e748fd5dbe94..65b0402c1ca1 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_USB_YUREX) += yurex.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ +obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c new file mode 100644 index 000000000000..02df9a72b990 --- /dev/null +++ b/drivers/usb/misc/lvstest.c @@ -0,0 +1,460 @@ +/* + * drivers/usb/misc/lvstest.c + * + * Test pattern generation for Link Layer Validation System Tests + * + * Copyright (C) 2014 ST Microelectronics + * Pratyush Anand + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct lvs_rh { + /* root hub interface */ + struct usb_interface *intf; + /* if lvs device connected */ + bool present; + /* port no at which lvs device is present */ + int portnum; + /* urb buffer */ + u8 buffer[8]; + /* class descriptor */ + struct usb_hub_descriptor descriptor; + /* urb for polling interrupt pipe */ + struct urb *urb; + /* LVS RH work queue */ + struct workqueue_struct *rh_queue; + /* LVH RH work */ + struct work_struct rh_work; + /* RH port status */ + struct usb_port_status port_status; +}; + +static struct usb_device *create_lvs_device(struct usb_interface *intf) +{ + struct usb_device *udev, *hdev; + struct usb_hcd *hcd; + struct lvs_rh *lvs = usb_get_intfdata(intf); + + if (!lvs->present) { + dev_err(&intf->dev, "No LVS device is present\n"); + return NULL; + } + + hdev = interface_to_usbdev(intf); + hcd = bus_to_hcd(hdev->bus); + + udev = usb_alloc_dev(hdev, hdev->bus, lvs->portnum); + if (!udev) { + dev_err(&intf->dev, "Could not allocate lvs udev\n"); + return NULL; + } + udev->speed = USB_SPEED_SUPER; + udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); + usb_set_device_state(udev, USB_STATE_DEFAULT); + + if (hcd->driver->enable_device) { + if (hcd->driver->enable_device(hcd, udev) < 0) { + dev_err(&intf->dev, "Failed to enable\n"); + usb_put_dev(udev); + return NULL; + } + } + + return udev; +} + +static void destroy_lvs_device(struct usb_device *udev) +{ + struct usb_device *hdev = udev->parent; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); + + if (hcd->driver->free_dev) + hcd->driver->free_dev(hcd, udev); + + usb_put_dev(udev); +} + +static int lvs_rh_clear_port_feature(struct usb_device *hdev, + int port1, int feature) +{ + return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, 1000); +} + +static int lvs_rh_set_port_feature(struct usb_device *hdev, + int port1, int feature) +{ + return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, 1000); +} + +static ssize_t u3_entry_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *hdev = interface_to_usbdev(intf); + struct lvs_rh *lvs = usb_get_intfdata(intf); + struct usb_device *udev; + int ret; + + udev = create_lvs_device(intf); + if (!udev) { + dev_err(dev, "failed to create lvs device\n"); + return -ENOMEM; + } + + ret = lvs_rh_set_port_feature(hdev, lvs->portnum, + USB_PORT_FEAT_SUSPEND); + if (ret < 0) + dev_err(dev, "can't issue U3 entry %d\n", ret); + + destroy_lvs_device(udev); + + if (ret < 0) + return ret; + + return count; +} +static DEVICE_ATTR_WO(u3_entry); + +static ssize_t u3_exit_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *hdev = interface_to_usbdev(intf); + struct lvs_rh *lvs = usb_get_intfdata(intf); + struct usb_device *udev; + int ret; + + udev = create_lvs_device(intf); + if (!udev) { + dev_err(dev, "failed to create lvs device\n"); + return -ENOMEM; + } + + ret = lvs_rh_clear_port_feature(hdev, lvs->portnum, + USB_PORT_FEAT_SUSPEND); + if (ret < 0) + dev_err(dev, "can't issue U3 exit %d\n", ret); + + destroy_lvs_device(udev); + + if (ret < 0) + return ret; + + return count; +} +static DEVICE_ATTR_WO(u3_exit); + +static ssize_t hot_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *hdev = interface_to_usbdev(intf); + struct lvs_rh *lvs = usb_get_intfdata(intf); + int ret; + + ret = lvs_rh_set_port_feature(hdev, lvs->portnum, + USB_PORT_FEAT_RESET); + if (ret < 0) { + dev_err(dev, "can't issue hot reset %d\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(hot_reset); + +static ssize_t u2_timeout_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *hdev = interface_to_usbdev(intf); + struct lvs_rh *lvs = usb_get_intfdata(intf); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret < 0) { + dev_err(dev, "couldn't parse string %d\n", ret); + return ret; + } + + if (val < 0 || val > 127) + return -EINVAL; + + ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8), + USB_PORT_FEAT_U2_TIMEOUT); + if (ret < 0) { + dev_err(dev, "Error %d while setting U2 timeout %ld\n", ret, val); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(u2_timeout); + +static ssize_t u1_timeout_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *hdev = interface_to_usbdev(intf); + struct lvs_rh *lvs = usb_get_intfdata(intf); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret < 0) { + dev_err(dev, "couldn't parse string %d\n", ret); + return ret; + } + + if (val < 0 || val > 127) + return -EINVAL; + + ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8), + USB_PORT_FEAT_U1_TIMEOUT); + if (ret < 0) { + dev_err(dev, "Error %d while setting U1 timeout %ld\n", ret, val); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(u1_timeout); + +static ssize_t get_dev_desc_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev; + struct usb_device_descriptor *descriptor; + int ret; + + descriptor = kmalloc(sizeof(*descriptor), GFP_KERNEL); + if (!descriptor) { + dev_err(dev, "failed to allocate descriptor memory\n"); + return -ENOMEM; + } + + udev = create_lvs_device(intf); + if (!udev) { + dev_err(dev, "failed to create lvs device\n"); + ret = -ENOMEM; + goto free_desc; + } + + ret = usb_control_msg(udev, (PIPE_CONTROL << 30) | USB_DIR_IN, + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8, + 0, descriptor, sizeof(*descriptor), + USB_CTRL_GET_TIMEOUT); + if (ret < 0) + dev_err(dev, "can't read device descriptor %d\n", ret); + + destroy_lvs_device(udev); + +free_desc: + kfree(descriptor); + + if (ret < 0) + return ret; + + return count; +} +static DEVICE_ATTR_WO(get_dev_desc); + +static struct attribute *lvs_attributes[] = { + &dev_attr_get_dev_desc.attr, + &dev_attr_u1_timeout.attr, + &dev_attr_u2_timeout.attr, + &dev_attr_hot_reset.attr, + &dev_attr_u3_entry.attr, + &dev_attr_u3_exit.attr, + NULL +}; + +static const struct attribute_group lvs_attr_group = { + .attrs = lvs_attributes, +}; + +static void lvs_rh_work(struct work_struct *work) +{ + struct lvs_rh *lvs = container_of(work, struct lvs_rh, rh_work); + struct usb_interface *intf = lvs->intf; + struct usb_device *hdev = interface_to_usbdev(intf); + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); + struct usb_hub_descriptor *descriptor = &lvs->descriptor; + struct usb_port_status *port_status = &lvs->port_status; + int i, ret = 0; + u16 portchange; + + /* Examine each root port */ + for (i = 1; i <= descriptor->bNbrPorts; i++) { + ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, i, + port_status, sizeof(*port_status), 1000); + if (ret < 4) + continue; + + portchange = port_status->wPortChange; + + if (portchange & USB_PORT_STAT_C_LINK_STATE) + lvs_rh_clear_port_feature(hdev, i, + USB_PORT_FEAT_C_PORT_LINK_STATE); + if (portchange & USB_PORT_STAT_C_ENABLE) + lvs_rh_clear_port_feature(hdev, i, + USB_PORT_FEAT_C_ENABLE); + if (portchange & USB_PORT_STAT_C_RESET) + lvs_rh_clear_port_feature(hdev, i, + USB_PORT_FEAT_C_RESET); + if (portchange & USB_PORT_STAT_C_BH_RESET) + lvs_rh_clear_port_feature(hdev, i, + USB_PORT_FEAT_C_BH_PORT_RESET); + if (portchange & USB_PORT_STAT_C_CONNECTION) { + lvs_rh_clear_port_feature(hdev, i, + USB_PORT_FEAT_C_CONNECTION); + + if (port_status->wPortStatus & + USB_PORT_STAT_CONNECTION) { + lvs->present = true; + lvs->portnum = i; + if (hcd->phy) + usb_phy_notify_connect(hcd->phy, + USB_SPEED_SUPER); + } else { + lvs->present = false; + if (hcd->phy) + usb_phy_notify_disconnect(hcd->phy, + USB_SPEED_SUPER); + } + break; + } + } + + ret = usb_submit_urb(lvs->urb, GFP_KERNEL); + if (ret != 0 && ret != -ENODEV && ret != -EPERM) + dev_err(&intf->dev, "urb resubmit error %d\n", ret); +} + +static void lvs_rh_irq(struct urb *urb) +{ + struct lvs_rh *lvs = urb->context; + + queue_work(lvs->rh_queue, &lvs->rh_work); +} + +static int lvs_rh_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *hdev; + struct usb_host_interface *desc; + struct usb_endpoint_descriptor *endpoint; + struct lvs_rh *lvs; + unsigned int pipe; + int ret, maxp; + + hdev = interface_to_usbdev(intf); + desc = intf->cur_altsetting; + endpoint = &desc->endpoint[0].desc; + + /* valid only for SS root hub */ + if (hdev->descriptor.bDeviceProtocol != USB_HUB_PR_SS || hdev->parent) { + dev_err(&intf->dev, "Bind LVS driver with SS root Hub only\n"); + return -EINVAL; + } + + lvs = devm_kzalloc(&intf->dev, sizeof(*lvs), GFP_KERNEL); + if (!lvs) + return -ENOMEM; + + lvs->intf = intf; + usb_set_intfdata(intf, lvs); + + /* how many number of ports this root hub has */ + ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, + USB_DT_SS_HUB << 8, 0, &lvs->descriptor, + USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT); + if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) { + dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret); + return ret; + } + + /* submit urb to poll interrupt endpoint */ + lvs->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!lvs->urb) { + dev_err(&intf->dev, "couldn't allocate lvs urb\n"); + return -ENOMEM; + } + + lvs->rh_queue = create_singlethread_workqueue("lvs_rh_queue"); + if (!lvs->rh_queue) { + dev_err(&intf->dev, "couldn't create workqueue\n"); + ret = -ENOMEM; + goto free_urb; + } + + INIT_WORK(&lvs->rh_work, lvs_rh_work); + + ret = sysfs_create_group(&intf->dev.kobj, &lvs_attr_group); + if (ret < 0) { + dev_err(&intf->dev, "Failed to create sysfs node %d\n", ret); + goto destroy_queue; + } + + pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe)); + usb_fill_int_urb(lvs->urb, hdev, pipe, &lvs->buffer[0], maxp, + lvs_rh_irq, lvs, endpoint->bInterval); + + ret = usb_submit_urb(lvs->urb, GFP_KERNEL); + if (ret < 0) { + dev_err(&intf->dev, "couldn't submit lvs urb %d\n", ret); + goto sysfs_remove; + } + + return ret; + +sysfs_remove: + sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); +destroy_queue: + destroy_workqueue(lvs->rh_queue); +free_urb: + usb_free_urb(lvs->urb); + return ret; +} + +static void lvs_rh_disconnect(struct usb_interface *intf) +{ + struct lvs_rh *lvs = usb_get_intfdata(intf); + + sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); + destroy_workqueue(lvs->rh_queue); + usb_free_urb(lvs->urb); +} + +static struct usb_driver lvs_driver = { + .name = "lvs", + .probe = lvs_rh_probe, + .disconnect = lvs_rh_disconnect, +}; + +module_usb_driver(lvs_driver); + +MODULE_DESCRIPTION("Link Layer Validation System Driver"); +MODULE_LICENSE("GPL"); From 934ef5aca9daea10507eebcbd0fb8f6d57d55359 Mon Sep 17 00:00:00 2001 From: Preston Fick Date: Wed, 16 Jul 2014 14:31:30 -0500 Subject: [PATCH 157/211] USB: serial: cp210x: Removing unncessary `usb_reset_device` on startup This `usb_reset_device` command has been around since the driver was originally reverse engineered. It doesn't cause much issue on single interface CP210x devices, but on the CP2105 and CP2108 with 2 and 4 interfaces respectively it will cause instability on enumeration and delays enumeration noticably. There should be no reason to reset a device at startup, per the CP210x AN571 spec. Signed-off-by: Preston Fick Cc: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 330df5ce435b..e4bb62225cb9 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -856,9 +856,6 @@ static int cp210x_startup(struct usb_serial *serial) struct usb_host_interface *cur_altsetting; struct cp210x_serial_private *spriv; - /* cp210x buffers behave strangely unless device is reset */ - usb_reset_device(serial->dev); - spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; From 5ee0f803cc3a0738a63288e4a2f453c85889fbda Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 14 Jul 2014 15:39:49 +0200 Subject: [PATCH 158/211] usbcore: don't log on consecutive debounce failures of the same port Some laptops have an internal port for a BT device which picks up noise when the kill switch is used, but not enough to trigger printk_rlimit(). So we shouldn't log consecutive faults of this kind. Signed-off-by: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 88f1db27e0af..2c2f67ec36ad 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4547,6 +4547,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, struct usb_hcd *hcd = bus_to_hcd(hdev->bus); struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_device *udev = port_dev->child; + static int unreliable_port = -1; /* Disconnect any existing devices under this port */ if (udev) { @@ -4567,10 +4568,14 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, USB_PORT_STAT_C_ENABLE)) { status = hub_port_debounce_be_stable(hub, port1); if (status < 0) { - if (status != -ENODEV && printk_ratelimit()) - dev_err(&port_dev->dev, - "connect-debounce failed\n"); + if (status != -ENODEV && + port1 != unreliable_port && + printk_ratelimit()) + dev_err(&udev->dev, "connect-debounce failed, port %d disabled\n", + port1); + portstatus &= ~USB_PORT_STAT_CONNECTION; + unreliable_port = port1; } else { portstatus = status; } From 1c094728b68c28e52abb64f0686aace61495a4fa Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Fri, 18 Jul 2014 13:34:40 -0400 Subject: [PATCH 159/211] usb-core: Remove Fix mes in file hcd.c I am removing two fix mes in this file as after dicussing then it seems there is no reason to check against Null for usb_device as it can never be NULL and this is check is therefore not needed. Signed-off-by: Nicholas Krause Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bec31e2efb88..487abcfcccd8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -855,8 +855,6 @@ static ssize_t authorized_default_show(struct device *dev, struct usb_bus *usb_bus = rh_usb_dev->bus; struct usb_hcd *usb_hcd; - if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ - return -ENODEV; usb_hcd = bus_to_hcd(usb_bus); return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); } @@ -871,8 +869,6 @@ static ssize_t authorized_default_store(struct device *dev, struct usb_bus *usb_bus = rh_usb_dev->bus; struct usb_hcd *usb_hcd; - if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ - return -ENODEV; usb_hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { From a40178b2fa6ad87670fb1e5fa4024db00c149629 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 18 Jul 2014 12:37:10 +0530 Subject: [PATCH 160/211] USB: Fix persist resume of some SS USB devices Problem Summary: Problem has been observed generally with PM states where VBUS goes off during suspend. There are some SS USB devices which take longer time for link training compared to many others. Such devices fail to reconnect with same old address which was associated with it before suspend. When system resumes, at some point of time (dpm_run_callback-> usb_dev_resume->usb_resume->usb_resume_both->usb_resume_device-> usb_port_resume) SW reads hub status. If device is present, then it finishes port resume and re-enumerates device with same address. If device is not present then, SW thinks that device was removed during suspend and therefore does logical disconnection and removes all the resource allocated for this device. Now, if I put sufficient delay just before root hub status read in usb_resume_device then, SW sees always that device is present. In normal course(without any delay) SW sees that no device is present and then SW removes all resource associated with the device at this port. In the latter case, after sometime, device says that hey I am here, now host enumerates it, but with new address. Problem had been reproduced when I connect verbatim USB3.0 hard disc with my STiH407 XHCI host running with 3.10 kernel. I see that similar problem has been reported here. https://bugzilla.kernel.org/show_bug.cgi?id=53211 Reading above it seems that bug was not in 3.6.6 and was present in 3.8 and again it was not present for some in 3.12.6, while it was present for few others. I tested with 3.13-FC19 running at i686 desktop, problem was still there. However, I was failed to reproduce it with 3.16-RC4 running at same i686 machine. I would say it is just a random observation. Problem for few devices is always there, as I am unable to find a proper fix for the issue. So, now question is what should be the amount of delay so that host is always able to recognize suspended device after resume. XHCI specs 4.19.4 says that when Link training is successful, port sets CSC bit to 1. So if SW reads port status before successful link training, then it will not find device to be present. USB Analyzer log with such buggy devices show that in some cases device switch on the RX termination after long delay of host enabling the VBUS. In few other cases it has been seen that device fails to negotiate link training in first attempt. It has been reported till now that few devices take as long as 2000 ms to train the link after host enabling its VBUS and RX termination. This patch implements a 2000 ms timeout for CSC bit to set ie for link training. If in a case link trains before timeout, loop will exit earlier. This patch implements above delay, but only for SS device and when persist is enabled. So, for the good device overhead is almost none. While for the bad devices penalty could be the time which it take for link training. But, If a device was connected before suspend, and was removed while system was asleep, then the penalty would be the timeout ie 2000 ms. Results: Verbatim USB SS hard disk connected with STiH407 USB host running 3.10 Kernel resumes in 461 msecs without this patch, but hard disk is assigned a new device address. Same system resumes in 790 msecs with this patch, but with old device address. Cc: Signed-off-by: Pratyush Anand Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2c2f67ec36ad..3654c67bd8bb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3258,6 +3258,43 @@ static int finish_port_resume(struct usb_device *udev) return status; } +/* + * There are some SS USB devices which take longer time for link training. + * XHCI specs 4.19.4 says that when Link training is successful, port + * sets CSC bit to 1. So if SW reads port status before successful link + * training, then it will not find device to be present. + * USB Analyzer log with such buggy devices show that in some cases + * device switch on the RX termination after long delay of host enabling + * the VBUS. In few other cases it has been seen that device fails to + * negotiate link training in first attempt. It has been + * reported till now that few devices take as long as 2000 ms to train + * the link after host enabling its VBUS and termination. Following + * routine implements a 2000 ms timeout for link training. If in a case + * link trains before timeout, loop will exit earlier. + * + * FIXME: If a device was connected before suspend, but was removed + * while system was asleep, then the loop in the following routine will + * only exit at timeout. + * + * This routine should only be called when persist is enabled for a SS + * device. + */ +static int wait_for_ss_port_enable(struct usb_device *udev, + struct usb_hub *hub, int *port1, + u16 *portchange, u16 *portstatus) +{ + int status = 0, delay_ms = 0; + + while (delay_ms < 2000) { + if (status || *portstatus & USB_PORT_STAT_CONNECTION) + break; + msleep(20); + delay_ms += 20; + status = hub_port_status(hub, *port1, portstatus, portchange); + } + return status; +} + /* * usb_port_resume - re-activate a suspended usb device's upstream port * @udev: device to re-activate, not a root hub @@ -3354,6 +3391,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } } + if (udev->persist_enabled && hub_is_superspeed(hub->hdev)) + status = wait_for_ss_port_enable(udev, hub, &port1, &portchange, + &portstatus); + status = check_port_resume_type(udev, hub, port1, status, portchange, portstatus); if (status == 0) From 95d9a01d727fdb6d2b667ac374341c48777cc41e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 18 Jul 2014 16:25:36 -0400 Subject: [PATCH 161/211] USB: OHCI: revert the ZF Micro orphan-TD quirk This patch reverts the important parts of commit 89a0fd18a96e (USB: OHCI handles more ZFMicro quirks), namely, the parts related to handling orphan TDs for interrupt endpoints. A later patch in this series will introduce a more general mechanism that applies to all endpoint types and all controllers. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 134 +----------------------------------- drivers/usb/host/ohci-q.c | 25 ++----- drivers/usb/host/ohci.h | 6 -- 3 files changed, 5 insertions(+), 160 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 7570098b1cfa..a8f0e1b00e7d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -355,8 +355,6 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) if (ohci->rh_state != OHCI_RH_RUNNING) { sanitize: ed->state = ED_IDLE; - if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) - ohci->eds_scheduled--; finish_unlinks (ohci, 0); } @@ -365,11 +363,6 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) /* major IRQ delivery trouble loses INTR_SF too... */ if (limit-- == 0) { ohci_warn(ohci, "ED unlink timeout\n"); - if (quirk_zfmicro(ohci)) { - ohci_warn(ohci, "Attempting ZF TD recovery\n"); - ohci->ed_to_check = ed; - ohci->zf_delay = 2; - } goto sanitize; } spin_unlock_irqrestore (&ohci->lock, flags); @@ -431,93 +424,6 @@ ohci_shutdown (struct usb_hcd *hcd) ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); } -static int check_ed(struct ohci_hcd *ohci, struct ed *ed) -{ - return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 - && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) - == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) - && !list_empty(&ed->td_list); -} - -/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes - * an interrupt TD but neglects to add it to the donelist. On systems with - * this chipset, we need to periodically check the state of the queues to look - * for such "lost" TDs. - */ -static void unlink_watchdog_func(unsigned long _ohci) -{ - unsigned long flags; - unsigned max; - unsigned seen_count = 0; - unsigned i; - struct ed **seen = NULL; - struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; - - spin_lock_irqsave(&ohci->lock, flags); - max = ohci->eds_scheduled; - if (!max) - goto done; - - if (ohci->ed_to_check) - goto out; - - seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); - if (!seen) - goto out; - - for (i = 0; i < NUM_INTS; i++) { - struct ed *ed = ohci->periodic[i]; - - while (ed) { - unsigned temp; - - /* scan this branch of the periodic schedule tree */ - for (temp = 0; temp < seen_count; temp++) { - if (seen[temp] == ed) { - /* we've checked it and what's after */ - ed = NULL; - break; - } - } - if (!ed) - break; - seen[seen_count++] = ed; - if (!check_ed(ohci, ed)) { - ed = ed->ed_next; - continue; - } - - /* HC's TD list is empty, but HCD sees at least one - * TD that's not been sent through the donelist. - */ - ohci->ed_to_check = ed; - ohci->zf_delay = 2; - - /* The HC may wait until the next frame to report the - * TD as done through the donelist and INTR_WDH. (We - * just *assume* it's not a multi-TD interrupt URB; - * those could defer the IRQ more than one frame, using - * DI...) Check again after the next INTR_SF. - */ - ohci_writel(ohci, OHCI_INTR_SF, - &ohci->regs->intrstatus); - ohci_writel(ohci, OHCI_INTR_SF, - &ohci->regs->intrenable); - - /* flush those writes */ - (void) ohci_readl(ohci, &ohci->regs->control); - - goto out; - } - } -out: - kfree(seen); - if (ohci->eds_scheduled) - mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ)); -done: - spin_unlock_irqrestore(&ohci->lock, flags); -} - /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -761,15 +667,6 @@ static int ohci_run (struct ohci_hcd *ohci) // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((val >> 23) & 0x1fe); - if (quirk_zfmicro(ohci)) { - /* Create timer to watch for bad queue state on ZF Micro */ - setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, - (unsigned long) ohci); - - ohci->eds_scheduled = 0; - ohci->ed_to_check = NULL; - } - ohci_dump(ohci); return 0; @@ -895,31 +792,6 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) spin_unlock (&ohci->lock); } - if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { - spin_lock(&ohci->lock); - if (ohci->ed_to_check) { - struct ed *ed = ohci->ed_to_check; - - if (check_ed(ohci, ed)) { - /* HC thinks the TD list is empty; HCD knows - * at least one TD is outstanding - */ - if (--ohci->zf_delay == 0) { - struct td *td = list_entry( - ed->td_list.next, - struct td, td_list); - ohci_warn(ohci, - "Reclaiming orphan TD %p\n", - td); - takeback_td(ohci, td); - ohci->ed_to_check = NULL; - } - } else - ohci->ed_to_check = NULL; - } - spin_unlock(&ohci->lock); - } - /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -928,9 +800,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) spin_lock (&ohci->lock); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(ohci)); - if ((ints & OHCI_INTR_SF) != 0 - && !ohci->ed_rm_list - && !ohci->ed_to_check + if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list && ohci->rh_state == OHCI_RH_RUNNING) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); @@ -961,8 +831,6 @@ static void ohci_stop (struct usb_hcd *hcd) free_irq(hcd->irq, hcd); hcd->irq = 0; - if (quirk_zfmicro(ohci)) - del_timer(&ohci->unlink_watchdog); if (quirk_amdiso(ohci)) usb_amd_dev_put(); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index a6376f3e55cb..a9f4f04c3fad 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -187,10 +187,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; - if (quirk_zfmicro(ohci) - && (ed->type == PIPE_INTERRUPT) - && !(ohci->eds_scheduled++)) - mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ)); wmb (); /* we care about rm_list when setting CLE/BLE in case the HC was at @@ -977,19 +973,13 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) TD_MASK; /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) { - if (ed == ohci->ed_to_check) - ohci->ed_to_check = NULL; - else - goto skip_ed; - } + if (td->td_dma != head) + goto skip_ed; } } /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; - if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) - ohci->eds_scheduled--; ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); ed->hwNextED = 0; wmb(); @@ -1122,12 +1112,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) /*-------------------------------------------------------------------------*/ -/* - * Used to take back a TD from the host controller. This would normally be - * called from within dl_done_list, however it may be called directly if the - * HC no longer sees the TD and it has not appeared on the donelist (after - * two frames). This bug has been observed on ZF Micro systems. - */ +/* Take back a TD from the host controller */ static void takeback_td(struct ohci_hcd *ohci, struct td *td) { struct urb *urb = td->urb; @@ -1174,9 +1159,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) * * This is the main path for handing urbs back to drivers. The only other * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, - * instead of scanning the (re-reversed) donelist as this does. There's - * an abnormal path too, handling a quirk in some Compaq silicon: URBs - * with TDs that appear to be orphaned are directly reclaimed. + * instead of scanning the (re-reversed) donelist as this does. */ static void dl_done_list (struct ohci_hcd *ohci) diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 05e02a709d4f..392932dd6318 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -411,12 +411,6 @@ struct ohci_hcd { struct work_struct nec_work; /* Worker for NEC quirk */ - /* Needed for ZF Micro quirk */ - struct timer_list unlink_watchdog; - unsigned eds_scheduled; - struct ed *ed_to_check; - unsigned zf_delay; - struct dentry *debug_dir; struct dentry *debug_async; struct dentry *debug_periodic; From 8b3ab0edaf6acd281243bf974fac7e01c9574d08 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 18 Jul 2014 16:25:49 -0400 Subject: [PATCH 162/211] USB: OHCI: no shortcut for unlinking URBS from a dead controller When an URB is unlinked from a dead controller, ohci-hcd gives back the URB with no regard for cleaning up the internal data structures. This won't play nicely with the upcoming changes to the TD done list. Therefore make ohci_urb_dequeue() call finish_unlinks(), which uses td_done() to do a proper cleanup, rather than calling finish_urb() directly. Also, remove the checks that urb_priv is non-NULL; the driver guarantees that urb_priv will never be NULL for a valid URB. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index a8f0e1b00e7d..52829276a44e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -300,30 +300,24 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; int rc; + urb_priv_t *urb_priv; spin_lock_irqsave (&ohci->lock, flags); rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) { - ; /* Do nothing */ - } else if (ohci->rh_state == OHCI_RH_RUNNING) { - urb_priv_t *urb_priv; + if (rc == 0) { /* Unless an IRQ completed the unlink while it was being * handed to us, flag it for unlink and giveback, and force * some upcoming INTR_SF to call finish_unlinks() */ urb_priv = urb->hcpriv; - if (urb_priv) { - if (urb_priv->ed->state == ED_OPER) - start_ed_unlink (ohci, urb_priv->ed); + if (urb_priv->ed->state == ED_OPER) + start_ed_unlink(ohci, urb_priv->ed); + + if (ohci->rh_state != OHCI_RH_RUNNING) { + /* With HC dead, we can clean up right away */ + finish_unlinks(ohci, 0); } - } else { - /* - * with HC dead, we won't respect hc queue pointers - * any more ... just clean up every urb's memory. - */ - if (urb->hcpriv) - finish_urb(ohci, urb, status); } spin_unlock_irqrestore (&ohci->lock, flags); return rc; From c6fcb85ea22889527ee44aba42c3e3b479fd2d92 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 18 Jul 2014 16:25:59 -0400 Subject: [PATCH 163/211] USB: OHCI: redesign the TD done list This patch changes the way ohci-hcd handles the TD done list. In addition to relying on the TD pointers stored by the controller hardware, we need to handle TDs that the hardware has forgotten about. This means the list has to exist even while the dl_done_list() routine isn't running. That function essentially gets split in two: update_done_list() reads the TD pointers stored by the hardware and adds the TDs to the done list, and process_done_list() scans through the list to handle URB completions. When we detect a TD that the hardware forgot about, we will be able to add it to the done list manually and then process it normally. Since the list is really a queue, and because there can be a lot of TDs, keep the existing singly linked implementation. To insure that URBs are given back in order of submission, whenever a TD is added to the done list, all the preceding TDs for the same endpoint must be added as well (going back to the first one that isn't already on the done list). The done list manipulations must all be protected by the private lock. The scope of the lock is expanded in preparation for the watchdog routine to be added in a later patch. We have to be more careful about giving back unlinked URBs. Since TDs may be added to the done list by the watchdog routine and not in response to a controller interrupt, we have to check explicitly to make sure all the URB's TDs that were added to the done list have been processed before giving back the URB. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 12 ++-- drivers/usb/host/ohci-hub.c | 6 +- drivers/usb/host/ohci-q.c | 109 ++++++++++++++++++++---------------- drivers/usb/host/ohci.h | 1 + 4 files changed, 70 insertions(+), 58 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 52829276a44e..3112799bba7f 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -780,24 +780,21 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) usb_hcd_resume_root_hub(hcd); } - if (ints & OHCI_INTR_WDH) { - spin_lock (&ohci->lock); - dl_done_list (ohci); - spin_unlock (&ohci->lock); - } + spin_lock(&ohci->lock); + if (ints & OHCI_INTR_WDH) + update_done_list(ohci); /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled * when there's still unlinking to be done (next frame). */ - spin_lock (&ohci->lock); + process_done_list(ohci); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(ohci)); if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list && ohci->rh_state == OHCI_RH_RUNNING) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); - spin_unlock (&ohci->lock); if (ohci->rh_state == OHCI_RH_RUNNING) { ohci_writel (ohci, ints, ®s->intrstatus); @@ -805,6 +802,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); } + spin_unlock(&ohci->lock); return IRQ_HANDLED; } diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index b4940de1eba3..dccb90edd66e 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -39,7 +39,8 @@ #define OHCI_SCHED_ENABLES \ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) -static void dl_done_list (struct ohci_hcd *); +static void update_done_list(struct ohci_hcd *); +static void process_done_list(struct ohci_hcd *); static void finish_unlinks (struct ohci_hcd *, u16); #ifdef CONFIG_PM @@ -87,7 +88,8 @@ __acquires(ohci->lock) msleep (8); spin_lock_irq (&ohci->lock); } - dl_done_list (ohci); + update_done_list(ohci); + process_done_list(ohci); finish_unlinks (ohci, ohci_frame_no(ohci)); /* diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index a9f4f04c3fad..f36b2fa0ee2f 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -892,13 +892,41 @@ static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) } } -/* replies to the request have to be on a FIFO basis so - * we unreverse the hc-reversed done-list - */ -static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) +/* Add a TD to the done list */ +static void add_to_done_list(struct ohci_hcd *ohci, struct td *td) +{ + struct td *td2, *td_prev; + struct ed *ed; + + if (td->next_dl_td) + return; /* Already on the list */ + + /* Add all the TDs going back until we reach one that's on the list */ + ed = td->ed; + td2 = td_prev = td; + list_for_each_entry_continue_reverse(td2, &ed->td_list, td_list) { + if (td2->next_dl_td) + break; + td2->next_dl_td = td_prev; + td_prev = td2; + } + + if (ohci->dl_end) + ohci->dl_end->next_dl_td = td_prev; + else + ohci->dl_start = td_prev; + + /* + * Make td->next_dl_td point to td itself, to mark the fact + * that td is on the done list. + */ + ohci->dl_end = td->next_dl_td = td; +} + +/* Get the entries on the hardware done queue and put them on our list */ +static void update_done_list(struct ohci_hcd *ohci) { u32 td_dma; - struct td *td_rev = NULL; struct td *td = NULL; td_dma = hc32_to_cpup (ohci, &ohci->hcca->done_head); @@ -906,7 +934,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) wmb(); /* get TD from hc's singly linked list, and - * prepend to ours. ed->td_list changes later. + * add to ours. ed->td_list changes later. */ while (td_dma) { int cc; @@ -928,11 +956,9 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) ed_halted(ohci, td, cc); - td->next_dl_td = td_rev; - td_rev = td; td_dma = hc32_to_cpup (ohci, &td->hwNextTD); + add_to_done_list(ohci, td); } - return td_rev; } /*-------------------------------------------------------------------------*/ @@ -956,26 +982,27 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs */ - if (likely(ohci->rh_state == OHCI_RH_RUNNING)) { - if (tick_before (tick, ed->tick)) { + if (likely(ohci->rh_state == OHCI_RH_RUNNING) && + tick_before(tick, ed->tick)) { skip_ed: - last = &ed->ed_next; - continue; - } + last = &ed->ed_next; + continue; + } + if (!list_empty(&ed->td_list)) { + struct td *td; + u32 head; - if (!list_empty (&ed->td_list)) { - struct td *td; - u32 head; + td = list_first_entry(&ed->td_list, struct td, td_list); - td = list_entry (ed->td_list.next, struct td, - td_list); - head = hc32_to_cpu (ohci, ed->hwHeadP) & - TD_MASK; + /* INTR_WDH may need to clean up first */ + head = hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK; + if (td->td_dma != head && + ohci->rh_state == OHCI_RH_RUNNING) + goto skip_ed; - /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) - goto skip_ed; - } + /* Don't mess up anything already on the done list */ + if (td->next_dl_td) + goto skip_ed; } /* ED's now officially unlinked, hc doesn't see */ @@ -1161,33 +1188,17 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, * instead of scanning the (re-reversed) donelist as this does. */ -static void -dl_done_list (struct ohci_hcd *ohci) +static void process_done_list(struct ohci_hcd *ohci) { - struct td *td = dl_reverse_done_list (ohci); + struct td *td; - while (td) { - struct td *td_next = td->next_dl_td; - struct ed *ed = td->ed; - - /* - * Some OHCI controllers (NVIDIA for sure, maybe others) - * occasionally forget to add TDs to the done queue. Since - * TDs for a given endpoint are always processed in order, - * if we find a TD on the donelist then all of its - * predecessors must be finished as well. - */ - for (;;) { - struct td *td2; - - td2 = list_first_entry(&ed->td_list, struct td, - td_list); - if (td2 == td) - break; - takeback_td(ohci, td2); - } + while (ohci->dl_start) { + td = ohci->dl_start; + if (td == ohci->dl_end) + ohci->dl_start = ohci->dl_end = NULL; + else + ohci->dl_start = td->next_dl_td; takeback_td(ohci, td); - td = td_next; } } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 392932dd6318..a8259bc6fd8b 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -380,6 +380,7 @@ struct ohci_hcd { struct dma_pool *td_cache; struct dma_pool *ed_cache; struct td *td_hash [TD_HASH_SIZE]; + struct td *dl_start, *dl_end; /* the done list */ struct list_head pending; /* From cdb4dd15e62eb984d9461b520d15d00ff2b88d9d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 18 Jul 2014 16:26:07 -0400 Subject: [PATCH 164/211] USB: OHCI: make URB completions single-threaded URBs for a particular endpoint should complete sequentially. That is, we shouldn't call the completion handler for one URB until the handler for the previous URB has returned. When the OHCI watchdog routine is added, there will be two paths for completing URBs: interrupt handler and watchdog routine. Their activities have to be synchronized so that completions don't occur in multiple threads concurrently. For that purpose, this patch creates an ohci_work() routine which will be responsible for calling process_done_list() and finish_unlinks(), the two routines that detect when an URB is complete. Everything will funnel through ohci_work(), and it will be careful not to run in more than one thread at a time. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 10 ++++------ drivers/usb/host/ohci-hub.c | 6 ++---- drivers/usb/host/ohci-q.c | 28 ++++++++++++++++++++++++++-- drivers/usb/host/ohci.h | 2 ++ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 3112799bba7f..ad588538e2e7 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -316,7 +316,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (ohci->rh_state != OHCI_RH_RUNNING) { /* With HC dead, we can clean up right away */ - finish_unlinks(ohci, 0); + ohci_work(ohci); } } spin_unlock_irqrestore (&ohci->lock, flags); @@ -349,7 +349,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) if (ohci->rh_state != OHCI_RH_RUNNING) { sanitize: ed->state = ED_IDLE; - finish_unlinks (ohci, 0); + ohci_work(ohci); } switch (ed->state) { @@ -789,9 +789,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) /* handle any pending URB/ED unlinks, leaving INTR_SF enabled * when there's still unlinking to be done (next frame). */ - process_done_list(ohci); - if (ohci->ed_rm_list) - finish_unlinks (ohci, ohci_frame_no(ohci)); + ohci_work(ohci); if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list && ohci->rh_state == OHCI_RH_RUNNING) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); @@ -879,7 +877,7 @@ int ohci_restart(struct ohci_hcd *ohci) if (!urb->unlinked) urb->unlinked = -ESHUTDOWN; } - finish_unlinks (ohci, 0); + ohci_work(ohci); spin_unlock_irq(&ohci->lock); /* paranoia, in case that didn't work: */ diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index dccb90edd66e..8991692bcfb8 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -40,8 +40,7 @@ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) static void update_done_list(struct ohci_hcd *); -static void process_done_list(struct ohci_hcd *); -static void finish_unlinks (struct ohci_hcd *, u16); +static void ohci_work(struct ohci_hcd *); #ifdef CONFIG_PM static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) @@ -89,8 +88,7 @@ __acquires(ohci->lock) spin_lock_irq (&ohci->lock); } update_done_list(ohci); - process_done_list(ohci); - finish_unlinks (ohci, ohci_frame_no(ohci)); + ohci_work(ohci); /* * Some controllers don't handle "global" suspend properly if diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index f36b2fa0ee2f..1974ddc68e45 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -964,9 +964,9 @@ static void update_done_list(struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ -static void -finish_unlinks (struct ohci_hcd *ohci, u16 tick) +static void finish_unlinks(struct ohci_hcd *ohci) { + unsigned tick = ohci_frame_no(ohci); struct ed *ed, **last; rescan_all: @@ -1202,3 +1202,27 @@ static void process_done_list(struct ohci_hcd *ohci) takeback_td(ohci, td); } } + +/* + * TD takeback and URB giveback must be single-threaded. + * This routine takes care of it all. + */ +static void ohci_work(struct ohci_hcd *ohci) +{ + if (ohci->working) { + ohci->restart_work = 1; + return; + } + ohci->working = 1; + + restart: + process_done_list(ohci); + if (ohci->ed_rm_list) + finish_unlinks(ohci); + + if (ohci->restart_work) { + ohci->restart_work = 0; + goto restart; + } + ohci->working = 0; +} diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index a8259bc6fd8b..ef348c2e1e4b 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -393,6 +393,8 @@ struct ohci_hcd { unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ unsigned autostop:1; /* rh auto stopping/stopped */ + unsigned working:1; + unsigned restart_work:1; unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ From 81e38333513cec155c720432226dabe9f9f76a77 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 18 Jul 2014 16:26:12 -0400 Subject: [PATCH 165/211] USB: OHCI: add I/O watchdog for orphan TDs Some OHCI controllers have a bug: They fail to add completed TDs to the done queue. Examining this queue is the only method ohci-hcd has for telling when a transfer is complete; failure to add a TD can result in an URB that never completes and cannot be unlinked. This patch adds a watchdog routine to ohci-hcd. The routine periodically scans the active ED and TD lists, looking for TDs which are finished but not on the done queue. When one is found, and it is certain that the controller hardware will never add the TD to the done queue, the watchdog routine manually puts the TD on the done list so that it can be handled normally. The watchdog routine also checks for a condition indicating the controller has died. If the done queue is non-empty but the HccaDoneHead pointer hasn't been updated for a few hundred milliseconds, we assume the controller will never update it and therefore is dead. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 125 ++++++++++++++++++++++++++++++++++++ drivers/usb/host/ohci-hub.c | 3 + drivers/usb/host/ohci-mem.c | 1 + drivers/usb/host/ohci-q.c | 6 ++ drivers/usb/host/ohci.h | 13 ++++ 5 files changed, 148 insertions(+) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ad588538e2e7..aba8f19eae4d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -72,12 +72,14 @@ static const char hcd_name [] = "ohci_hcd"; #define STATECHANGE_DELAY msecs_to_jiffies(300) +#define IO_WATCHDOG_DELAY msecs_to_jiffies(250) #include "ohci.h" #include "pci-quirks.h" static void ohci_dump(struct ohci_hcd *ohci); static void ohci_stop(struct usb_hcd *hcd); +static void io_watchdog_func(unsigned long _ohci); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -225,6 +227,14 @@ static int ohci_urb_enqueue ( usb_hcd_unlink_urb_from_ep(hcd, urb); goto fail; } + + /* Start up the I/O watchdog timer, if it's not running */ + if (!timer_pending(&ohci->io_watchdog) && + list_empty(&ohci->eds_in_use)) + mod_timer(&ohci->io_watchdog, + jiffies + IO_WATCHDOG_DELAY); + list_add(&ed->in_use_list, &ohci->eds_in_use); + if (ed->type == PIPE_ISOCHRONOUS) { u16 frame = ohci_frame_no(ohci); @@ -416,6 +426,7 @@ ohci_shutdown (struct usb_hcd *hcd) udelay(10); ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); + ohci->rh_state = OHCI_RH_HALTED; } /*-------------------------------------------------------------------------* @@ -484,6 +495,10 @@ static int ohci_init (struct ohci_hcd *ohci) if (ohci->hcca) return 0; + setup_timer(&ohci->io_watchdog, io_watchdog_func, + (unsigned long) ohci); + set_timer_slack(&ohci->io_watchdog, msecs_to_jiffies(20)); + ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); if (!ohci->hcca) @@ -694,6 +709,112 @@ static int ohci_start(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ +/* + * Some OHCI controllers are known to lose track of completed TDs. They + * don't add the TDs to the hardware done queue, which means we never see + * them as being completed. + * + * This watchdog routine checks for such problems. Without some way to + * tell when those TDs have completed, we would never take their EDs off + * the unlink list. As a result, URBs could never be dequeued and + * endpoints could never be released. + */ +static void io_watchdog_func(unsigned long _ohci) +{ + struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; + bool takeback_all_pending = false; + u32 status; + u32 head; + struct ed *ed; + struct td *td, *td_start, *td_next; + unsigned long flags; + + spin_lock_irqsave(&ohci->lock, flags); + + /* + * One way to lose track of completed TDs is if the controller + * never writes back the done queue head. If it hasn't been + * written back since the last time this function ran and if it + * was non-empty at that time, something is badly wrong with the + * hardware. + */ + status = ohci_readl(ohci, &ohci->regs->intrstatus); + if (!(status & OHCI_INTR_WDH) && ohci->wdh_cnt == ohci->prev_wdh_cnt) { + if (ohci->prev_donehead) { + ohci_err(ohci, "HcDoneHead not written back; disabled\n"); + usb_hc_died(ohci_to_hcd(ohci)); + ohci_dump(ohci); + ohci_shutdown(ohci_to_hcd(ohci)); + goto done; + } else { + /* No write back because the done queue was empty */ + takeback_all_pending = true; + } + } + + /* Check every ED which might have pending TDs */ + list_for_each_entry(ed, &ohci->eds_in_use, in_use_list) { + if (ed->pending_td) { + if (takeback_all_pending || + OKAY_TO_TAKEBACK(ohci, ed)) { + unsigned tmp = hc32_to_cpu(ohci, ed->hwINFO); + + ohci_dbg(ohci, "takeback pending TD for dev %d ep 0x%x\n", + 0x007f & tmp, + (0x000f & (tmp >> 7)) + + ((tmp & ED_IN) >> 5)); + add_to_done_list(ohci, ed->pending_td); + } + } + + /* Starting from the latest pending TD, */ + td = ed->pending_td; + + /* or the last TD on the done list, */ + if (!td) { + list_for_each_entry(td_next, &ed->td_list, td_list) { + if (!td_next->next_dl_td) + break; + td = td_next; + } + } + + /* find the last TD processed by the controller. */ + head = hc32_to_cpu(ohci, ACCESS_ONCE(ed->hwHeadP)) & TD_MASK; + td_start = td; + td_next = list_prepare_entry(td, &ed->td_list, td_list); + list_for_each_entry_continue(td_next, &ed->td_list, td_list) { + if (head == (u32) td_next->td_dma) + break; + td = td_next; /* head pointer has passed this TD */ + } + if (td != td_start) { + /* + * In case a WDH cycle is in progress, we will wait + * for the next two cycles to complete before assuming + * this TD will never get on the done queue. + */ + ed->takeback_wdh_cnt = ohci->wdh_cnt + 2; + ed->pending_td = td; + } + } + + ohci_work(ohci); + + if (ohci->rh_state == OHCI_RH_RUNNING) { + if (!list_empty(&ohci->eds_in_use)) { + ohci->prev_wdh_cnt = ohci->wdh_cnt; + ohci->prev_donehead = ohci_readl(ohci, + &ohci->regs->donehead); + mod_timer(&ohci->io_watchdog, + jiffies + IO_WATCHDOG_DELAY); + } + } + + done: + spin_unlock_irqrestore(&ohci->lock, flags); +} + /* an interrupt happens */ static irqreturn_t ohci_irq (struct usb_hcd *hcd) @@ -796,6 +917,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) if (ohci->rh_state == OHCI_RH_RUNNING) { ohci_writel (ohci, ints, ®s->intrstatus); + if (ints & OHCI_INTR_WDH) + ++ohci->wdh_cnt; + ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); @@ -815,6 +939,7 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_nec(ohci)) flush_work(&ohci->nec_work); + del_timer_sync(&ohci->io_watchdog); ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); ohci_usb_reset(ohci); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 8991692bcfb8..17d32b0ea565 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -309,6 +309,9 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) else rc = ohci_rh_suspend (ohci, 0); spin_unlock_irq (&ohci->lock); + + if (rc == 0) + del_timer_sync(&ohci->io_watchdog); return rc; } diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 2f20d3dc895b..c9e315c6808a 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,6 +28,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); + INIT_LIST_HEAD(&ohci->eds_in_use); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 1974ddc68e45..1463c398d322 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -921,6 +921,11 @@ static void add_to_done_list(struct ohci_hcd *ohci, struct td *td) * that td is on the done list. */ ohci->dl_end = td->next_dl_td = td; + + /* Did we just add the latest pending TD? */ + td2 = ed->pending_td; + if (td2 && td2->next_dl_td) + ed->pending_td = NULL; } /* Get the entries on the hardware done queue and put them on our list */ @@ -1082,6 +1087,7 @@ static void finish_unlinks(struct ohci_hcd *ohci) if (list_empty(&ed->td_list)) { *last = ed->ed_next; ed->ed_next = NULL; + list_del(&ed->in_use_list); } else if (ohci->rh_state == OHCI_RH_RUNNING) { *last = ed->ed_next; ed->ed_next = NULL; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index ef348c2e1e4b..0548f5ca18e2 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -47,6 +47,7 @@ struct ed { struct ed *ed_next; /* on schedule or rm_list */ struct ed *ed_prev; /* for non-interrupt EDs */ struct list_head td_list; /* "shadow list" of our TDs */ + struct list_head in_use_list; /* create --> IDLE --> OPER --> ... --> IDLE --> destroy * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... @@ -66,6 +67,13 @@ struct ed { /* HC may see EDs on rm_list until next frame (frame_no == tick) */ u16 tick; + + /* Detect TDs not added to the done queue */ + unsigned takeback_wdh_cnt; + struct td *pending_td; +#define OKAY_TO_TAKEBACK(ohci, ed) \ + ((int) (ohci->wdh_cnt - ed->takeback_wdh_cnt) >= 0) + } __attribute__ ((aligned(16))); #define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ @@ -382,6 +390,7 @@ struct ohci_hcd { struct td *td_hash [TD_HASH_SIZE]; struct td *dl_start, *dl_end; /* the done list */ struct list_head pending; + struct list_head eds_in_use; /* all EDs with at least 1 TD */ /* * driver state @@ -412,6 +421,10 @@ struct ohci_hcd { // there are also chip quirks/bugs in init logic + unsigned wdh_cnt, prev_wdh_cnt; + u32 prev_donehead; + struct timer_list io_watchdog; + struct work_struct nec_work; /* Worker for NEC quirk */ struct dentry *debug_dir; From 499b3803d3e2f062f73bf22372b38393369ffcbf Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 18 Jul 2014 16:26:17 -0400 Subject: [PATCH 166/211] USB: OHCI: add check for stopped frame counter This patch adds an extra check to ohci-hcd's I/O watchdog routine. If the controller stops updating the frame counter, we will assume it is dead. But there has to be an exception: Some controllers stop the frame counter when no ports are connected. Check to make sure there is at least one active port before deciding the controller is dead. (This test may appear racy, but it isn't. Enabling a newly connected port takes several milliseconds, during which time the frame counter must advance.) Signed-off-by: Alan Stern Tested-by: Dennis New Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 36 ++++++++++++++++++++++++++++++++++-- drivers/usb/host/ohci.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index aba8f19eae4d..46987735a2e3 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -72,7 +72,7 @@ static const char hcd_name [] = "ohci_hcd"; #define STATECHANGE_DELAY msecs_to_jiffies(300) -#define IO_WATCHDOG_DELAY msecs_to_jiffies(250) +#define IO_WATCHDOG_DELAY msecs_to_jiffies(250) #include "ohci.h" #include "pci-quirks.h" @@ -230,9 +230,11 @@ static int ohci_urb_enqueue ( /* Start up the I/O watchdog timer, if it's not running */ if (!timer_pending(&ohci->io_watchdog) && - list_empty(&ohci->eds_in_use)) + list_empty(&ohci->eds_in_use)) { + ohci->prev_frame_no = ohci_frame_no(ohci); mod_timer(&ohci->io_watchdog, jiffies + IO_WATCHDOG_DELAY); + } list_add(&ed->in_use_list, &ohci->eds_in_use); if (ed->type == PIPE_ISOCHRONOUS) { @@ -727,6 +729,7 @@ static void io_watchdog_func(unsigned long _ohci) u32 head; struct ed *ed; struct td *td, *td_start, *td_next; + unsigned frame_no; unsigned long flags; spin_lock_irqsave(&ohci->lock, flags); @@ -742,6 +745,7 @@ static void io_watchdog_func(unsigned long _ohci) if (!(status & OHCI_INTR_WDH) && ohci->wdh_cnt == ohci->prev_wdh_cnt) { if (ohci->prev_donehead) { ohci_err(ohci, "HcDoneHead not written back; disabled\n"); + died: usb_hc_died(ohci_to_hcd(ohci)); ohci_dump(ohci); ohci_shutdown(ohci_to_hcd(ohci)); @@ -802,7 +806,35 @@ static void io_watchdog_func(unsigned long _ohci) ohci_work(ohci); if (ohci->rh_state == OHCI_RH_RUNNING) { + + /* + * Sometimes a controller just stops working. We can tell + * by checking that the frame counter has advanced since + * the last time we ran. + * + * But be careful: Some controllers violate the spec by + * stopping their frame counter when no ports are active. + */ + frame_no = ohci_frame_no(ohci); + if (frame_no == ohci->prev_frame_no) { + int active_cnt = 0; + int i; + unsigned tmp; + + for (i = 0; i < ohci->num_ports; ++i) { + tmp = roothub_portstatus(ohci, i); + /* Enabled and not suspended? */ + if ((tmp & RH_PS_PES) && !(tmp & RH_PS_PSS)) + ++active_cnt; + } + + if (active_cnt > 0) { + ohci_err(ohci, "frame counter not updating; disabled\n"); + goto died; + } + } if (!list_empty(&ohci->eds_in_use)) { + ohci->prev_frame_no = frame_no; ohci->prev_wdh_cnt = ohci->wdh_cnt; ohci->prev_donehead = ohci_readl(ohci, &ohci->regs->donehead); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 0548f5ca18e2..59f424567a8d 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -421,6 +421,7 @@ struct ohci_hcd { // there are also chip quirks/bugs in init logic + unsigned prev_frame_no; unsigned wdh_cnt, prev_wdh_cnt; u32 prev_donehead; struct timer_list io_watchdog; From d821bfa4ca7d2699ef82557bceb05192fffcc51a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 9 Jul 2014 12:41:11 +0100 Subject: [PATCH 167/211] phy: miphy365x: Add MiPHY365x header file for DT x Driver defines This provides the shared header file which will be reference from both the MiPHY365x driver and its associated Device Tree node(s). Cc: Kishon Vijay Abraham I Acked-by: Mark Rutland Acked-by: Alexandre Torgue Signed-off-by: Lee Jones Signed-off-by: Kishon Vijay Abraham I --- include/dt-bindings/phy/phy-miphy365x.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 include/dt-bindings/phy/phy-miphy365x.h diff --git a/include/dt-bindings/phy/phy-miphy365x.h b/include/dt-bindings/phy/phy-miphy365x.h new file mode 100644 index 000000000000..8ef8aba6edd6 --- /dev/null +++ b/include/dt-bindings/phy/phy-miphy365x.h @@ -0,0 +1,14 @@ +/* + * This header provides constants for the phy framework + * based on the STMicroelectronics MiPHY365x. + * + * Author: Lee Jones + */ +#ifndef _DT_BINDINGS_PHY_MIPHY +#define _DT_BINDINGS_PHY_MIPHY + +#define MIPHY_TYPE_SATA 1 +#define MIPHY_TYPE_PCIE 2 +#define MIPHY_TYPE_USB 3 + +#endif /* _DT_BINDINGS_PHY_MIPHY */ From bbe21b2a9bb807957baf36e659bfe2aedc51e5ea Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 29 May 2014 12:00:47 +0530 Subject: [PATCH 168/211] phy: exynos-dp-video: Use PTR_ERR_OR_ZERO PTR_ERR_OR_ZERO simplifies the code. Signed-off-by: Sachin Kamat Cc: Jingoo Han Acked-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-exynos-dp-video.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 0786fef842e7..098f822a2fa4 100644 --- a/drivers/phy/phy-exynos-dp-video.c +++ b/drivers/phy/phy-exynos-dp-video.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -84,10 +85,8 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy, state); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id exynos_dp_video_phy_of_match[] = { From 22fda307ca53f18a179c38ac10a0bc4293dd9f21 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 29 May 2014 12:00:48 +0530 Subject: [PATCH 169/211] phy: exynos-mipi-video: Use PTR_ERR_OR_ZERO PTR_ERR_OR_ZERO simplifies the code. Signed-off-by: Sachin Kamat Cc: Sylwester Nawrocki Acked-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-exynos-mipi-video.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index ff026689358c..6d6bcf52a10e 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -149,10 +150,8 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) phy_provider = devm_of_phy_provider_register(dev, exynos_mipi_video_phy_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id exynos_mipi_video_phy_of_match[] = { From 2d84aff9c395d770bfe4d3fb6d1749882be7e4cc Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 29 May 2014 12:00:49 +0530 Subject: [PATCH 170/211] phy: sun4i-usb: Use PTR_ERR_OR_ZERO PTR_ERR_OR_ZERO simplifies the code. Signed-off-by: Sachin Kamat Cc: Maxime Ripard Acked-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 115d8d5190d5..7a4ea552f621 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -306,10 +307,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, data); phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id sun4i_usb_phy_of_match[] = { From ad6202b4d941c69e9154419bd3002fbcacccbb67 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 22 May 2014 13:00:28 +0900 Subject: [PATCH 171/211] phy: exynos5-usbdrd: Make local functions static Make local functions static, because these are used only in this file. Signed-off-by: Jingoo Han Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-exynos5-usbdrd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index 76d862b2202f..205159db37a3 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -506,7 +506,7 @@ static struct phy_ops exynos5_usbdrd_phy_ops = { .owner = THIS_MODULE, }; -const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { +static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { { .id = EXYNOS5_DRDPHY_UTMI, .phy_isol = exynos5_usbdrd_phy_isol, @@ -521,13 +521,13 @@ const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { }, }; -const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { +static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, }; -const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { +static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, }; From 57416c23e3ab57e65ba6e7c2e30fb40ba85035a6 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Tue, 1 Jul 2014 17:15:54 +0200 Subject: [PATCH 172/211] phy: phy-samsung-usb2: Change phy power on/power off sequence The Exynos4412 USB 2.0 PHY hardware differs from the description provided in the documentation. Some register bits have different function. This patch fixes the defines of register bits and changes the way how phys are powered on and off. Signed-off-by: Kamil Debski Tested-by: Daniel Drake Tested-by: Marek Szyprowski Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-exynos4x12-usb2.c | 112 ++++++++++++++++++++---------- drivers/phy/phy-exynos5250-usb2.c | 2 - drivers/phy/phy-samsung-usb2.h | 3 +- 3 files changed, 77 insertions(+), 40 deletions(-) diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c index d92a7cc5698a..63134d8bda08 100644 --- a/drivers/phy/phy-exynos4x12-usb2.c +++ b/drivers/phy/phy-exynos4x12-usb2.c @@ -86,13 +86,23 @@ #define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1) #define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2) #define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3) +/* The following bit defines are presented in the + * order taken from the Exynos4412 reference manual. + * + * During experiments with the hardware and debugging + * it was determined that the hardware behaves contrary + * to the manual. + * + * The following bit values were chaned accordingly to the + * results of real hardware experiments. + */ #define EXYNOS_4x12_URSTCON_PHY1 BIT(4) -#define EXYNOS_4x12_URSTCON_HSIC0 BIT(5) -#define EXYNOS_4x12_URSTCON_HSIC1 BIT(6) +#define EXYNOS_4x12_URSTCON_HSIC0 BIT(6) +#define EXYNOS_4x12_URSTCON_HSIC1 BIT(5) #define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7) -#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(8) +#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(10) #define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9) -#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(10) +#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(8) /* Isolation, configured in the power management unit */ #define EXYNOS_4x12_USB_ISOL_OFFSET 0x704 @@ -188,6 +198,7 @@ static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst) clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK); clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK; clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET; + clk |= EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON; writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK); } @@ -198,27 +209,22 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) u32 phypwr = 0; u32 rst; u32 pwr; - u32 mode = 0; - u32 switch_mode = 0; switch (inst->cfg->id) { case EXYNOS4x12_DEVICE: phypwr = EXYNOS_4x12_UPHYPWR_PHY0; rstbits = EXYNOS_4x12_URSTCON_PHY0; - mode = EXYNOS_4x12_MODE_SWITCH_DEVICE; - switch_mode = 1; break; case EXYNOS4x12_HOST: phypwr = EXYNOS_4x12_UPHYPWR_PHY1; - rstbits = EXYNOS_4x12_URSTCON_HOST_PHY; - mode = EXYNOS_4x12_MODE_SWITCH_HOST; - switch_mode = 1; + rstbits = EXYNOS_4x12_URSTCON_HOST_PHY | + EXYNOS_4x12_URSTCON_PHY1 | + EXYNOS_4x12_URSTCON_HOST_LINK_P0; break; case EXYNOS4x12_HSIC0: phypwr = EXYNOS_4x12_UPHYPWR_HSIC0; - rstbits = EXYNOS_4x12_URSTCON_HSIC1 | - EXYNOS_4x12_URSTCON_HOST_LINK_P0 | - EXYNOS_4x12_URSTCON_HOST_PHY; + rstbits = EXYNOS_4x12_URSTCON_HSIC0 | + EXYNOS_4x12_URSTCON_HOST_LINK_P1; break; case EXYNOS4x12_HSIC1: phypwr = EXYNOS_4x12_UPHYPWR_HSIC1; @@ -228,11 +234,6 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) }; if (on) { - if (switch_mode) - regmap_update_bits(drv->reg_sys, - EXYNOS_4x12_MODE_SWITCH_OFFSET, - EXYNOS_4x12_MODE_SWITCH_MASK, mode); - pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR); pwr &= ~phypwr; writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR); @@ -253,41 +254,78 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) } } +static void exynos4x12_power_on_int(struct samsung_usb2_phy_instance *inst) +{ + if (inst->int_cnt++ > 0) + return; + + exynos4x12_setup_clk(inst); + exynos4x12_isol(inst, 0); + exynos4x12_phy_pwr(inst, 1); +} + static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) { struct samsung_usb2_phy_driver *drv = inst->drv; - inst->enabled = 1; - exynos4x12_setup_clk(inst); - exynos4x12_phy_pwr(inst, 1); - exynos4x12_isol(inst, 0); + if (inst->ext_cnt++ > 0) + return 0; - /* Power on the device, as it is necessary for HSIC to work */ - if (inst->cfg->id == EXYNOS4x12_HSIC0) { - struct samsung_usb2_phy_instance *device = - &drv->instances[EXYNOS4x12_DEVICE]; - exynos4x12_phy_pwr(device, 1); - exynos4x12_isol(device, 0); + if (inst->cfg->id == EXYNOS4x12_HOST) { + regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, + EXYNOS_4x12_MODE_SWITCH_MASK, + EXYNOS_4x12_MODE_SWITCH_HOST); + exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]); } + if (inst->cfg->id == EXYNOS4x12_DEVICE) + regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, + EXYNOS_4x12_MODE_SWITCH_MASK, + EXYNOS_4x12_MODE_SWITCH_DEVICE); + + if (inst->cfg->id == EXYNOS4x12_HSIC0 || + inst->cfg->id == EXYNOS4x12_HSIC1) { + exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]); + exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_HOST]); + } + + exynos4x12_power_on_int(inst); + return 0; } +static void exynos4x12_power_off_int(struct samsung_usb2_phy_instance *inst) +{ + if (inst->int_cnt-- > 1) + return; + + exynos4x12_isol(inst, 1); + exynos4x12_phy_pwr(inst, 0); +} + static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst) { struct samsung_usb2_phy_driver *drv = inst->drv; - struct samsung_usb2_phy_instance *device = - &drv->instances[EXYNOS4x12_DEVICE]; - inst->enabled = 0; - exynos4x12_isol(inst, 1); - exynos4x12_phy_pwr(inst, 0); + if (inst->ext_cnt-- > 1) + return 0; - if (inst->cfg->id == EXYNOS4x12_HSIC0 && !device->enabled) { - exynos4x12_isol(device, 1); - exynos4x12_phy_pwr(device, 0); + if (inst->cfg->id == EXYNOS4x12_DEVICE) + regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, + EXYNOS_4x12_MODE_SWITCH_MASK, + EXYNOS_4x12_MODE_SWITCH_HOST); + + if (inst->cfg->id == EXYNOS4x12_HOST) + exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_DEVICE]); + + if (inst->cfg->id == EXYNOS4x12_HSIC0 || + inst->cfg->id == EXYNOS4x12_HSIC1) { + exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_DEVICE]); + exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_HOST]); } + exynos4x12_power_off_int(inst); + return 0; } diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c index 94179afda951..1c139aa0d074 100644 --- a/drivers/phy/phy-exynos5250-usb2.c +++ b/drivers/phy/phy-exynos5250-usb2.c @@ -318,7 +318,6 @@ static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst) break; } - inst->enabled = 1; exynos5250_isol(inst, 0); return 0; @@ -331,7 +330,6 @@ static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst) u32 otg; u32 hsic; - inst->enabled = 0; exynos5250_isol(inst, 1); switch (inst->cfg->id) { diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h index 45b3170652bd..918847843a95 100644 --- a/drivers/phy/phy-samsung-usb2.h +++ b/drivers/phy/phy-samsung-usb2.h @@ -29,7 +29,8 @@ struct samsung_usb2_phy_instance { const struct samsung_usb2_common_phy *cfg; struct phy *phy; struct samsung_usb2_phy_driver *drv; - bool enabled; + int int_cnt; + int ext_cnt; }; struct samsung_usb2_phy_driver { From 99bbd48c2065552fd2d224c9f065dcac9b7e25ce Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 25 Jun 2014 23:22:56 +0530 Subject: [PATCH 173/211] phy: phy-omap-pipe3: Add support for PCIe PHY PCIe PHY uses an external pll instead of the internal pll used by SATA and USB3. So added support in pipe3 PHY to use external pll. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros --- .../devicetree/bindings/phy/ti-phy.txt | 11 +- drivers/phy/phy-ti-pipe3.c | 107 ++++++++++++++---- 2 files changed, 93 insertions(+), 25 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index 9ce458f32945..b50e1c10a05d 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -56,8 +56,8 @@ usb2phy@4a0ad080 { TI PIPE3 PHY Required properties: - - compatible: Should be "ti,phy-usb3" or "ti,phy-pipe3-sata". - "ti,omap-usb3" is deprecated. + - compatible: Should be "ti,phy-usb3", "ti,phy-pipe3-sata" or + "ti,phy-pipe3-pcie. "ti,omap-usb3" is deprecated. - reg : Address and length of the register set for the device. - reg-names: The names of the register addresses corresponding to the registers filled in "reg". @@ -69,10 +69,17 @@ Required properties: * "wkupclk" - wakeup clock. * "sysclk" - system clock. * "refclk" - reference clock. + * "dpll_ref" - external dpll ref clk + * "dpll_ref_m2" - external dpll ref clk + * "phy-div" - divider for apll + * "div-clk" - apll clock Optional properties: - ctrl-module : phandle of the control module used by PHY driver to power on the PHY. + - id: If there are multiple instance of the same type, in order to + differentiate between each instance "id" can be used (e.g., multi-lane PCIe + PHY). If "id" is not provided, it is set to default value of '1'. This is usually a subnode of ocp2scp to which it is connected. diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 591367654613..6174f4b1a5de 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -80,7 +80,9 @@ struct ti_pipe3 { struct clk *wkupclk; struct clk *sys_clk; struct clk *refclk; + struct clk *div_clk; struct pipe3_dpll_map *dpll_map; + u8 id; }; static struct pipe3_dpll_map dpll_map_usb[] = { @@ -215,6 +217,9 @@ static int ti_pipe3_init(struct phy *x) u32 val; int ret = 0; + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) + return 0; + /* Bring it out of IDLE if it is IDLE */ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); if (val & PLL_IDLE) { @@ -238,8 +243,11 @@ static int ti_pipe3_exit(struct phy *x) u32 val; unsigned long timeout; - /* SATA DPLL can't be powered down due to Errata i783 */ - if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) + /* SATA DPLL can't be powered down due to Errata i783 and PCIe + * does not have internal DPLL + */ + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") || + of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) return 0; /* Put DPLL in IDLE mode */ @@ -286,32 +294,41 @@ static int ti_pipe3_probe(struct platform_device *pdev) struct device_node *control_node; struct platform_device *control_pdev; const struct of_device_id *match; - - match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev); - if (!match) - return -EINVAL; + struct clk *clk; phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); if (!phy) { dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n"); return -ENOMEM; } - - phy->dpll_map = (struct pipe3_dpll_map *)match->data; - if (!phy->dpll_map) { - dev_err(&pdev->dev, "no DPLL data\n"); - return -EINVAL; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); - phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(phy->pll_ctrl_base)) - return PTR_ERR(phy->pll_ctrl_base); - phy->dev = &pdev->dev; - if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { + if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { + match = of_match_device(of_match_ptr(ti_pipe3_id_table), + &pdev->dev); + if (!match) + return -EINVAL; + phy->dpll_map = (struct pipe3_dpll_map *)match->data; + if (!phy->dpll_map) { + dev_err(&pdev->dev, "no DPLL data\n"); + return -EINVAL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pll_ctrl"); + phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(phy->pll_ctrl_base)) + return PTR_ERR(phy->pll_ctrl_base); + + phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); + if (IS_ERR(phy->sys_clk)) { + dev_err(&pdev->dev, "unable to get sysclk\n"); + return -EINVAL; + } + } + + if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); if (IS_ERR(phy->wkupclk)) { dev_err(&pdev->dev, "unable to get wkupclk\n"); @@ -328,10 +345,38 @@ static int ti_pipe3_probe(struct platform_device *pdev) phy->refclk = ERR_PTR(-ENODEV); } - phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); - if (IS_ERR(phy->sys_clk)) { - dev_err(&pdev->dev, "unable to get sysclk\n"); - return -EINVAL; + if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { + if (of_property_read_u8(node, "id", &phy->id) < 0) + phy->id = 1; + + clk = devm_clk_get(phy->dev, "dpll_ref"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get dpll ref clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 1500000000); + + clk = devm_clk_get(phy->dev, "dpll_ref_m2"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get dpll ref m2 clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 100000000); + + clk = devm_clk_get(phy->dev, "phy-div"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get phy-div clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 100000000); + + phy->div_clk = devm_clk_get(phy->dev, "div-clk"); + if (IS_ERR(phy->div_clk)) { + dev_err(&pdev->dev, "unable to get div-clk\n"); + return PTR_ERR(phy->div_clk); + } + } else { + phy->div_clk = ERR_PTR(-ENODEV); } control_node = of_parse_phandle(node, "ctrl-module", 0); @@ -387,6 +432,8 @@ static int ti_pipe3_runtime_suspend(struct device *dev) clk_disable_unprepare(phy->wkupclk); if (!IS_ERR(phy->refclk)) clk_disable_unprepare(phy->refclk); + if (!IS_ERR(phy->div_clk)) + clk_disable_unprepare(phy->div_clk); return 0; } @@ -412,8 +459,19 @@ static int ti_pipe3_runtime_resume(struct device *dev) } } + if (!IS_ERR(phy->div_clk)) { + ret = clk_prepare_enable(phy->div_clk); + if (ret) { + dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); + goto err3; + } + } return 0; +err3: + if (!IS_ERR(phy->wkupclk)) + clk_disable_unprepare(phy->wkupclk); + err2: if (!IS_ERR(phy->refclk)) clk_disable_unprepare(phy->refclk); @@ -446,6 +504,9 @@ static const struct of_device_id ti_pipe3_id_table[] = { .compatible = "ti,phy-pipe3-sata", .data = dpll_map_sata, }, + { + .compatible = "ti,phy-pipe3-pcie", + }, {} }; MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); From f0e2cf7b912522c9c7146d9d6e99d1b0ea5c97c6 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 25 Jun 2014 23:22:57 +0530 Subject: [PATCH 174/211] phy: pipe3: insert delay to enumerate in GEN2 mode 8-bit delay value (0xF1) is required for GEN2 devices to be enumerated consistently. Added an API to be called from PHY drivers to set this delay value and called it from PIPE3 driver to set the delay value. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros --- .../devicetree/bindings/phy/ti-phy.txt | 12 +++-- drivers/phy/phy-omap-control.c | 52 ++++++++++++++++++- drivers/phy/phy-ti-pipe3.c | 4 +- include/linux/phy/omap_control_phy.h | 10 ++++ 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index b50e1c10a05d..305e3df3d9b1 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -9,15 +9,17 @@ Required properties: e.g. USB2_PHY on OMAP5. "ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control e.g. USB3 PHY and SATA PHY on OMAP5. + "ti,control-phy-pcie" - for pcie to support external clock for pcie and to + set PCS delay value. + e.g. PCIE PHY in DRA7x "ti,control-phy-usb2-dra7" - if it has power down register like USB2 PHY on DRA7 platform. "ti,control-phy-usb2-am437" - if it has power down register like USB2 PHY on AM437 platform. - - reg : Address and length of the register set for the device. It contains - the address of "otghs_control" for control-phy-otghs or "power" register - for other types. - - reg-names: should be "otghs_control" control-phy-otghs and "power" for - other types. + - reg : register ranges as listed in the reg-names property + - reg-names: "otghs_control" for control-phy-otghs + "power", "pcie_pcs" and "control_sma" for control-phy-pcie + "power" for all other types omap_control_usb: omap-control-usb@4a002300 { compatible = "ti,control-phy-otghs"; diff --git a/drivers/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c index 311b4f9a5132..9487bf112267 100644 --- a/drivers/phy/phy-omap-control.c +++ b/drivers/phy/phy-omap-control.c @@ -26,6 +26,41 @@ #include #include +/** + * omap_control_pcie_pcs - set the PCS delay count + * @dev: the control module device + * @id: index of the pcie PHY (should be 1 or 2) + * @delay: 8 bit delay value + */ +void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay) +{ + u32 val; + struct omap_control_phy *control_phy; + + if (IS_ERR(dev) || !dev) { + pr_err("%s: invalid device\n", __func__); + return; + } + + control_phy = dev_get_drvdata(dev); + if (!control_phy) { + dev_err(dev, "%s: invalid control phy device\n", __func__); + return; + } + + if (control_phy->type != OMAP_CTRL_TYPE_PCIE) { + dev_err(dev, "%s: unsupported operation\n", __func__); + return; + } + + val = readl(control_phy->pcie_pcs); + val &= ~(OMAP_CTRL_PCIE_PCS_MASK << + (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT)); + val |= delay << (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT); + writel(val, control_phy->pcie_pcs); +} +EXPORT_SYMBOL_GPL(omap_control_pcie_pcs); + /** * omap_control_phy_power - power on/off the phy using control module reg * @dev: the control module device @@ -61,6 +96,7 @@ void omap_control_phy_power(struct device *dev, int on) val |= OMAP_CTRL_DEV_PHY_PD; break; + case OMAP_CTRL_TYPE_PCIE: case OMAP_CTRL_TYPE_PIPE3: rate = clk_get_rate(control_phy->sys_clk); rate = rate/1000000; @@ -211,6 +247,7 @@ EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS; static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2; static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; +static const enum omap_control_phy_type pcie_data = OMAP_CTRL_TYPE_PCIE; static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2; static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2; @@ -227,6 +264,10 @@ static const struct of_device_id omap_control_phy_id_table[] = { .compatible = "ti,control-phy-pipe3", .data = &pipe3_data, }, + { + .compatible = "ti,control-phy-pcie", + .data = &pcie_data, + }, { .compatible = "ti,control-phy-usb2-dra7", .data = &dra7usb2_data, @@ -279,7 +320,8 @@ static int omap_control_phy_probe(struct platform_device *pdev) } } - if (control_phy->type == OMAP_CTRL_TYPE_PIPE3) { + if (control_phy->type == OMAP_CTRL_TYPE_PIPE3 || + control_phy->type == OMAP_CTRL_TYPE_PCIE) { control_phy->sys_clk = devm_clk_get(control_phy->dev, "sys_clkin"); if (IS_ERR(control_phy->sys_clk)) { @@ -288,6 +330,14 @@ static int omap_control_phy_probe(struct platform_device *pdev) } } + if (control_phy->type == OMAP_CTRL_TYPE_PCIE) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pcie_pcs"); + control_phy->pcie_pcs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(control_phy->pcie_pcs)) + return PTR_ERR(control_phy->pcie_pcs); + } + dev_set_drvdata(control_phy->dev, control_phy); return 0; diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 6174f4b1a5de..93bcd67f1b22 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -217,8 +217,10 @@ static int ti_pipe3_init(struct phy *x) u32 val; int ret = 0; - if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) { + omap_control_pcie_pcs(phy->control_dev, phy->id, 0xF1); return 0; + } /* Bring it out of IDLE if it is IDLE */ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); diff --git a/include/linux/phy/omap_control_phy.h b/include/linux/phy/omap_control_phy.h index 5450403c7546..e9e6cfbfbb58 100644 --- a/include/linux/phy/omap_control_phy.h +++ b/include/linux/phy/omap_control_phy.h @@ -23,6 +23,7 @@ enum omap_control_phy_type { OMAP_CTRL_TYPE_OTGHS = 1, /* Mailbox OTGHS_CONTROL */ OMAP_CTRL_TYPE_USB2, /* USB2_PHY, power down in CONTROL_DEV_CONF */ OMAP_CTRL_TYPE_PIPE3, /* PIPE3 PHY, DPLL & seperate Rx/Tx power */ + OMAP_CTRL_TYPE_PCIE, /* RX TX control of ACSPCIE */ OMAP_CTRL_TYPE_DRA7USB2, /* USB2 PHY, power and power_aux e.g. DRA7 */ OMAP_CTRL_TYPE_AM437USB2, /* USB2 PHY, power e.g. AM437x */ }; @@ -33,6 +34,7 @@ struct omap_control_phy { u32 __iomem *otghs_control; u32 __iomem *power; u32 __iomem *power_aux; + u32 __iomem *pcie_pcs; struct clk *sys_clk; @@ -63,6 +65,9 @@ enum omap_control_usb_mode { #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON 0x3 #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF 0x0 +#define OMAP_CTRL_PCIE_PCS_MASK 0xff +#define OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT 0x8 + #define OMAP_CTRL_USB2_PHY_PD BIT(28) #define AM437X_CTRL_USB2_PHY_PD BIT(0) @@ -74,6 +79,7 @@ enum omap_control_usb_mode { void omap_control_phy_power(struct device *dev, int on); void omap_control_usb_set_mode(struct device *dev, enum omap_control_usb_mode mode); +void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay); #else static inline void omap_control_phy_power(struct device *dev, int on) @@ -84,6 +90,10 @@ static inline void omap_control_usb_set_mode(struct device *dev, enum omap_control_usb_mode mode) { } + +static inline void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay) +{ +} #endif #endif /* __OMAP_CONTROL_PHY_H__ */ From f1876accff7ffb3f3cb91ab86aaa866a5eec3f0a Mon Sep 17 00:00:00 2001 From: Jiancheng Xue Date: Thu, 3 Jul 2014 22:28:37 +0800 Subject: [PATCH 175/211] Documentation: Document Hisilicon hix5hd2 sata PHY Add necessary binding documentation SATA PHY on Hisilicon hix5hd2 soc. Signed-off-by: Jiancheng Xue Signed-off-by: Zhangfei Gao Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/hix5hd2-phy.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/hix5hd2-phy.txt diff --git a/Documentation/devicetree/bindings/phy/hix5hd2-phy.txt b/Documentation/devicetree/bindings/phy/hix5hd2-phy.txt new file mode 100644 index 000000000000..296168b74d24 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/hix5hd2-phy.txt @@ -0,0 +1,22 @@ +Hisilicon hix5hd2 SATA PHY +----------------------- + +Required properties: +- compatible: should be "hisilicon,hix5hd2-sata-phy" +- reg: offset and length of the PHY registers +- #phy-cells: must be 0 +Refer to phy/phy-bindings.txt for the generic PHY binding properties + +Optional Properties: +- hisilicon,peripheral-syscon: phandle of syscon used to control peripheral. +- hisilicon,power-reg: offset and bit number within peripheral-syscon, + register of controlling sata power supply. + +Example: + sata_phy: phy@f9900000 { + compatible = "hisilicon,hix5hd2-sata-phy"; + reg = <0xf9900000 0x10000>; + #phy-cells = <0>; + hisilicon,peripheral-syscon = <&peripheral_ctrl>; + hisilicon,power-reg = <0x8 10>; + }; From e379413a346ce5943ab895aa5a702ec752577f13 Mon Sep 17 00:00:00 2001 From: Jiancheng Xue Date: Thu, 3 Jul 2014 22:28:38 +0800 Subject: [PATCH 176/211] phy: add hix5hd2-sata-phy driver Add hix5hd2-sata-phy driver on Hisilicon hix5hd2 soc. Signed-off-by: Jiancheng Xue Signed-off-by: Zhangfei Gao Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 8 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-hix5hd2-sata.c | 192 +++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 drivers/phy/phy-hix5hd2-sata.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 64b98d242ea6..30c82fcbb492 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -109,6 +109,14 @@ config PHY_EXYNOS5250_SATA SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host port to accept one SATA device. +config PHY_HIX5HD2_SATA + tristate "HIX5HD2 SATA PHY Driver" + depends on ARCH_HIX5HD2 && OF && HAS_IOMEM + select GENERIC_PHY + select MFD_SYSCON + help + Support for SATA PHY on Hisilicon hix5hd2 Soc. + config PHY_SUN4I_USB tristate "Allwinner sunxi SoC USB PHY driver" depends on ARCH_SUNXI && HAS_IOMEM && OF diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index b4f1d5770601..54f04d04e85d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o +obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o phy-exynos-usb2-y += phy-samsung-usb2.o diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c new file mode 100644 index 000000000000..d44283453d71 --- /dev/null +++ b/drivers/phy/phy-hix5hd2-sata.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2014 Linaro Ltd. + * Copyright (c) 2014 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SATA_PHY0_CTLL 0xa0 +#define MPLL_MULTIPLIER_SHIFT 1 +#define MPLL_MULTIPLIER_MASK 0xfe +#define MPLL_MULTIPLIER_50M 0x3c +#define MPLL_MULTIPLIER_100M 0x1e +#define PHY_RESET BIT(0) +#define REF_SSP_EN BIT(9) +#define SSC_EN BIT(10) +#define REF_USE_PAD BIT(23) + +#define SATA_PORT_PHYCTL 0x174 +#define SPEED_MODE_MASK 0x6f0000 +#define HALF_RATE_SHIFT 16 +#define PHY_CONFIG_SHIFT 18 +#define GEN2_EN_SHIFT 21 +#define SPEED_CTRL BIT(20) + +#define SATA_PORT_PHYCTL1 0x148 +#define AMPLITUDE_MASK 0x3ffffe +#define AMPLITUDE_GEN3 0x68 +#define AMPLITUDE_GEN3_SHIFT 15 +#define AMPLITUDE_GEN2 0x56 +#define AMPLITUDE_GEN2_SHIFT 8 +#define AMPLITUDE_GEN1 0x56 +#define AMPLITUDE_GEN1_SHIFT 1 + +#define SATA_PORT_PHYCTL2 0x14c +#define PREEMPH_MASK 0x3ffff +#define PREEMPH_GEN3 0x20 +#define PREEMPH_GEN3_SHIFT 12 +#define PREEMPH_GEN2 0x15 +#define PREEMPH_GEN2_SHIFT 6 +#define PREEMPH_GEN1 0x5 +#define PREEMPH_GEN1_SHIFT 0 + +struct hix5hd2_priv { + void __iomem *base; + struct regmap *peri_ctrl; +}; + +enum phy_speed_mode { + SPEED_MODE_GEN1 = 0, + SPEED_MODE_GEN2 = 1, + SPEED_MODE_GEN3 = 2, +}; + +static int hix5hd2_sata_phy_init(struct phy *phy) +{ + struct hix5hd2_priv *priv = phy_get_drvdata(phy); + u32 val, data[2]; + int ret; + + if (priv->peri_ctrl) { + ret = of_property_read_u32_array(phy->dev.of_node, + "hisilicon,power-reg", + &data[0], 2); + if (ret) { + dev_err(&phy->dev, "Fail read hisilicon,power-reg\n"); + return ret; + } + + regmap_update_bits(priv->peri_ctrl, data[0], + BIT(data[1]), BIT(data[1])); + } + + /* reset phy */ + val = readl_relaxed(priv->base + SATA_PHY0_CTLL); + val &= ~(MPLL_MULTIPLIER_MASK | REF_USE_PAD); + val |= MPLL_MULTIPLIER_50M << MPLL_MULTIPLIER_SHIFT | + REF_SSP_EN | PHY_RESET; + writel_relaxed(val, priv->base + SATA_PHY0_CTLL); + msleep(20); + val &= ~PHY_RESET; + writel_relaxed(val, priv->base + SATA_PHY0_CTLL); + + val = readl_relaxed(priv->base + SATA_PORT_PHYCTL1); + val &= ~AMPLITUDE_MASK; + val |= AMPLITUDE_GEN3 << AMPLITUDE_GEN3_SHIFT | + AMPLITUDE_GEN2 << AMPLITUDE_GEN2_SHIFT | + AMPLITUDE_GEN1 << AMPLITUDE_GEN1_SHIFT; + writel_relaxed(val, priv->base + SATA_PORT_PHYCTL1); + + val = readl_relaxed(priv->base + SATA_PORT_PHYCTL2); + val &= ~PREEMPH_MASK; + val |= PREEMPH_GEN3 << PREEMPH_GEN3_SHIFT | + PREEMPH_GEN2 << PREEMPH_GEN2_SHIFT | + PREEMPH_GEN1 << PREEMPH_GEN1_SHIFT; + writel_relaxed(val, priv->base + SATA_PORT_PHYCTL2); + + /* ensure PHYCTRL setting takes effect */ + val = readl_relaxed(priv->base + SATA_PORT_PHYCTL); + val &= ~SPEED_MODE_MASK; + val |= SPEED_MODE_GEN1 << HALF_RATE_SHIFT | + SPEED_MODE_GEN1 << PHY_CONFIG_SHIFT | + SPEED_MODE_GEN1 << GEN2_EN_SHIFT | SPEED_CTRL; + writel_relaxed(val, priv->base + SATA_PORT_PHYCTL); + + msleep(20); + val &= ~SPEED_MODE_MASK; + val |= SPEED_MODE_GEN3 << HALF_RATE_SHIFT | + SPEED_MODE_GEN3 << PHY_CONFIG_SHIFT | + SPEED_MODE_GEN3 << GEN2_EN_SHIFT | SPEED_CTRL; + writel_relaxed(val, priv->base + SATA_PORT_PHYCTL); + + val &= ~(SPEED_MODE_MASK | SPEED_CTRL); + val |= SPEED_MODE_GEN2 << HALF_RATE_SHIFT | + SPEED_MODE_GEN2 << PHY_CONFIG_SHIFT | + SPEED_MODE_GEN2 << GEN2_EN_SHIFT; + writel_relaxed(val, priv->base + SATA_PORT_PHYCTL); + + return 0; +} + +static struct phy_ops hix5hd2_sata_phy_ops = { + .init = hix5hd2_sata_phy_init, + .owner = THIS_MODULE, +}; + +static int hix5hd2_sata_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct resource *res; + struct phy *phy; + struct hix5hd2_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->base) + return -ENOMEM; + + priv->peri_ctrl = syscon_regmap_lookup_by_phandle(dev->of_node, + "hisilicon,peripheral-syscon"); + if (IS_ERR(priv->peri_ctrl)) + priv->peri_ctrl = NULL; + + phy = devm_phy_create(dev, &hix5hd2_sata_phy_ops, NULL); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, priv); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + return 0; +} + +static const struct of_device_id hix5hd2_sata_phy_of_match[] = { + {.compatible = "hisilicon,hix5hd2-sata-phy",}, + { }, +}; +MODULE_DEVICE_TABLE(of, hix5hd2_sata_phy_of_match); + +static struct platform_driver hix5hd2_sata_phy_driver = { + .probe = hix5hd2_sata_phy_probe, + .driver = { + .name = "hix5hd2-sata-phy", + .owner = THIS_MODULE, + .of_match_table = hix5hd2_sata_phy_of_match, + } +}; +module_platform_driver(hix5hd2_sata_phy_driver); + +MODULE_AUTHOR("Jiancheng Xue "); +MODULE_DESCRIPTION("HISILICON HIX5HD2 SATA PHY driver"); +MODULE_ALIAS("platform:hix5hd2-sata-phy"); +MODULE_LICENSE("GPL v2"); From 016e0d3cb72c1433810fd85a7a7c0946e710d3d6 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 7 Jul 2014 11:39:26 +0200 Subject: [PATCH 177/211] drivers: phy: exynos-usb2: add support for Exynos 3250 This patch adds support for Exynos3250 SoC to Exynos2USB PHY driver. Although Exynos3250 has only one device phy interface, the register layout and all operations that are required to get it enabled are almost same as on Exynos4x12. The only different is one more register (REFCLKSEL) which need to be set and lack of MODE SWITCH register. Signed-off-by: Marek Szyprowski Reviewed-by: Tomasz Figa Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/samsung-phy.txt | 2 ++ drivers/phy/Kconfig | 12 ++++++------ drivers/phy/phy-exynos4x12-usb2.c | 17 +++++++++++++++-- drivers/phy/phy-samsung-usb2.c | 6 ++++++ drivers/phy/phy-samsung-usb2.h | 2 ++ 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index 2049261d8c31..6099a5c94283 100644 --- a/Documentation/devicetree/bindings/phy/samsung-phy.txt +++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt @@ -26,6 +26,7 @@ Samsung S5P/EXYNOS SoC series USB PHY Required properties: - compatible : should be one of the listed compatibles: + - "samsung,exynos3250-usb2-phy" - "samsung,exynos4210-usb2-phy" - "samsung,exynos4x12-usb2-phy" - "samsung,exynos5250-usb2-phy" @@ -46,6 +47,7 @@ and Exynos 4212) it is as follows: 1 - USB host ("host"), 2 - HSIC0 ("hsic0"), 3 - HSIC1 ("hsic1"), +Exynos3250 has only USB device phy available as phy 0. Exynos 4210 and Exynos 4212 use mode switching and require that mode switch register is supplied. diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 30c82fcbb492..7c49c4c61727 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -151,14 +151,14 @@ config PHY_EXYNOS4210_USB2 phys are available - device, host, HSIC0 and HSIC1. config PHY_EXYNOS4X12_USB2 - bool "Support for Exynos 4x12" + bool "Support for Exynos 3250/4x12" depends on PHY_SAMSUNG_USB2 - depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412) + depends on (SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412) help - Enable USB PHY support for Exynos 4x12. This option requires that - Samsung USB 2.0 PHY driver is enabled and means that support for this - particular SoC is compiled in the driver. In case of Exynos 4x12 four - phys are available - device, host, HSIC0 and HSIC1. + Enable USB PHY support for Exynos 3250/4x12. This option requires + that Samsung USB 2.0 PHY driver is enabled and means that support for + this particular SoC is compiled in the driver. In case of Exynos 4x12 + four phys are available - device, host, HSIC0 and HSIC1. config PHY_EXYNOS5250_USB2 bool "Support for Exynos 5250" diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c index 63134d8bda08..0b9de88579b1 100644 --- a/drivers/phy/phy-exynos4x12-usb2.c +++ b/drivers/phy/phy-exynos4x12-usb2.c @@ -67,6 +67,8 @@ #define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ (0x5 << 0) #define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ (0x7 << 0) +#define EXYNOS_3250_UPHYCLK_REFCLKSEL (0x2 << 8) + #define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3) #define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4) #define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7) @@ -197,6 +199,10 @@ static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst) clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK); clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK; + + if (drv->cfg->has_refclk_sel) + clk = EXYNOS_3250_UPHYCLK_REFCLKSEL; + clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET; clk |= EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON; writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK); @@ -278,7 +284,7 @@ static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]); } - if (inst->cfg->id == EXYNOS4x12_DEVICE) + if (inst->cfg->id == EXYNOS4x12_DEVICE && drv->cfg->has_mode_switch) regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, EXYNOS_4x12_MODE_SWITCH_MASK, EXYNOS_4x12_MODE_SWITCH_DEVICE); @@ -310,7 +316,7 @@ static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst) if (inst->ext_cnt-- > 1) return 0; - if (inst->cfg->id == EXYNOS4x12_DEVICE) + if (inst->cfg->id == EXYNOS4x12_DEVICE && drv->cfg->has_mode_switch) regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, EXYNOS_4x12_MODE_SWITCH_MASK, EXYNOS_4x12_MODE_SWITCH_HOST); @@ -358,6 +364,13 @@ static const struct samsung_usb2_common_phy exynos4x12_phys[] = { {}, }; +const struct samsung_usb2_phy_config exynos3250_usb2_phy_config = { + .has_refclk_sel = 1, + .num_phys = 1, + .phys = exynos4x12_phys, + .rate_to_clk = exynos4x12_rate_to_clk, +}; + const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = { .has_mode_switch = 1, .num_phys = EXYNOS4x12_NUM_PHYS, diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c index 1e69a32c221d..16aae7a285f0 100644 --- a/drivers/phy/phy-samsung-usb2.c +++ b/drivers/phy/phy-samsung-usb2.c @@ -87,6 +87,12 @@ static struct phy *samsung_usb2_phy_xlate(struct device *dev, } static const struct of_device_id samsung_usb2_phy_of_match[] = { +#ifdef CONFIG_PHY_EXYNOS4X12_USB2 + { + .compatible = "samsung,exynos3250-usb2-phy", + .data = &exynos3250_usb2_phy_config, + }, +#endif #ifdef CONFIG_PHY_EXYNOS4210_USB2 { .compatible = "samsung,exynos4210-usb2-phy", diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h index 918847843a95..b03da0ef39ac 100644 --- a/drivers/phy/phy-samsung-usb2.h +++ b/drivers/phy/phy-samsung-usb2.h @@ -60,8 +60,10 @@ struct samsung_usb2_phy_config { int (*rate_to_clk)(unsigned long, u32 *); unsigned int num_phys; bool has_mode_switch; + bool has_refclk_sel; }; +extern const struct samsung_usb2_phy_config exynos3250_usb2_phy_config; extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config; extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config; extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config; From 3be88125d85df587085b0be0a5c0e9953eb5ed6b Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 4 Jul 2014 12:55:45 +0300 Subject: [PATCH 178/211] phy: core: Support regulator supply for PHY power Some PHYs can be powered by an external power regulator. e.g. USB_HS PHY on DRA7 SoC. Make the PHY core support a power regulator. Signed-off-by: Roger Quadros Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-core.c | 26 ++++++++++++++++++++++++++ include/linux/phy/phy.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 49c446530101..75c97396dbfa 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -21,6 +21,7 @@ #include #include #include +#include static struct class *phy_class; static DEFINE_MUTEX(phy_provider_mutex); @@ -226,6 +227,12 @@ int phy_power_on(struct phy *phy) if (!phy) return 0; + if (phy->pwr) { + ret = regulator_enable(phy->pwr); + if (ret) + return ret; + } + ret = phy_pm_runtime_get_sync(phy); if (ret < 0 && ret != -ENOTSUPP) return ret; @@ -247,6 +254,8 @@ int phy_power_on(struct phy *phy) out: mutex_unlock(&phy->mutex); phy_pm_runtime_put_sync(phy); + if (phy->pwr) + regulator_disable(phy->pwr); return ret; } @@ -272,6 +281,9 @@ int phy_power_off(struct phy *phy) mutex_unlock(&phy->mutex); phy_pm_runtime_put(phy); + if (phy->pwr) + regulator_disable(phy->pwr); + return 0; } EXPORT_SYMBOL_GPL(phy_power_off); @@ -588,6 +600,16 @@ struct phy *phy_create(struct device *dev, const struct phy_ops *ops, goto free_phy; } + /* phy-supply */ + phy->pwr = regulator_get_optional(dev, "phy"); + if (IS_ERR(phy->pwr)) { + if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto free_ida; + } + phy->pwr = NULL; + } + device_initialize(&phy->dev); mutex_init(&phy->mutex); @@ -617,6 +639,9 @@ struct phy *phy_create(struct device *dev, const struct phy_ops *ops, put_device(&phy->dev); /* calls phy_release() which frees resources */ return ERR_PTR(ret); +free_ida: + ida_simple_remove(&phy_ida, phy->id); + free_phy: kfree(phy); return ERR_PTR(ret); @@ -800,6 +825,7 @@ static void phy_release(struct device *dev) phy = to_phy(dev); dev_vdbg(dev, "releasing '%s'\n", dev_name(dev)); + regulator_put(phy->pwr); ida_simple_remove(&phy_ida, phy->id); kfree(phy); } diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 2760744cb2a7..9a8694524742 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -18,6 +18,7 @@ #include #include #include +#include struct phy; @@ -65,6 +66,7 @@ struct phy { int init_count; int power_count; struct phy_attrs attrs; + struct regulator *pwr; }; /** From e9e8cf49f9ebbdc8ffafc9627bfade76c5384845 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 4 Jul 2014 12:55:46 +0300 Subject: [PATCH 179/211] phy: core: Add phy-supply to DT binding documentation phy-supply is a phandle to the regulator that provides power to the PHY. This regulator is managed during the PHY power on/off sequence by the phy core driver. Signed-off-by: Roger Quadros Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/phy-bindings.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/phy-bindings.txt b/Documentation/devicetree/bindings/phy/phy-bindings.txt index 8ae844fc0c60..2aa1840200ed 100644 --- a/Documentation/devicetree/bindings/phy/phy-bindings.txt +++ b/Documentation/devicetree/bindings/phy/phy-bindings.txt @@ -10,6 +10,10 @@ Required Properties: provider can use the values in cells to find the appropriate PHY. +Optional Properties: +phy-supply: Phandle to a regulator that provides power to the PHY. This + regulator will be managed during the PHY power on/off sequence. + For example: phys: phy { From d6125af9afd622b6dbb6d7cd97972e2f398b8d35 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 14 Jul 2014 15:38:41 +0530 Subject: [PATCH 180/211] phy: Kconfig: Re-organize Exynos USB 2.0 PHY configs Since the USB 2.0 PHYs are required with EHCI/OHCI USB drivers and USB gadget controller supported by the DWC2 gadget driver, make it depend on them and default to ARCH_EXYNOS as they are meant for Exynos platforms. Also, make the sub-drivers silent options enabling them based on the SoC platforms that they are meant to work with. This will make life easier for end users who do not have any way knowing the dependencies. Signed-off-by: Sachin Kamat Reviewed-by: Jingoo Han Tested-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 7c49c4c61727..f28b87f1582d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -132,43 +132,30 @@ config PHY_SUN4I_USB config PHY_SAMSUNG_USB2 tristate "Samsung USB 2.0 PHY driver" depends on HAS_IOMEM + depends on USB_EHCI_EXYNOS || USB_OHCI_EXYNOS || USB_DWC2 select GENERIC_PHY select MFD_SYSCON + default ARCH_EXYNOS help Enable this to support the Samsung USB 2.0 PHY driver for Samsung - SoCs. This driver provides the interface for USB 2.0 PHY. Support for - particular SoCs has to be enabled in addition to this driver. Number - and type of supported phys depends on the SoC. + SoCs. This driver provides the interface for USB 2.0 PHY. Support + for particular PHYs will be enabled based on the SoC type in addition + to this driver. config PHY_EXYNOS4210_USB2 - bool "Support for Exynos 4210" + bool depends on PHY_SAMSUNG_USB2 - depends on CPU_EXYNOS4210 - help - Enable USB PHY support for Exynos 4210. This option requires that - Samsung USB 2.0 PHY driver is enabled and means that support for this - particular SoC is compiled in the driver. In case of Exynos 4210 four - phys are available - device, host, HSIC0 and HSIC1. + default CPU_EXYNOS4210 config PHY_EXYNOS4X12_USB2 - bool "Support for Exynos 3250/4x12" + bool depends on PHY_SAMSUNG_USB2 - depends on (SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412) - help - Enable USB PHY support for Exynos 3250/4x12. This option requires - that Samsung USB 2.0 PHY driver is enabled and means that support for - this particular SoC is compiled in the driver. In case of Exynos 4x12 - four phys are available - device, host, HSIC0 and HSIC1. + default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412 config PHY_EXYNOS5250_USB2 - bool "Support for Exynos 5250" + bool depends on PHY_SAMSUNG_USB2 - depends on SOC_EXYNOS5250 - help - Enable USB PHY support for Exynos 5250. This option requires that - Samsung USB 2.0 PHY driver is enabled and means that support for this - particular SoC is compiled in the driver. In case of Exynos 5250 four - phys are available - device, host, HSIC0 and HSIC. + default SOC_EXYNOS5250 || SOC_EXYNOS5420 config PHY_EXYNOS5_USBDRD tristate "Exynos5 SoC series USB DRD PHY driver" From c233f529480398d46d7098316fc7203587f03c0f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 14 Jul 2014 15:38:42 +0530 Subject: [PATCH 181/211] phy: Kconfig: Update config for Exynos USB DRD USB DWC3 driver on Exynos platform does not work without its corresponding phy driver. Hence make the PHY driver depend on Exynos DWC3 driver and default it to yes to make things easier for the end user. Signed-off-by: Sachin Kamat Reviewed-by: Jingoo Han Tested-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index f28b87f1582d..778e126700bf 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -161,8 +161,10 @@ config PHY_EXYNOS5_USBDRD tristate "Exynos5 SoC series USB DRD PHY driver" depends on ARCH_EXYNOS5 && OF depends on HAS_IOMEM + depends on USB_DWC3_EXYNOS select GENERIC_PHY select MFD_SYSCON + default y help Enable USB DRD PHY support for Exynos 5 SoC series. This driver provides PHY interface for USB 3.0 DRD controller From 1de990d8a169de8aa971cea650e5dec6cdf62a09 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 14 Jul 2014 12:17:59 +0100 Subject: [PATCH 182/211] phy: qcom: Add driver for QCOM APQ8064 SATA PHY Add a PHY driver for uses with AHCI based SATA controller driver on the APQ8064 family of SoCs. This patch is a forward port from Qualcomm's v3.4 andriod kernel. Tested on IFC6410 board. CC: Sujit Reddy Thumma Tested-by: Kiran Padwal Signed-off-by: Srinivas Kandagatla Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-qcom-apq8064-sata.c | 288 ++++++++++++++++++++++++++++ 3 files changed, 296 insertions(+) create mode 100644 drivers/phy/phy-qcom-apq8064-sata.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 778e126700bf..691115292a99 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -177,4 +177,11 @@ config PHY_XGENE help This option enables support for APM X-Gene SoC multi-purpose PHY. +config PHY_QCOM_APQ8064_SATA + tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" + depends on ARCH_QCOM + depends on HAS_IOMEM + depends on OF + select GENERIC_PHY + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 54f04d04e85d..a4819d378619 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -21,3 +21,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o +obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c new file mode 100644 index 000000000000..c9b4dd6becf5 --- /dev/null +++ b/drivers/phy/phy-qcom-apq8064-sata.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PHY registers */ +#define UNIPHY_PLL_REFCLK_CFG 0x000 +#define UNIPHY_PLL_PWRGEN_CFG 0x014 +#define UNIPHY_PLL_GLB_CFG 0x020 +#define UNIPHY_PLL_SDM_CFG0 0x038 +#define UNIPHY_PLL_SDM_CFG1 0x03C +#define UNIPHY_PLL_SDM_CFG2 0x040 +#define UNIPHY_PLL_SDM_CFG3 0x044 +#define UNIPHY_PLL_SDM_CFG4 0x048 +#define UNIPHY_PLL_SSC_CFG0 0x04C +#define UNIPHY_PLL_SSC_CFG1 0x050 +#define UNIPHY_PLL_SSC_CFG2 0x054 +#define UNIPHY_PLL_SSC_CFG3 0x058 +#define UNIPHY_PLL_LKDET_CFG0 0x05C +#define UNIPHY_PLL_LKDET_CFG1 0x060 +#define UNIPHY_PLL_LKDET_CFG2 0x064 +#define UNIPHY_PLL_CAL_CFG0 0x06C +#define UNIPHY_PLL_CAL_CFG8 0x08C +#define UNIPHY_PLL_CAL_CFG9 0x090 +#define UNIPHY_PLL_CAL_CFG10 0x094 +#define UNIPHY_PLL_CAL_CFG11 0x098 +#define UNIPHY_PLL_STATUS 0x0C0 + +#define SATA_PHY_SER_CTRL 0x100 +#define SATA_PHY_TX_DRIV_CTRL0 0x104 +#define SATA_PHY_TX_DRIV_CTRL1 0x108 +#define SATA_PHY_TX_IMCAL0 0x11C +#define SATA_PHY_TX_IMCAL2 0x124 +#define SATA_PHY_RX_IMCAL0 0x128 +#define SATA_PHY_EQUAL 0x13C +#define SATA_PHY_OOB_TERM 0x144 +#define SATA_PHY_CDR_CTRL0 0x148 +#define SATA_PHY_CDR_CTRL1 0x14C +#define SATA_PHY_CDR_CTRL2 0x150 +#define SATA_PHY_CDR_CTRL3 0x154 +#define SATA_PHY_PI_CTRL0 0x168 +#define SATA_PHY_POW_DWN_CTRL0 0x180 +#define SATA_PHY_POW_DWN_CTRL1 0x184 +#define SATA_PHY_TX_DATA_CTRL 0x188 +#define SATA_PHY_ALIGNP 0x1A4 +#define SATA_PHY_TX_IMCAL_STAT 0x1E4 +#define SATA_PHY_RX_IMCAL_STAT 0x1E8 + +#define UNIPHY_PLL_LOCK BIT(0) +#define SATA_PHY_TX_CAL BIT(0) +#define SATA_PHY_RX_CAL BIT(0) + +/* default timeout set to 1 sec */ +#define TIMEOUT_MS 10000 +#define DELAY_INTERVAL_US 100 + +struct qcom_apq8064_sata_phy { + void __iomem *mmio; + struct clk *cfg_clk; + struct device *dev; +}; + +/* Helper function to do poll and timeout */ +static int read_poll_timeout(void __iomem *addr, u32 mask) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); + + do { + if (readl_relaxed(addr) & mask) + return 0; + + usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); + } while (!time_after(jiffies, timeout)); + + return -ETIMEDOUT; +} + +static int qcom_apq8064_sata_phy_init(struct phy *generic_phy) +{ + struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); + void __iomem *base = phy->mmio; + int ret = 0; + + /* SATA phy initialization */ + writel_relaxed(0x01, base + SATA_PHY_SER_CTRL); + writel_relaxed(0xB1, base + SATA_PHY_POW_DWN_CTRL0); + /* Make sure the power down happens before power up */ + mb(); + usleep_range(10, 60); + + writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); + writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); + writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); + writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); + writel_relaxed(0x02, base + SATA_PHY_TX_IMCAL2); + + /* Write UNIPHYPLL registers to configure PLL */ + writel_relaxed(0x04, base + UNIPHY_PLL_REFCLK_CFG); + writel_relaxed(0x00, base + UNIPHY_PLL_PWRGEN_CFG); + + writel_relaxed(0x0A, base + UNIPHY_PLL_CAL_CFG0); + writel_relaxed(0xF3, base + UNIPHY_PLL_CAL_CFG8); + writel_relaxed(0x01, base + UNIPHY_PLL_CAL_CFG9); + writel_relaxed(0xED, base + UNIPHY_PLL_CAL_CFG10); + writel_relaxed(0x02, base + UNIPHY_PLL_CAL_CFG11); + + writel_relaxed(0x36, base + UNIPHY_PLL_SDM_CFG0); + writel_relaxed(0x0D, base + UNIPHY_PLL_SDM_CFG1); + writel_relaxed(0xA3, base + UNIPHY_PLL_SDM_CFG2); + writel_relaxed(0xF0, base + UNIPHY_PLL_SDM_CFG3); + writel_relaxed(0x00, base + UNIPHY_PLL_SDM_CFG4); + + writel_relaxed(0x19, base + UNIPHY_PLL_SSC_CFG0); + writel_relaxed(0xE1, base + UNIPHY_PLL_SSC_CFG1); + writel_relaxed(0x00, base + UNIPHY_PLL_SSC_CFG2); + writel_relaxed(0x11, base + UNIPHY_PLL_SSC_CFG3); + + writel_relaxed(0x04, base + UNIPHY_PLL_LKDET_CFG0); + writel_relaxed(0xFF, base + UNIPHY_PLL_LKDET_CFG1); + + writel_relaxed(0x02, base + UNIPHY_PLL_GLB_CFG); + /* make sure global config LDO power down happens before power up */ + mb(); + + writel_relaxed(0x03, base + UNIPHY_PLL_GLB_CFG); + writel_relaxed(0x05, base + UNIPHY_PLL_LKDET_CFG2); + + /* PLL Lock wait */ + ret = read_poll_timeout(base + UNIPHY_PLL_STATUS, UNIPHY_PLL_LOCK); + if (ret) { + dev_err(phy->dev, "poll timeout UNIPHY_PLL_STATUS\n"); + return ret; + } + + /* TX Calibration */ + ret = read_poll_timeout(base + SATA_PHY_TX_IMCAL_STAT, SATA_PHY_TX_CAL); + if (ret) { + dev_err(phy->dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n"); + return ret; + } + + /* RX Calibration */ + ret = read_poll_timeout(base + SATA_PHY_RX_IMCAL_STAT, SATA_PHY_RX_CAL); + if (ret) { + dev_err(phy->dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n"); + return ret; + } + + /* SATA phy calibrated succesfully, power up to functional mode */ + writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); + writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); + writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); + + writel_relaxed(0x00, base + SATA_PHY_POW_DWN_CTRL1); + writel_relaxed(0x59, base + SATA_PHY_CDR_CTRL0); + writel_relaxed(0x04, base + SATA_PHY_CDR_CTRL1); + writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL2); + writel_relaxed(0x00, base + SATA_PHY_PI_CTRL0); + writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL3); + writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); + + writel_relaxed(0x11, base + SATA_PHY_TX_DATA_CTRL); + writel_relaxed(0x43, base + SATA_PHY_ALIGNP); + writel_relaxed(0x04, base + SATA_PHY_OOB_TERM); + + writel_relaxed(0x01, base + SATA_PHY_EQUAL); + writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL0); + writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL1); + + return 0; +} + +static int qcom_apq8064_sata_phy_exit(struct phy *generic_phy) +{ + struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); + void __iomem *base = phy->mmio; + + /* Power down PHY */ + writel_relaxed(0xF8, base + SATA_PHY_POW_DWN_CTRL0); + writel_relaxed(0xFE, base + SATA_PHY_POW_DWN_CTRL1); + + /* Power down PLL block */ + writel_relaxed(0x00, base + UNIPHY_PLL_GLB_CFG); + + return 0; +} + +static struct phy_ops qcom_apq8064_sata_phy_ops = { + .init = qcom_apq8064_sata_phy_init, + .exit = qcom_apq8064_sata_phy_exit, + .owner = THIS_MODULE, +}; + +static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev) +{ + struct qcom_apq8064_sata_phy *phy; + struct device *dev = &pdev->dev; + struct resource *res; + struct phy_provider *phy_provider; + struct phy *generic_phy; + int ret; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(phy->mmio)) + return PTR_ERR(phy->mmio); + + generic_phy = devm_phy_create(dev, &qcom_apq8064_sata_phy_ops, NULL); + if (IS_ERR(generic_phy)) { + dev_err(dev, "%s: failed to create phy\n", __func__); + return PTR_ERR(generic_phy); + } + + phy->dev = dev; + phy_set_drvdata(generic_phy, phy); + platform_set_drvdata(pdev, phy); + + phy->cfg_clk = devm_clk_get(dev, "cfg"); + if (IS_ERR(phy->cfg_clk)) { + dev_err(dev, "Failed to get sata cfg clock\n"); + return PTR_ERR(phy->cfg_clk); + } + + ret = clk_prepare_enable(phy->cfg_clk); + if (ret) + return ret; + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + clk_disable_unprepare(phy->cfg_clk); + dev_err(dev, "%s: failed to register phy\n", __func__); + return PTR_ERR(phy_provider); + } + + return 0; +} + +static int qcom_apq8064_sata_phy_remove(struct platform_device *pdev) +{ + struct qcom_apq8064_sata_phy *phy = platform_get_drvdata(pdev); + + clk_disable_unprepare(phy->cfg_clk); + + return 0; +} + +static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = { + { .compatible = "qcom,apq8064-sata-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_apq8064_sata_phy_of_match); + +static struct platform_driver qcom_apq8064_sata_phy_driver = { + .probe = qcom_apq8064_sata_phy_probe, + .remove = qcom_apq8064_sata_phy_remove, + .driver = { + .name = "qcom-apq8064-sata-phy", + .owner = THIS_MODULE, + .of_match_table = qcom_apq8064_sata_phy_of_match, + } +}; +module_platform_driver(qcom_apq8064_sata_phy_driver); + +MODULE_DESCRIPTION("QCOM apq8064 SATA PHY driver"); +MODULE_LICENSE("GPL v2"); From e299f59a2ea1d1f6ce43ebfc56c75ea266a056de Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 14 Jul 2014 12:18:08 +0100 Subject: [PATCH 183/211] phy: qcom: Add APQ8064 SATA PHY device tree bindings This patch adds binding spec for Qualcomm AP8064 SATA PHY. Signed-off-by: Srinivas Kandagatla Tested-by: Kiran Padwal Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/qcom-apq8064-sata-phy.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/qcom-apq8064-sata-phy.txt diff --git a/Documentation/devicetree/bindings/phy/qcom-apq8064-sata-phy.txt b/Documentation/devicetree/bindings/phy/qcom-apq8064-sata-phy.txt new file mode 100644 index 000000000000..952f6c96bab9 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom-apq8064-sata-phy.txt @@ -0,0 +1,24 @@ +Qualcomm APQ8064 SATA PHY Controller +------------------------------------ + +SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers. +Each SATA PHY controller should have its own node. + +Required properties: +- compatible: compatible list, contains "qcom,apq8064-sata-phy". +- reg: offset and length of the SATA PHY register set; +- #phy-cells: must be zero +- clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. +- clock-names: must be "cfg" for phy config clock. + +Example: + sata_phy: sata-phy@1b400000 { + compatible = "qcom,apq8064-sata-phy"; + reg = <0x1b400000 0x200>; + + clocks = <&gcc SATA_PHY_CFG_CLK>; + clock-names = "cfg"; + + #phy-cells = <0>; + }; From 74d64b59b49b322c8bbc73cdaba37348faf59582 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 10 Jul 2014 23:36:30 +0200 Subject: [PATCH 184/211] phy: Remove ARCH_KIRKWOOD dependency mach-kirkwood has been removed, now that kirkwood lives in mach-mvebu. Depend on MACH_KIRKWOOD, which will be set when these SoCs are built as part of mach-mvebv. Signed-off-by: Andrew Lunn Cc: Kishon Vijay Abraham I Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 691115292a99..261ad18854c1 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -27,7 +27,7 @@ config PHY_EXYNOS_MIPI_VIDEO config PHY_MVEBU_SATA def_bool y - depends on ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD + depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD depends on OF select GENERIC_PHY From 942a31b521911b0f162a37844c29f91022d129f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Mon, 7 Jul 2014 12:16:07 +0200 Subject: [PATCH 185/211] phy: add a driver for the Berlin SATA PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Berlin SoC has a two SATA ports. Add a PHY driver to handle them. The mode selection can let us think this PHY can be configured to fit other purposes. But there are reasons to think the SATA mode will be the only one usable: the PHY registers are only accessible indirectly through two registers in the SATA range, the PHY seems to be integrated and no information tells us the contrary. For these reasons, make the driver a SATA PHY driver. Signed-off-by: Antoine Ténart Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-berlin-sata.c | 284 ++++++++++++++++++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 drivers/phy/phy-berlin-sata.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 261ad18854c1..1704fd4be99e 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -15,6 +15,13 @@ config GENERIC_PHY phy users can obtain reference to the PHY. All the users of this framework should select this config. +config PHY_BERLIN_SATA + tristate "Marvell Berlin SATA PHY driver" + depends on ARCH_BERLIN && HAS_IOMEM && OF + select GENERIC_PHY + help + Enable this to support the SATA PHY on Marvell Berlin SoCs. + config PHY_EXYNOS_MIPI_VIDEO tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" depends on HAS_IOMEM diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index a4819d378619..3c2ad5915be2 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_GENERIC_PHY) += phy-core.o +obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c new file mode 100644 index 000000000000..c5e688b0899f --- /dev/null +++ b/drivers/phy/phy-berlin-sata.c @@ -0,0 +1,284 @@ +/* + * Marvell Berlin SATA PHY driver + * + * Copyright (C) 2014 Marvell Technology Group Ltd. + * + * Antoine Ténart + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#define HOST_VSA_ADDR 0x0 +#define HOST_VSA_DATA 0x4 +#define PORT_SCR_CTL 0x2c +#define PORT_VSR_ADDR 0x78 +#define PORT_VSR_DATA 0x7c + +#define CONTROL_REGISTER 0x0 +#define MBUS_SIZE_CONTROL 0x4 + +#define POWER_DOWN_PHY0 BIT(6) +#define POWER_DOWN_PHY1 BIT(14) +#define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16) +#define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19) + +#define PHY_BASE 0x200 + +/* register 0x01 */ +#define REF_FREF_SEL_25 BIT(0) +#define PHY_MODE_SATA (0x0 << 5) + +/* register 0x02 */ +#define USE_MAX_PLL_RATE BIT(12) + +/* register 0x23 */ +#define DATA_BIT_WIDTH_10 (0x0 << 10) +#define DATA_BIT_WIDTH_20 (0x1 << 10) +#define DATA_BIT_WIDTH_40 (0x2 << 10) + +/* register 0x25 */ +#define PHY_GEN_MAX_1_5 (0x0 << 10) +#define PHY_GEN_MAX_3_0 (0x1 << 10) +#define PHY_GEN_MAX_6_0 (0x2 << 10) + +struct phy_berlin_desc { + struct phy *phy; + u32 power_bit; + unsigned index; +}; + +struct phy_berlin_priv { + void __iomem *base; + spinlock_t lock; + struct clk *clk; + struct phy_berlin_desc **phys; + unsigned nphys; +}; + +static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg, + u32 mask, u32 val) +{ + u32 regval; + + /* select register */ + writel(PHY_BASE + reg, ctrl_reg + PORT_VSR_ADDR); + + /* set bits */ + regval = readl(ctrl_reg + PORT_VSR_DATA); + regval &= ~mask; + regval |= val; + writel(regval, ctrl_reg + PORT_VSR_DATA); +} + +static int phy_berlin_sata_power_on(struct phy *phy) +{ + struct phy_berlin_desc *desc = phy_get_drvdata(phy); + struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent); + void __iomem *ctrl_reg = priv->base + 0x60 + (desc->index * 0x80); + int ret = 0; + u32 regval; + + clk_prepare_enable(priv->clk); + + spin_lock(&priv->lock); + + /* Power on PHY */ + writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR); + regval = readl(priv->base + HOST_VSA_DATA); + regval &= ~desc->power_bit; + writel(regval, priv->base + HOST_VSA_DATA); + + /* Configure MBus */ + writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR); + regval = readl(priv->base + HOST_VSA_DATA); + regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128; + writel(regval, priv->base + HOST_VSA_DATA); + + /* set PHY mode and ref freq to 25 MHz */ + phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff, + REF_FREF_SEL_25 | PHY_MODE_SATA); + + /* set PHY up to 6 Gbps */ + phy_berlin_sata_reg_setbits(ctrl_reg, 0x25, 0xc00, PHY_GEN_MAX_6_0); + + /* set 40 bits width */ + phy_berlin_sata_reg_setbits(ctrl_reg, 0x23, 0xc00, DATA_BIT_WIDTH_40); + + /* use max pll rate */ + phy_berlin_sata_reg_setbits(ctrl_reg, 0x2, 0x0, USE_MAX_PLL_RATE); + + /* set Gen3 controller speed */ + regval = readl(ctrl_reg + PORT_SCR_CTL); + regval &= ~GENMASK(7, 4); + regval |= 0x30; + writel(regval, ctrl_reg + PORT_SCR_CTL); + + spin_unlock(&priv->lock); + + clk_disable_unprepare(priv->clk); + + return ret; +} + +static int phy_berlin_sata_power_off(struct phy *phy) +{ + struct phy_berlin_desc *desc = phy_get_drvdata(phy); + struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent); + u32 regval; + + clk_prepare_enable(priv->clk); + + spin_lock(&priv->lock); + + /* Power down PHY */ + writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR); + regval = readl(priv->base + HOST_VSA_DATA); + regval |= desc->power_bit; + writel(regval, priv->base + HOST_VSA_DATA); + + spin_unlock(&priv->lock); + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static struct phy *phy_berlin_sata_phy_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct phy_berlin_priv *priv = dev_get_drvdata(dev); + int i; + + if (WARN_ON(args->args[0] >= priv->nphys)) + return ERR_PTR(-ENODEV); + + for (i = 0; i < priv->nphys; i++) { + if (priv->phys[i]->index == args->args[0]) + break; + } + + if (i == priv->nphys) + return ERR_PTR(-ENODEV); + + return priv->phys[i]->phy; +} + +static struct phy_ops phy_berlin_sata_ops = { + .power_on = phy_berlin_sata_power_on, + .power_off = phy_berlin_sata_power_off, + .owner = THIS_MODULE, +}; + +static u32 phy_berlin_power_down_bits[] = { + POWER_DOWN_PHY0, + POWER_DOWN_PHY1, +}; + +static int phy_berlin_sata_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *child; + struct phy *phy; + struct phy_provider *phy_provider; + struct phy_berlin_priv *priv; + struct resource *res; + int i = 0; + u32 phy_id; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + priv->base = devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->base) + return -ENOMEM; + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + priv->nphys = of_get_child_count(dev->of_node); + if (priv->nphys == 0) + return -ENODEV; + + priv->phys = devm_kzalloc(dev, priv->nphys * sizeof(*priv->phys), + GFP_KERNEL); + if (!priv->phys) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + spin_lock_init(&priv->lock); + + for_each_available_child_of_node(dev->of_node, child) { + struct phy_berlin_desc *phy_desc; + + if (of_property_read_u32(child, "reg", &phy_id)) { + dev_err(dev, "missing reg property in node %s\n", + child->name); + return -EINVAL; + } + + if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) { + dev_err(dev, "invalid reg in node %s\n", child->name); + return -EINVAL; + } + + phy_desc = devm_kzalloc(dev, sizeof(*phy_desc), GFP_KERNEL); + if (!phy_desc) + return -ENOMEM; + + phy = devm_phy_create(dev, &phy_berlin_sata_ops, NULL); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create PHY %d\n", phy_id); + return PTR_ERR(phy); + } + + phy_desc->phy = phy; + phy_desc->power_bit = phy_berlin_power_down_bits[phy_id]; + phy_desc->index = phy_id; + phy_set_drvdata(phy, phy_desc); + + priv->phys[i++] = phy_desc; + + /* Make sure the PHY is off */ + phy_berlin_sata_power_off(phy); + } + + phy_provider = + devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + return 0; +} + +static const struct of_device_id phy_berlin_sata_of_match[] = { + { .compatible = "marvell,berlin2q-sata-phy" }, + { }, +}; + +static struct platform_driver phy_berlin_sata_driver = { + .probe = phy_berlin_sata_probe, + .driver = { + .name = "phy-berlin-sata", + .owner = THIS_MODULE, + .of_match_table = phy_berlin_sata_of_match, + }, +}; +module_platform_driver(phy_berlin_sata_driver); + +MODULE_DESCRIPTION("Marvell Berlin SATA PHY driver"); +MODULE_AUTHOR("Antoine Ténart "); +MODULE_LICENSE("GPL v2"); From 6e58240fae556c23150bb0c7cb9fdba17e6c14cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Mon, 7 Jul 2014 12:16:08 +0200 Subject: [PATCH 186/211] Documentation: bindings: add the Berlin SATA PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Berlin SATA PHY drives the PHY related to the SATA interface. Add the corresponding documentation. Signed-off-by: Antoine Ténart Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/berlin-sata-phy.txt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/berlin-sata-phy.txt diff --git a/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt b/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt new file mode 100644 index 000000000000..88f8c23384c0 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt @@ -0,0 +1,34 @@ +Berlin SATA PHY +--------------- + +Required properties: +- compatible: should be "marvell,berlin2q-sata-phy" +- address-cells: should be 1 +- size-cells: should be 0 +- phy-cells: from the generic PHY bindings, must be 1 +- reg: address and length of the register +- clocks: reference to the clock entry + +Sub-nodes: +Each PHY should be represented as a sub-node. + +Sub-nodes required properties: +- reg: the PHY number + +Example: + sata_phy: phy@f7e900a0 { + compatible = "marvell,berlin2q-sata-phy"; + reg = <0xf7e900a0 0x200>; + clocks = <&chip CLKID_SATA>; + #address-cells = <1>; + #size-cells = <0>; + #phy-cells = <1>; + + sata-phy@0 { + reg = <0>; + }; + + sata-phy@1 { + reg = <1>; + }; + }; From 2a4c37016ca96e413cd352985d3a0db8cfb7716c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 14 Jul 2014 15:55:01 +0530 Subject: [PATCH 187/211] phy: core: Fix of_phy_provider_lookup to return PHY provider for sub node Fixed of_phy_provider_lookup to return 'phy_provider' if _of_phy_get passes the node pointer of the sub-node of phy provider node. This is needed when phy provider implements multiple PHYs and each PHY is modelled as the sub-node of PHY provider device node. Signed-off-by: Kishon Vijay Abraham I Acked-by: Lee Jones --- drivers/phy/phy-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 75c97396dbfa..527e744a3809 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -87,10 +87,15 @@ static struct phy *phy_lookup(struct device *device, const char *port) static struct phy_provider *of_phy_provider_lookup(struct device_node *node) { struct phy_provider *phy_provider; + struct device_node *child; list_for_each_entry(phy_provider, &phy_provider_list, list) { if (phy_provider->dev->of_node == node) return phy_provider; + + for_each_child_of_node(phy_provider->dev->of_node, child) + if (child == node) + return phy_provider; } return ERR_PTR(-EPROBE_DEFER); From f0ed817638b59aa927f1f7e9564dd8796b18dc4f Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 14 Jul 2014 15:55:02 +0530 Subject: [PATCH 188/211] phy: core: Let node ptr of PHY point to PHY and not of PHY provider In case of multi-phy PHY providers, each PHY should be modeled as a sub node of the PHY provider. Then each PHY will have a different node pointer (node pointer of sub node) than that of PHY provider. Added this provision in the PHY core. Also fixed all drivers to use the updated API. Signed-off-by: Kishon Vijay Abraham I Acked-by: Lee Jones --- Documentation/phy.txt | 10 ++++++---- drivers/phy/phy-bcm-kona-usb2.c | 2 +- drivers/phy/phy-berlin-sata.c | 2 +- drivers/phy/phy-core.c | 25 ++++++++++++++++++------- drivers/phy/phy-exynos-dp-video.c | 2 +- drivers/phy/phy-exynos-mipi-video.c | 2 +- drivers/phy/phy-exynos5-usbdrd.c | 3 ++- drivers/phy/phy-exynos5250-sata.c | 2 +- drivers/phy/phy-hix5hd2-sata.c | 2 +- drivers/phy/phy-mvebu-sata.c | 2 +- drivers/phy/phy-omap-usb2.c | 2 +- drivers/phy/phy-qcom-apq8064-sata.c | 3 ++- drivers/phy/phy-samsung-usb2.c | 3 ++- drivers/phy/phy-sun4i-usb.c | 2 +- drivers/phy/phy-ti-pipe3.c | 2 +- drivers/phy/phy-twl4030-usb.c | 2 +- drivers/phy/phy-xgene.c | 2 +- include/linux/phy/phy.h | 15 ++++++++++----- 18 files changed, 52 insertions(+), 31 deletions(-) diff --git a/Documentation/phy.txt b/Documentation/phy.txt index ebff6ee52441..c6594af94d25 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt @@ -53,10 +53,12 @@ unregister the PHY. The PHY driver should create the PHY in order for other peripheral controllers to make use of it. The PHY framework provides 2 APIs to create the PHY. -struct phy *phy_create(struct device *dev, const struct phy_ops *ops, - struct phy_init_data *init_data); -struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, - struct phy_init_data *init_data); +struct phy *phy_create(struct device *dev, struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data); +struct phy *devm_phy_create(struct device *dev, struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data); The PHY drivers can use one of the above 2 APIs to create the PHY by passing the device pointer, phy ops and init_data. diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c index e94f5a6a5645..894fe74c1e44 100644 --- a/drivers/phy/phy-bcm-kona-usb2.c +++ b/drivers/phy/phy-bcm-kona-usb2.c @@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); - gphy = devm_phy_create(dev, &ops, NULL); + gphy = devm_phy_create(dev, NULL, &ops, NULL); if (IS_ERR(gphy)) return PTR_ERR(gphy); diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index c5e688b0899f..5c3a0424aeb4 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -239,7 +239,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) if (!phy_desc) return -ENOMEM; - phy = devm_phy_create(dev, &phy_berlin_sata_ops, NULL); + phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops, NULL); if (IS_ERR(phy)) { dev_err(dev, "failed to create PHY %d\n", phy_id); return PTR_ERR(phy); diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 527e744a3809..ff5eec5af817 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -415,13 +415,20 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args struct phy *phy; struct class_dev_iter iter; struct device_node *node = dev->of_node; + struct device_node *child; class_dev_iter_init(&iter, phy_class, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) { phy = to_phy(dev); - if (node != phy->dev.of_node) + if (node != phy->dev.of_node) { + for_each_child_of_node(node, child) { + if (child == phy->dev.of_node) + goto phy_found; + } continue; + } +phy_found: class_dev_iter_exit(&iter); return phy; } @@ -579,13 +586,15 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get); /** * phy_create() - create a new phy * @dev: device that is creating the new phy + * @node: device node of the phy * @ops: function pointers for performing phy operations * @init_data: contains the list of PHY consumers or NULL * * Called to create a phy using phy framework. */ -struct phy *phy_create(struct device *dev, const struct phy_ops *ops, - struct phy_init_data *init_data) +struct phy *phy_create(struct device *dev, struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data) { int ret; int id; @@ -620,7 +629,7 @@ struct phy *phy_create(struct device *dev, const struct phy_ops *ops, phy->dev.class = phy_class; phy->dev.parent = dev; - phy->dev.of_node = dev->of_node; + phy->dev.of_node = node ?: dev->of_node; phy->id = id; phy->ops = ops; phy->init_data = init_data; @@ -656,6 +665,7 @@ EXPORT_SYMBOL_GPL(phy_create); /** * devm_phy_create() - create a new phy * @dev: device that is creating the new phy + * @node: device node of the phy * @ops: function pointers for performing phy operations * @init_data: contains the list of PHY consumers or NULL * @@ -664,8 +674,9 @@ EXPORT_SYMBOL_GPL(phy_create); * On driver detach, release function is invoked on the devres data, * then, devres data is freed. */ -struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, - struct phy_init_data *init_data) +struct phy *devm_phy_create(struct device *dev, struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data) { struct phy **ptr, *phy; @@ -673,7 +684,7 @@ struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, if (!ptr) return ERR_PTR(-ENOMEM); - phy = phy_create(dev, ops, init_data); + phy = phy_create(dev, node, ops, init_data); if (!IS_ERR(phy)) { *ptr = phy; devres_add(dev, ptr); diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 098f822a2fa4..8b3026e2af7f 100644 --- a/drivers/phy/phy-exynos-dp-video.c +++ b/drivers/phy/phy-exynos-dp-video.c @@ -77,7 +77,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev) if (IS_ERR(state->regs)) return PTR_ERR(state->regs); - phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL); + phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops, NULL); if (IS_ERR(phy)) { dev_err(dev, "failed to create Display Port PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 6d6bcf52a10e..b55a92e12496 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -136,7 +136,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) spin_lock_init(&state->slock); for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { - struct phy *phy = devm_phy_create(dev, + struct phy *phy = devm_phy_create(dev, NULL, &exynos_mipi_video_phy_ops, NULL); if (IS_ERR(phy)) { dev_err(dev, "failed to create PHY %d\n", i); diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index 205159db37a3..b05302b09c9f 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -635,7 +635,8 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) dev_vdbg(dev, "Creating usbdrd_phy phy\n"); for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { - struct phy *phy = devm_phy_create(dev, &exynos5_usbdrd_phy_ops, + struct phy *phy = devm_phy_create(dev, NULL, + &exynos5_usbdrd_phy_ops, NULL); if (IS_ERR(phy)) { dev_err(dev, "Failed to create usbdrd_phy phy\n"); diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c index 05689450f93b..19a679aca4ac 100644 --- a/drivers/phy/phy-exynos5250-sata.c +++ b/drivers/phy/phy-exynos5250-sata.c @@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev) return ret; } - sata_phy->phy = devm_phy_create(dev, &exynos_sata_phy_ops, NULL); + sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops, NULL); if (IS_ERR(sata_phy->phy)) { clk_disable_unprepare(sata_phy->phyclk); dev_err(dev, "failed to create PHY\n"); diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c index d44283453d71..6a08fa5f81eb 100644 --- a/drivers/phy/phy-hix5hd2-sata.c +++ b/drivers/phy/phy-hix5hd2-sata.c @@ -156,7 +156,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev) if (IS_ERR(priv->peri_ctrl)) priv->peri_ctrl = NULL; - phy = devm_phy_create(dev, &hix5hd2_sata_phy_ops, NULL); + phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops, NULL); if (IS_ERR(phy)) { dev_err(dev, "failed to create PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c index d70ecd6a1b3f..cc3c0e166daf 100644 --- a/drivers/phy/phy-mvebu-sata.c +++ b/drivers/phy/phy-mvebu-sata.c @@ -99,7 +99,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev) if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); - phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL); + phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops, NULL); if (IS_ERR(phy)) return PTR_ERR(phy); diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index 34b396146c8a..93d78359246c 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -263,7 +263,7 @@ static int omap_usb2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); - generic_phy = devm_phy_create(phy->dev, &ops, NULL); + generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); if (IS_ERR(generic_phy)) return PTR_ERR(generic_phy); diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c index c9b4dd6becf5..d7c01aa1f8d7 100644 --- a/drivers/phy/phy-qcom-apq8064-sata.c +++ b/drivers/phy/phy-qcom-apq8064-sata.c @@ -228,7 +228,8 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev) if (IS_ERR(phy->mmio)) return PTR_ERR(phy->mmio); - generic_phy = devm_phy_create(dev, &qcom_apq8064_sata_phy_ops, NULL); + generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops, + NULL); if (IS_ERR(generic_phy)) { dev_err(dev, "%s: failed to create phy\n", __func__); return PTR_ERR(generic_phy); diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c index 16aae7a285f0..ae30640a411d 100644 --- a/drivers/phy/phy-samsung-usb2.c +++ b/drivers/phy/phy-samsung-usb2.c @@ -196,7 +196,8 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev) struct samsung_usb2_phy_instance *p = &drv->instances[i]; dev_dbg(dev, "Creating phy \"%s\"\n", label); - p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL); + p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops, + NULL); if (IS_ERR(p->phy)) { dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n", label); diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 7a4ea552f621..61ebea49709b 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -295,7 +295,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(phy->pmu); } - phy->phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL); + phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops, NULL); if (IS_ERR(phy->phy)) { dev_err(dev, "failed to create PHY %d\n", i); return PTR_ERR(phy->phy); diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 93bcd67f1b22..b964aa967b46 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -400,7 +400,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); pm_runtime_enable(phy->dev); - generic_phy = devm_phy_create(phy->dev, &ops, NULL); + generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); if (IS_ERR(generic_phy)) return PTR_ERR(generic_phy); diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 2e0e9b3774c8..e1a6623d4696 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -695,7 +695,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) otg->set_host = twl4030_set_host; otg->set_peripheral = twl4030_set_peripheral; - phy = devm_phy_create(twl->dev, &ops, init_data); + phy = devm_phy_create(twl->dev, NULL, &ops, init_data); if (IS_ERR(phy)) { dev_dbg(&pdev->dev, "Failed to create PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index 4aa1ccd1511f..db809b97219e 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev) ctx->dev = &pdev->dev; platform_set_drvdata(pdev, ctx); - ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops, NULL); + ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops, NULL); if (IS_ERR(ctx->phy)) { dev_dbg(&pdev->dev, "Failed to create PHY\n"); rc = PTR_ERR(ctx->phy); diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 9a8694524742..8cb6f815475b 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -158,9 +158,10 @@ void devm_phy_put(struct device *dev, struct phy *phy); struct phy *of_phy_get(struct device_node *np, const char *con_id); struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args *args); -struct phy *phy_create(struct device *dev, const struct phy_ops *ops, - struct phy_init_data *init_data); -struct phy *devm_phy_create(struct device *dev, +struct phy *phy_create(struct device *dev, struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data); +struct phy *devm_phy_create(struct device *dev, struct device_node *node, const struct phy_ops *ops, struct phy_init_data *init_data); void phy_destroy(struct phy *phy); void devm_phy_destroy(struct device *dev, struct phy *phy); @@ -299,13 +300,17 @@ static inline struct phy *of_phy_simple_xlate(struct device *dev, } static inline struct phy *phy_create(struct device *dev, - const struct phy_ops *ops, struct phy_init_data *init_data) + struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data) { return ERR_PTR(-ENOSYS); } static inline struct phy *devm_phy_create(struct device *dev, - const struct phy_ops *ops, struct phy_init_data *init_data) + struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data) { return ERR_PTR(-ENOSYS); } From 175f02ebdfdf8431dbf607c04fe5caf667ba8e6c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 16 Jul 2014 09:18:43 +0100 Subject: [PATCH 189/211] phy: qcom-apq8064: fix possible timeout without check This patch fixes a possible timeout in poll loop without actually checking the register before return. In theory the there is a possibility of loop being scheduled after a long lock/delay, which would then force the loop to exit without actually checking the register. Reported-by: Bartlomiej Zolnierkiewicz Signed-off-by: Srinivas Kandagatla Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-qcom-apq8064-sata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c index d7c01aa1f8d7..b3ef7d805765 100644 --- a/drivers/phy/phy-qcom-apq8064-sata.c +++ b/drivers/phy/phy-qcom-apq8064-sata.c @@ -91,7 +91,7 @@ static int read_poll_timeout(void __iomem *addr, u32 mask) usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); } while (!time_after(jiffies, timeout)); - return -ETIMEDOUT; + return (readl_relaxed(addr) & mask) ? 0 : -ETIMEDOUT; } static int qcom_apq8064_sata_phy_init(struct phy *generic_phy) From 4f6160d4089ec0e39e33a197138413bd0701ce21 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 16 Jul 2014 11:10:08 -0500 Subject: [PATCH 190/211] phy: qcom: Add driver for QCOM IPQ806x SATA PHY Add a PHY driver for uses with AHCI based SATA controller driver on the IPQ806x family of SoCs. Signed-off-by: Kumar Gala Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-qcom-ipq806x-sata.c | 211 ++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 drivers/phy/phy-qcom-ipq806x-sata.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 1704fd4be99e..3e251aa64ffd 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -191,4 +191,11 @@ config PHY_QCOM_APQ8064_SATA depends on OF select GENERIC_PHY +config PHY_QCOM_IPQ806X_SATA + tristate "Qualcomm IPQ806x SATA SerDes/PHY driver" + depends on ARCH_QCOM + depends on HAS_IOMEM + depends on OF + select GENERIC_PHY + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 3c2ad5915be2..54ab9785932c 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -23,3 +23,4 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o +obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o diff --git a/drivers/phy/phy-qcom-ipq806x-sata.c b/drivers/phy/phy-qcom-ipq806x-sata.c new file mode 100644 index 000000000000..909b5a87fc6a --- /dev/null +++ b/drivers/phy/phy-qcom-ipq806x-sata.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct qcom_ipq806x_sata_phy { + void __iomem *mmio; + struct clk *cfg_clk; + struct device *dev; +}; + +#define __set(v, a, b) (((v) << (b)) & GENMASK(a, b)) + +#define SATA_PHY_P0_PARAM0 0x200 +#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(x) __set(x, 17, 12) +#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK GENMASK(17, 12) +#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2(x) __set(x, 11, 6) +#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK GENMASK(11, 6) +#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1(x) __set(x, 5, 0) +#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK GENMASK(5, 0) + +#define SATA_PHY_P0_PARAM1 0x204 +#define SATA_PHY_P0_PARAM1_RESERVED_BITS31_21(x) __set(x, 31, 21) +#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(x) __set(x, 20, 14) +#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK GENMASK(20, 14) +#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(x) __set(x, 13, 7) +#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK GENMASK(13, 7) +#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(x) __set(x, 6, 0) +#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK GENMASK(6, 0) + +#define SATA_PHY_P0_PARAM2 0x208 +#define SATA_PHY_P0_PARAM2_RX_EQ(x) __set(x, 20, 18) +#define SATA_PHY_P0_PARAM2_RX_EQ_MASK GENMASK(20, 18) + +#define SATA_PHY_P0_PARAM3 0x20C +#define SATA_PHY_SSC_EN 0x8 +#define SATA_PHY_P0_PARAM4 0x210 +#define SATA_PHY_REF_SSP_EN 0x2 +#define SATA_PHY_RESET 0x1 + +static int qcom_ipq806x_sata_phy_init(struct phy *generic_phy) +{ + struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy); + u32 reg; + + /* Setting SSC_EN to 1 */ + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM3); + reg = reg | SATA_PHY_SSC_EN; + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM3); + + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM0) & + ~(SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK | + SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK | + SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK); + reg |= SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(0xf); + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM0); + + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM1) & + ~(SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK | + SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK | + SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK); + reg |= SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(0x55) | + SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(0x55) | + SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(0x55); + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM1); + + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM2) & + ~SATA_PHY_P0_PARAM2_RX_EQ_MASK; + reg |= SATA_PHY_P0_PARAM2_RX_EQ(0x3); + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM2); + + /* Setting PHY_RESET to 1 */ + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); + reg = reg | SATA_PHY_RESET; + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); + + /* Setting REF_SSP_EN to 1 */ + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); + reg = reg | SATA_PHY_REF_SSP_EN | SATA_PHY_RESET; + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); + + /* make sure all changes complete before we let the PHY out of reset */ + mb(); + + /* sleep for max. 50us more to combine processor wakeups */ + usleep_range(20, 20 + 50); + + /* Clearing PHY_RESET to 0 */ + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); + reg = reg & ~SATA_PHY_RESET; + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); + + return 0; +} + +static int qcom_ipq806x_sata_phy_exit(struct phy *generic_phy) +{ + struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy); + u32 reg; + + /* Setting PHY_RESET to 1 */ + reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); + reg = reg | SATA_PHY_RESET; + writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); + + return 0; +} + +static struct phy_ops qcom_ipq806x_sata_phy_ops = { + .init = qcom_ipq806x_sata_phy_init, + .exit = qcom_ipq806x_sata_phy_exit, + .owner = THIS_MODULE, +}; + +static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev) +{ + struct qcom_ipq806x_sata_phy *phy; + struct device *dev = &pdev->dev; + struct resource *res; + struct phy_provider *phy_provider; + struct phy *generic_phy; + int ret; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(phy->mmio)) + return PTR_ERR(phy->mmio); + + generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops, + NULL); + if (IS_ERR(generic_phy)) { + dev_err(dev, "%s: failed to create phy\n", __func__); + return PTR_ERR(generic_phy); + } + + phy->dev = dev; + phy_set_drvdata(generic_phy, phy); + platform_set_drvdata(pdev, phy); + + phy->cfg_clk = devm_clk_get(dev, "cfg"); + if (IS_ERR(phy->cfg_clk)) { + dev_err(dev, "Failed to get sata cfg clock\n"); + return PTR_ERR(phy->cfg_clk); + } + + ret = clk_prepare_enable(phy->cfg_clk); + if (ret) + return ret; + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + clk_disable_unprepare(phy->cfg_clk); + dev_err(dev, "%s: failed to register phy\n", __func__); + return PTR_ERR(phy_provider); + } + + return 0; +} + +static int qcom_ipq806x_sata_phy_remove(struct platform_device *pdev) +{ + struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev); + + clk_disable_unprepare(phy->cfg_clk); + + return 0; +} + +static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { + { .compatible = "qcom,ipq806x-sata-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match); + +static struct platform_driver qcom_ipq806x_sata_phy_driver = { + .probe = qcom_ipq806x_sata_phy_probe, + .remove = qcom_ipq806x_sata_phy_remove, + .driver = { + .name = "qcom-ipq806x-sata-phy", + .owner = THIS_MODULE, + .of_match_table = qcom_ipq806x_sata_phy_of_match, + } +}; +module_platform_driver(qcom_ipq806x_sata_phy_driver); + +MODULE_DESCRIPTION("QCOM IPQ806x SATA PHY driver"); +MODULE_LICENSE("GPL v2"); From c4aee1aacb4798d23f514ab4eb59acef752d2397 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 16 Jul 2014 11:10:09 -0500 Subject: [PATCH 191/211] phy: qcom: Add device tree bindings for IPQ806x SATA PHY Add binding spec for Qualcomm SoC PHYs, starting with the SATA PHY on the IPQ806x family of SoCs. Signed-off-by: Kumar Gala Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/qcom-ipq806x-sata-phy.txt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/qcom-ipq806x-sata-phy.txt diff --git a/Documentation/devicetree/bindings/phy/qcom-ipq806x-sata-phy.txt b/Documentation/devicetree/bindings/phy/qcom-ipq806x-sata-phy.txt new file mode 100644 index 000000000000..76bfbd056202 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom-ipq806x-sata-phy.txt @@ -0,0 +1,23 @@ +Qualcomm IPQ806x SATA PHY Controller +------------------------------------ + +SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers. +Each SATA PHY controller should have its own node. + +Required properties: +- compatible: compatible list, contains "qcom,ipq806x-sata-phy" +- reg: offset and length of the SATA PHY register set; +- #phy-cells: must be zero +- clocks: must be exactly one entry +- clock-names: must be "cfg" + +Example: + sata_phy: sata-phy@1b400000 { + compatible = "qcom,ipq806x-sata-phy"; + reg = <0x1b400000 0x200>; + + clocks = <&gcc SATA_PHY_CFG_CLK>; + clock-names = "cfg"; + + #phy-cells = <0>; + }; From f5c9f3be608017577731ebe8be37e55f800586d3 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 10 Jul 2014 10:09:31 +0100 Subject: [PATCH 192/211] phy: miphy365x: Add Device Tree bindings for the MiPHY365x The MiPHY365x is a Generic PHY which can serve various SATA or PCIe devices. It has 2 ports which it can use for either; both SATA, both PCIe or one of each in any configuration. Acked-by: Mark Rutland Acked-by: Alexandre Torgue Signed-off-by: Lee Jones Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/phy-miphy365x.txt | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-miphy365x.txt diff --git a/Documentation/devicetree/bindings/phy/phy-miphy365x.txt b/Documentation/devicetree/bindings/phy/phy-miphy365x.txt new file mode 100644 index 000000000000..42c880886cf7 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-miphy365x.txt @@ -0,0 +1,76 @@ +STMicroelectronics STi MIPHY365x PHY binding +============================================ + +This binding describes a miphy device that is used to control PHY hardware +for SATA and PCIe. + +Required properties (controller (parent) node): +- compatible : Should be "st,miphy365x-phy" +- st,syscfg : Should be a phandle of the system configuration register group + which contain the SATA, PCIe mode setting bits + +Required nodes : A sub-node is required for each channel the controller + provides. Address range information including the usual + 'reg' and 'reg-names' properties are used inside these + nodes to describe the controller's topology. These nodes + are translated by the driver's .xlate() function. + +Required properties (port (child) node): +- #phy-cells : Should be 1 (See second example) + Cell after port phandle is device type from: + - MIPHY_TYPE_SATA + - MIPHY_TYPE_PCI +- reg : Address and length of register sets for each device in + "reg-names" +- reg-names : The names of the register addresses corresponding to the + registers filled in "reg": + - sata: For SATA devices + - pcie: For PCIe devices + - syscfg: To specify the syscfg based config register + +Optional properties (port (child) node): +- st,sata-gen : Generation of locally attached SATA IP. Expected values + are {1,2,3). If not supplied generation 1 hardware will + be expected +- st,pcie-tx-pol-inv : Bool property to invert the polarity PCIe Tx (Txn/Txp) +- st,sata-tx-pol-inv : Bool property to invert the polarity SATA Tx (Txn/Txp) + +Example: + + miphy365x_phy: miphy365x@fe382000 { + compatible = "st,miphy365x-phy"; + st,syscfg = <&syscfg_rear>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + phy_port0: port@fe382000 { + reg = <0xfe382000 0x100>, <0xfe394000 0x100>, <0x824 0x4>; + reg-names = "sata", "pcie", "syscfg"; + #phy-cells = <1>; + st,sata-gen = <3>; + }; + + phy_port1: port@fe38a000 { + reg = <0xfe38a000 0x100>, <0xfe804000 0x100>, <0x828 0x4>;; + reg-names = "sata", "pcie", "syscfg"; + #phy-cells = <1>; + st,pcie-tx-pol-inv; + }; + }; + +Specifying phy control of devices +================================= + +Device nodes should specify the configuration required in their "phys" +property, containing a phandle to the phy port node and a device type. + +Example: + +#include + + sata0: sata@fe380000 { + ... + phys = <&phy_port0 MIPHY_TYPE_SATA>; + ... + }; From 6e877fedb1cff0f4a0988d30418ad87abaefafcb Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 9 Jul 2014 12:41:12 +0100 Subject: [PATCH 193/211] phy: miphy365x: Provide support for the MiPHY356x Generic PHY The MiPHY365x is a Generic PHY which can serve various SATA or PCIe devices. It has 2 ports which it can use for either; both SATA, both PCIe or one of each in any configuration. Acked-by: Mark Rutland Signed-off-by: Alexandre Torgue Signed-off-by: Lee Jones Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 10 + drivers/phy/Makefile | 1 + drivers/phy/phy-miphy365x.c | 616 ++++++++++++++++++++++++++++++++++++ 3 files changed, 627 insertions(+) create mode 100644 drivers/phy/phy-miphy365x.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 3e251aa64ffd..cc97c897945a 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -38,6 +38,16 @@ config PHY_MVEBU_SATA depends on OF select GENERIC_PHY +config PHY_MIPHY365X + tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series" + depends on ARCH_STI + depends on GENERIC_PHY + depends on HAS_IOMEM + depends on OF + help + Enable this to support the miphy transceiver (for SATA/PCIE) + that is part of STMicroelectronics STiH41x SoC series. + config OMAP_CONTROL_PHY tristate "OMAP CONTROL PHY Driver" depends on ARCH_OMAP2PLUS || COMPILE_TEST diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 54ab9785932c..971ad0aac388 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o +obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c new file mode 100644 index 000000000000..65ecd04da9bc --- /dev/null +++ b/drivers/phy/phy-miphy365x.c @@ -0,0 +1,616 @@ +/* + * Copyright (C) 2014 STMicroelectronics – All Rights Reserved + * + * STMicroelectronics PHY driver MiPHY365 (for SoC STiH416). + * + * Authors: Alexandre Torgue + * Lee Jones + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define HFC_TIMEOUT 100 + +#define SYSCFG_2521 0x824 +#define SYSCFG_2522 0x828 +#define SYSCFG_PCIE_SATA_MASK BIT(1) +#define SYSCFG_PCIE_SATA_POS 1 + +/* MiPHY365x register definitions */ +#define RESET_REG 0x00 +#define RST_PLL BIT(1) +#define RST_PLL_CAL BIT(2) +#define RST_RX BIT(4) +#define RST_MACRO BIT(7) + +#define STATUS_REG 0x01 +#define IDLL_RDY BIT(0) +#define PLL_RDY BIT(1) +#define DES_BIT_LOCK BIT(2) +#define DES_SYMBOL_LOCK BIT(3) + +#define CTRL_REG 0x02 +#define TERM_EN BIT(0) +#define PCI_EN BIT(2) +#define DES_BIT_LOCK_EN BIT(3) +#define TX_POL BIT(5) + +#define INT_CTRL_REG 0x03 + +#define BOUNDARY1_REG 0x10 +#define SPDSEL_SEL BIT(0) + +#define BOUNDARY3_REG 0x12 +#define TX_SPDSEL_GEN1_VAL 0 +#define TX_SPDSEL_GEN2_VAL 0x01 +#define TX_SPDSEL_GEN3_VAL 0x02 +#define RX_SPDSEL_GEN1_VAL 0 +#define RX_SPDSEL_GEN2_VAL (0x01 << 3) +#define RX_SPDSEL_GEN3_VAL (0x02 << 3) + +#define PCIE_REG 0x16 + +#define BUF_SEL_REG 0x20 +#define CONF_GEN_SEL_GEN3 0x02 +#define CONF_GEN_SEL_GEN2 0x01 +#define PD_VDDTFILTER BIT(4) + +#define TXBUF1_REG 0x21 +#define SWING_VAL 0x04 +#define SWING_VAL_GEN1 0x03 +#define PREEMPH_VAL (0x3 << 5) + +#define TXBUF2_REG 0x22 +#define TXSLEW_VAL 0x2 +#define TXSLEW_VAL_GEN1 0x4 + +#define RXBUF_OFFSET_CTRL_REG 0x23 + +#define RXBUF_REG 0x25 +#define SDTHRES_VAL 0x01 +#define EQ_ON3 (0x03 << 4) +#define EQ_ON1 (0x01 << 4) + +#define COMP_CTRL1_REG 0x40 +#define START_COMSR BIT(0) +#define START_COMZC BIT(1) +#define COMSR_DONE BIT(2) +#define COMZC_DONE BIT(3) +#define COMP_AUTO_LOAD BIT(4) + +#define COMP_CTRL2_REG 0x41 +#define COMP_2MHZ_RAT_GEN1 0x1e +#define COMP_2MHZ_RAT 0xf + +#define COMP_CTRL3_REG 0x42 +#define COMSR_COMP_REF 0x33 + +#define COMP_IDLL_REG 0x47 +#define COMZC_IDLL 0x2a + +#define PLL_CTRL1_REG 0x50 +#define PLL_START_CAL BIT(0) +#define BUF_EN BIT(2) +#define SYNCHRO_TX BIT(3) +#define SSC_EN BIT(6) +#define CONFIG_PLL BIT(7) + +#define PLL_CTRL2_REG 0x51 +#define BYPASS_PLL_CAL BIT(1) + +#define PLL_RAT_REG 0x52 + +#define PLL_SSC_STEP_MSB_REG 0x56 +#define PLL_SSC_STEP_MSB_VAL 0x03 + +#define PLL_SSC_STEP_LSB_REG 0x57 +#define PLL_SSC_STEP_LSB_VAL 0x63 + +#define PLL_SSC_PER_MSB_REG 0x58 +#define PLL_SSC_PER_MSB_VAL 0 + +#define PLL_SSC_PER_LSB_REG 0x59 +#define PLL_SSC_PER_LSB_VAL 0xf1 + +#define IDLL_TEST_REG 0x72 +#define START_CLK_HF BIT(6) + +#define DES_BITLOCK_REG 0x86 +#define BIT_LOCK_LEVEL 0x01 +#define BIT_LOCK_CNT_512 (0x03 << 5) + +static u8 ports[] = { MIPHY_PORT_0, MIPHY_PORT_1 }; + +struct miphy365x_phy { + struct phy *phy; + void __iomem *base; + void __iomem *sata; + void __iomem *pcie; + u8 type; + u8 port; +}; + +struct miphy365x_dev { + struct device *dev; + struct regmap *regmap; + struct mutex miphy_mutex; + struct miphy365x phys[ARRAY_SIZE(ports)]; + bool pcie_tx_pol_inv; + bool sata_tx_pol_inv; + u32 sata_gen; +}; + +/* + * These values are represented in Device tree. They are considered to be ABI + * and although they can be extended any existing values must not change. + */ +enum miphy_sata_gen { + SATA_GEN1 = 1, + SATA_GEN2, + SATA_GEN3 +}; + +static u8 rx_tx_spd[] = { + TX_SPDSEL_GEN1_VAL | RX_SPDSEL_GEN1_VAL, + TX_SPDSEL_GEN2_VAL | RX_SPDSEL_GEN2_VAL, + TX_SPDSEL_GEN3_VAL | RX_SPDSEL_GEN3_VAL +}; + +/* + * This function selects the system configuration, + * either two SATA, one SATA and one PCIe, or two PCIe lanes. + */ +static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, + struct miphy365x_dev *miphy_dev) +{ + u8 config = miphy_phy->type | miphy_phy->port; + u32 mask = SYSCFG_PCIE_SATA_MASK; + u32 reg; + bool sata; + + switch (config) { + case MIPHY_SATA_PORT0: + reg = SYSCFG_2521; + sata = true; + break; + case MIPHY_PCIE_PORT1: + reg = SYSCFG_2522; + sata = false; + break; + default: + dev_err(miphy_dev->dev, "Configuration not supported\n"); + return -EINVAL; + } + + return regmap_update_bits(miphy_dev->regmap, reg, mask, + sata << SYSCFG_PCIE_SATA_POS); +} + +static int miphy365x_init_pcie_port(struct miphy365x_phy *miphy_phy, + struct miphy365x_dev *miphy_dev) +{ + u8 val; + + if (miphy_phy->pcie_tx_pol_inv) { + /* Invert Tx polarity and clear pci_txdetect_pol bit */ + val = TERM_EN | PCI_EN | DES_BIT_LOCK_EN | TX_POL; + writeb_relaxed(val, miphy_phy->base + CTRL_REG); + writeb_relaxed(0x00, miphy_phy->base + PCIE_REG); + } + + return 0; +} + +static inline int miphy365x_hfc_not_rdy(struct miphy365x_phy *miphy_phy, + struct miphy365x_dev *miphy_dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT); + u8 mask = IDLL_RDY | PLL_RDY; + u8 regval; + + do { + regval = readb_relaxed(miphy_phy->base + STATUS_REG); + if (!(regval & mask)) + return 0; + + usleep_range(2000, 2500); + } while (time_before(jiffies, timeout)); + + dev_err(miphy_dev->dev, "HFC ready timeout!\n"); + return -EBUSY; +} + +static inline int miphy365x_rdy(struct miphy365x_phy *miphy_phy, + struct miphy365x_dev *miphy_dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT); + u8 mask = IDLL_RDY | PLL_RDY; + u8 regval; + + do { + regval = readb_relaxed(miphy_phy->base + STATUS_REG); + if ((regval & mask) == mask) + return 0; + + usleep_range(2000, 2500); + } while (time_before(jiffies, timeout)); + + dev_err(miphy_dev->dev, "PHY not ready timeout!\n"); + return -EBUSY; +} + +static inline void miphy365x_set_comp(struct miphy365x_phy *miphy_phy, + struct miphy365x_dev *miphy_dev) +{ + u8 val, mask; + + if (miphy_dev->sata_gen == SATA_GEN1) + writeb_relaxed(COMP_2MHZ_RAT_GEN1, + miphy_phy->base + COMP_CTRL2_REG); + else + writeb_relaxed(COMP_2MHZ_RAT, + miphy_phy->base + COMP_CTRL2_REG); + + if (miphy_dev->sata_gen != SATA_GEN3) { + writeb_relaxed(COMSR_COMP_REF, + miphy_phy->base + COMP_CTRL3_REG); + /* + * Force VCO current to value defined by address 0x5A + * and disable PCIe100Mref bit + * Enable auto load compensation for pll_i_bias + */ + writeb_relaxed(BYPASS_PLL_CAL, miphy_phy->base + PLL_CTRL2_REG); + writeb_relaxed(COMZC_IDLL, miphy_phy->base + COMP_IDLL_REG); + } + + /* + * Force restart compensation and enable auto load + * for Comzc_Tx, Comzc_Rx and Comsr on macro + */ + val = START_COMSR | START_COMZC | COMP_AUTO_LOAD; + writeb_relaxed(val, miphy_phy->base + COMP_CTRL1_REG); + + mask = COMSR_DONE | COMZC_DONE; + while ((readb_relaxed(miphy_phy->base + COMP_CTRL1_REG) & mask) != mask) + cpu_relax(); +} + +static inline void miphy365x_set_ssc(struct miphy365x_phy *miphy_phy, + struct miphy365x_dev *miphy_dev) +{ + u8 val; + + /* + * SSC Settings. SSC will be enabled through Link + * SSC Ampl. = 0.4% + * SSC Freq = 31KHz + */ + writeb_relaxed(PLL_SSC_STEP_MSB_VAL, + miphy_phy->base + PLL_SSC_STEP_MSB_REG); + writeb_relaxed(PLL_SSC_STEP_LSB_VAL, + miphy_phy->base + PLL_SSC_STEP_LSB_REG); + writeb_relaxed(PLL_SSC_PER_MSB_VAL, + miphy_phy->base + PLL_SSC_PER_MSB_REG); + writeb_relaxed(PLL_SSC_PER_LSB_VAL, + miphy_phy->base + PLL_SSC_PER_LSB_REG); + + /* SSC Settings complete */ + if (miphy_dev->sata_gen == SATA_GEN1) { + val = PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL; + writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG); + } else { + val = SSC_EN | PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL; + writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG); + } +} + +static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy, + struct miphy365x_dev *miphy_dev) +{ + int ret; + u8 val; + + /* + * Force PHY macro reset, PLL calibration reset, PLL reset + * and assert Deserializer Reset + */ + val = RST_PLL | RST_PLL_CAL | RST_RX | RST_MACRO; + writeb_relaxed(val, miphy_phy->base + RESET_REG); + + if (miphy_dev->sata_tx_pol_inv) + writeb_relaxed(TX_POL, miphy_phy->base + CTRL_REG); + + /* + * Force macro1 to use rx_lspd, tx_lspd + * Force Rx_Clock on first I-DLL phase + * Force Des in HP mode on macro, rx_lspd, tx_lspd for Gen2/3 + */ + writeb_relaxed(SPDSEL_SEL, miphy_phy->base + BOUNDARY1_REG); + writeb_relaxed(START_CLK_HF, miphy_phy->base + IDLL_TEST_REG); + val = rx_tx_spd[miphy_dev->sata_gen]; + writeb_relaxed(val, miphy_phy->base + BOUNDARY3_REG); + + /* Wait for HFC_READY = 0 */ + ret = miphy365x_hfc_not_rdy(miphy_phy, miphy_dev); + if (ret) + return ret; + + /* Compensation Recalibration */ + miphy365x_set_comp(miphy_phy, miphy_dev); + + switch (miphy_dev->sata_gen) { + case SATA_GEN3: + /* + * TX Swing target 550-600mv peak to peak diff + * Tx Slew target 90-110ps rising/falling time + * Rx Eq ON3, Sigdet threshold SDTH1 + */ + val = PD_VDDTFILTER | CONF_GEN_SEL_GEN3; + writeb_relaxed(val, miphy_phy->base + BUF_SEL_REG); + val = SWING_VAL | PREEMPH_VAL; + writeb_relaxed(val, miphy_phy->base + TXBUF1_REG); + writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG); + writeb_relaxed(0x00, miphy_phy->base + RXBUF_OFFSET_CTRL_REG); + val = SDTHRES_VAL | EQ_ON3; + writeb_relaxed(val, miphy_phy->base + RXBUF_REG); + break; + case SATA_GEN2: + /* + * conf gen sel=0x1 to program Gen2 banked registers + * VDDT filter ON + * Tx Swing target 550-600mV peak-to-peak diff + * Tx Slew target 90-110 ps rising/falling time + * RX Equalization ON1, Sigdet threshold SDTH1 + */ + writeb_relaxed(CONF_GEN_SEL_GEN2, + miphy_phy->base + BUF_SEL_REG); + writeb_relaxed(SWING_VAL, miphy_phy->base + TXBUF1_REG); + writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG); + val = SDTHRES_VAL | EQ_ON1; + writeb_relaxed(val, miphy_phy->base + RXBUF_REG); + break; + case SATA_GEN1: + /* + * conf gen sel = 00b to program Gen1 banked registers + * VDDT filter ON + * Tx Swing target 500-550mV peak-to-peak diff + * Tx Slew target120-140 ps rising/falling time + */ + writeb_relaxed(PD_VDDTFILTER, miphy_phy->base + BUF_SEL_REG); + writeb_relaxed(SWING_VAL_GEN1, miphy_phy->base + TXBUF1_REG); + writeb_relaxed(TXSLEW_VAL_GEN1, miphy_phy->base + TXBUF2_REG); + break; + default: + break; + } + + /* Force Macro1 in partial mode & release pll cal reset */ + writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG); + usleep_range(100, 150); + + miphy365x_set_ssc(miphy_phy, miphy_dev); + + /* Wait for phy_ready */ + ret = miphy365x_rdy(miphy_phy, miphy_dev); + if (ret) + return ret; + + /* + * Enable macro1 to use rx_lspd & tx_lspd + * Release Rx_Clock on first I-DLL phase on macro1 + * Assert deserializer reset + * des_bit_lock_en is set + * bit lock detection strength + * Deassert deserializer reset + */ + writeb_relaxed(0x00, miphy_phy->base + BOUNDARY1_REG); + writeb_relaxed(0x00, miphy_phy->base + IDLL_TEST_REG); + writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG); + val = miphy_dev->sata_tx_pol_inv ? + (TX_POL | DES_BIT_LOCK_EN) : DES_BIT_LOCK_EN; + writeb_relaxed(val, miphy_phy->base + CTRL_REG); + + val = BIT_LOCK_CNT_512 | BIT_LOCK_LEVEL; + writeb_relaxed(val, miphy_phy->base + DES_BITLOCK_REG); + writeb_relaxed(0x00, miphy_phy->base + RESET_REG); + + return 0; +} + +static int miphy365x_init(struct phy *phy) +{ + struct miphy365x_phy *miphy_phy = phy_get_drvdata(phy); + struct miphy365x_dev *miphy_dev = dev_get_drvdata(phy->dev.parent); + int ret = 0; + + mutex_lock(&miphy_dev->miphy_mutex); + + ret = miphy365x_set_path(miphy_phy, miphy_dev); + if (ret) { + mutex_unlock(&miphy_dev->miphy_mutex); + return ret; + } + + /* Initialise Miphy for PCIe or SATA */ + if (miphy_phy->type == MIPHY_TYPE_PCIE) + ret = miphy365x_init_pcie_port(miphy_phy, miphy_dev); + else + ret = miphy365x_init_sata_port(miphy_phy, miphy_dev); + + mutex_unlock(&miphy_dev->miphy_mutex); + + return ret; +} + +static struct phy *miphy365x_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct miphy365x_dev *state = dev_get_drvdata(dev); + u8 port, type; + + if (args->count != 2) { + dev_err(dev, "Invalid number of cells in 'phy' property\n"); + return ERR_PTR(-EINVAL); + } + + if (args->args[0] & 0xFFFFFF00 || args->args[1] & 0xFFFFFF00) { + dev_err(dev, "Unsupported flags set in 'phy' property\n"); + return ERR_PTR(-EINVAL); + } + + port = args->args[0]; + type = args->args[1]; + + if (WARN_ON(port >= ARRAY_SIZE(ports))) + return ERR_PTR(-EINVAL); + + if (type == MIPHY_TYPE_SATA) + state->phys[port].base = state->phys[port].sata; + else if (type == MIPHY_TYPE_PCIE) + state->phys[port].base = state->phys[port].pcie; + else { + WARN(1, "Invalid type specified in DT"); + return ERR_PTR(-EINVAL); + } + + state->phys[port].type = type; + + return state->phys[port].phy; +} + +static struct phy_ops miphy365x_ops = { + .init = miphy365x_init, + .owner = THIS_MODULE, +}; + +static int miphy365x_get_base_addr(struct platform_device *pdev, + struct miphy365x_phy *phy, u8 port) +{ + struct resource *res; + char type[6]; + + sprintf(type, "sata%d", port); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, type); + phy->sata = devm_ioremap_resource(&pdev->dev, res)); + if (!phy->sata) + return -ENOMEM; + + sprintf(type, "pcie%d", port); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, type); + phy->pcie = devm_ioremap_resource(&pdev->dev, res)); + if (!phy->pcie) + return -ENOMEM; + + return 0; +} + +static int miphy365x_of_probe(struct device_node *np, + struct miphy365x_dev *phy_dev) +{ + phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(phy_dev->regmap)) { + dev_err(phy_dev->dev, "No syscfg phandle specified\n"); + return PTR_ERR(phy_dev->regmap); + } + + of_property_read_u32(np, "st,sata-gen", &phy_dev->sata_gen); + if (!phy_dev->sata_gen) + phy_dev->sata_gen = SATA_GEN1; + + phy_dev->pcie_tx_pol_inv = + of_property_read_bool(np, "st,pcie-tx-pol-inv"); + + phy_dev->sata_tx_pol_inv = + of_property_read_bool(np, "st,sata-tx-pol-inv"); + + return 0; +} + +static int miphy365x_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct miphy365x_dev *phy_dev; + struct device *dev = &pdev->dev; + struct phy_provider *provider; + u8 port; + int ret; + + phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL); + if (!phy_dev) + return -ENOMEM; + + ret = miphy365x_of_probe(np, phy_dev); + if (ret) + return ret; + + phy_dev->dev = dev; + + dev_set_drvdata(dev, phy_dev); + + mutex_init(&phy_dev->miphy_mutex); + + for (port = 0; port < ARRAY_SIZE(ports); port++) { + struct phy *phy; + + phy = devm_phy_create(dev, &miphy365x_ops, NULL); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create PHY on port %d\n", port); + return PTR_ERR(phy); + } + + phy_dev->phys[port].phy = phy; + phy_dev->phys[port].port = port; + + ret = miphy365x_get_base_addr(pdev, + &phy_dev->phys[port], port); + if (ret) + return ret; + + phy_set_drvdata(phy, &phy_dev->phys[port]); + } + + provider = devm_of_phy_provider_register(dev, miphy365x_xlate); + if (IS_ERR(provider)) + return PTR_ERR(provider); + + return 0; +} + +static const struct of_device_id miphy365x_of_match[] = { + { .compatible = "st,miphy365x-phy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, miphy365x_of_match); + +static struct platform_driver miphy365x_driver = { + .probe = miphy365x_probe, + .driver = { + .name = "miphy365x-phy", + .owner = THIS_MODULE, + .of_match_table = miphy365x_of_match, + } +}; +module_platform_driver(miphy365x_driver); + +MODULE_AUTHOR("Alexandre Torgue "); +MODULE_DESCRIPTION("STMicroelectronics miphy365x driver"); +MODULE_LICENSE("GPL v2"); From 7ebdb52e192c4d496a9b3a87d47eba3eba3e1fd4 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 9 Jul 2014 12:41:13 +0100 Subject: [PATCH 194/211] phy: miphy365x: Represent each PHY channel as a DT subnode This has the added advantages of being able to enable/disable each of the channels as simply as enabling/disabling the DT node. Suggested-by: Kishon Vijay Abraham I Signed-off-by: Lee Jones Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-miphy365x.c | 256 +++++++++++++++++++----------------- 1 file changed, 138 insertions(+), 118 deletions(-) diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 65ecd04da9bc..e111baf187ce 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,10 +29,8 @@ #define HFC_TIMEOUT 100 -#define SYSCFG_2521 0x824 -#define SYSCFG_2522 0x828 -#define SYSCFG_PCIE_SATA_MASK BIT(1) -#define SYSCFG_PCIE_SATA_POS 1 +#define SYSCFG_SELECT_SATA_MASK BIT(1) +#define SYSCFG_SELECT_SATA_POS 1 /* MiPHY365x register definitions */ #define RESET_REG 0x00 @@ -136,25 +135,21 @@ #define BIT_LOCK_LEVEL 0x01 #define BIT_LOCK_CNT_512 (0x03 << 5) -static u8 ports[] = { MIPHY_PORT_0, MIPHY_PORT_1 }; - struct miphy365x_phy { struct phy *phy; void __iomem *base; - void __iomem *sata; - void __iomem *pcie; + bool pcie_tx_pol_inv; + bool sata_tx_pol_inv; + u32 sata_gen; + u64 ctrlreg; u8 type; - u8 port; }; struct miphy365x_dev { struct device *dev; struct regmap *regmap; struct mutex miphy_mutex; - struct miphy365x phys[ARRAY_SIZE(ports)]; - bool pcie_tx_pol_inv; - bool sata_tx_pol_inv; - u32 sata_gen; + struct miphy365x_phy **phys; }; /* @@ -180,27 +175,12 @@ static u8 rx_tx_spd[] = { static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, struct miphy365x_dev *miphy_dev) { - u8 config = miphy_phy->type | miphy_phy->port; - u32 mask = SYSCFG_PCIE_SATA_MASK; - u32 reg; - bool sata; + bool sata = (miphy_phy->type == MIPHY_TYPE_SATA); - switch (config) { - case MIPHY_SATA_PORT0: - reg = SYSCFG_2521; - sata = true; - break; - case MIPHY_PCIE_PORT1: - reg = SYSCFG_2522; - sata = false; - break; - default: - dev_err(miphy_dev->dev, "Configuration not supported\n"); - return -EINVAL; - } - - return regmap_update_bits(miphy_dev->regmap, reg, mask, - sata << SYSCFG_PCIE_SATA_POS); + return regmap_update_bits(miphy_dev->regmap, + (unsigned int)miphy_phy->ctrlreg, + SYSCFG_SELECT_SATA_MASK, + sata << SYSCFG_SELECT_SATA_POS); } static int miphy365x_init_pcie_port(struct miphy365x_phy *miphy_phy, @@ -261,14 +241,14 @@ static inline void miphy365x_set_comp(struct miphy365x_phy *miphy_phy, { u8 val, mask; - if (miphy_dev->sata_gen == SATA_GEN1) + if (miphy_phy->sata_gen == SATA_GEN1) writeb_relaxed(COMP_2MHZ_RAT_GEN1, miphy_phy->base + COMP_CTRL2_REG); else writeb_relaxed(COMP_2MHZ_RAT, miphy_phy->base + COMP_CTRL2_REG); - if (miphy_dev->sata_gen != SATA_GEN3) { + if (miphy_phy->sata_gen != SATA_GEN3) { writeb_relaxed(COMSR_COMP_REF, miphy_phy->base + COMP_CTRL3_REG); /* @@ -312,7 +292,7 @@ static inline void miphy365x_set_ssc(struct miphy365x_phy *miphy_phy, miphy_phy->base + PLL_SSC_PER_LSB_REG); /* SSC Settings complete */ - if (miphy_dev->sata_gen == SATA_GEN1) { + if (miphy_phy->sata_gen == SATA_GEN1) { val = PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL; writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG); } else { @@ -334,7 +314,7 @@ static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy, val = RST_PLL | RST_PLL_CAL | RST_RX | RST_MACRO; writeb_relaxed(val, miphy_phy->base + RESET_REG); - if (miphy_dev->sata_tx_pol_inv) + if (miphy_phy->sata_tx_pol_inv) writeb_relaxed(TX_POL, miphy_phy->base + CTRL_REG); /* @@ -344,7 +324,7 @@ static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy, */ writeb_relaxed(SPDSEL_SEL, miphy_phy->base + BOUNDARY1_REG); writeb_relaxed(START_CLK_HF, miphy_phy->base + IDLL_TEST_REG); - val = rx_tx_spd[miphy_dev->sata_gen]; + val = rx_tx_spd[miphy_phy->sata_gen]; writeb_relaxed(val, miphy_phy->base + BOUNDARY3_REG); /* Wait for HFC_READY = 0 */ @@ -355,7 +335,7 @@ static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy, /* Compensation Recalibration */ miphy365x_set_comp(miphy_phy, miphy_dev); - switch (miphy_dev->sata_gen) { + switch (miphy_phy->sata_gen) { case SATA_GEN3: /* * TX Swing target 550-600mv peak to peak diff @@ -423,7 +403,7 @@ static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy, writeb_relaxed(0x00, miphy_phy->base + BOUNDARY1_REG); writeb_relaxed(0x00, miphy_phy->base + IDLL_TEST_REG); writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG); - val = miphy_dev->sata_tx_pol_inv ? + val = miphy_phy->sata_tx_pol_inv ? (TX_POL | DES_BIT_LOCK_EN) : DES_BIT_LOCK_EN; writeb_relaxed(val, miphy_phy->base + CTRL_REG); @@ -459,40 +439,95 @@ static int miphy365x_init(struct phy *phy) return ret; } +int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, + int index) +{ + struct device_node *phynode = miphy_phy->phy->dev.of_node; + const char *name; + const __be32 *taddr; + int type = miphy_phy->type; + int ret; + + ret = of_property_read_string_index(phynode, "reg-names", index, &name); + if (ret) { + dev_err(dev, "no reg-names property not found\n"); + return ret; + } + + if (!strncmp(name, "syscfg", 6)) { + taddr = of_get_address(phynode, index, NULL, NULL); + if (!taddr) { + dev_err(dev, "failed to fetch syscfg address\n"); + return -EINVAL; + } + + miphy_phy->ctrlreg = of_translate_address(phynode, taddr); + if (miphy_phy->ctrlreg == OF_BAD_ADDR) { + dev_err(dev, "failed to translate syscfg address\n"); + return -EINVAL; + } + + return 0; + } + + if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) || + (!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE))) + return 0; + + miphy_phy->base = of_iomap(phynode, index); + if (!miphy_phy->base) { + dev_err(dev, "Failed to map %s\n", phynode->full_name); + return -EINVAL; + } + + return 0; +} + static struct phy *miphy365x_xlate(struct device *dev, struct of_phandle_args *args) { - struct miphy365x_dev *state = dev_get_drvdata(dev); - u8 port, type; + struct miphy365x_dev *miphy_dev = dev_get_drvdata(dev); + struct miphy365x_phy *miphy_phy = NULL; + struct device_node *phynode = args->np; + int ret, index; - if (args->count != 2) { + if (!of_device_is_available(phynode)) { + dev_warn(dev, "Requested PHY is disabled\n"); + return ERR_PTR(-ENODEV); + } + + if (args->args_count != 1) { dev_err(dev, "Invalid number of cells in 'phy' property\n"); return ERR_PTR(-EINVAL); } - if (args->args[0] & 0xFFFFFF00 || args->args[1] & 0xFFFFFF00) { - dev_err(dev, "Unsupported flags set in 'phy' property\n"); + for (index = 0; index < of_get_child_count(dev->of_node); index++) + if (phynode == miphy_dev->phys[index]->phy->dev.of_node) { + miphy_phy = miphy_dev->phys[index]; + break; + } + + if (!miphy_phy) { + dev_err(dev, "Failed to find appropriate phy\n"); return ERR_PTR(-EINVAL); } - port = args->args[0]; - type = args->args[1]; + miphy_phy->type = args->args[0]; - if (WARN_ON(port >= ARRAY_SIZE(ports))) - return ERR_PTR(-EINVAL); - - if (type == MIPHY_TYPE_SATA) - state->phys[port].base = state->phys[port].sata; - else if (type == MIPHY_TYPE_PCIE) - state->phys[port].base = state->phys[port].pcie; - else { - WARN(1, "Invalid type specified in DT"); + if (!(miphy_phy->type == MIPHY_TYPE_SATA || + miphy_phy->type == MIPHY_TYPE_PCIE)) { + dev_err(dev, "Unsupported device type: %d\n", miphy_phy->type); return ERR_PTR(-EINVAL); } - state->phys[port].type = type; + /* Each port handles SATA and PCIE - third entry is always sysconf. */ + for (index = 0; index < 3; index++) { + ret = miphy365x_get_addr(dev, miphy_phy, index); + if (ret < 0) + return ERR_PTR(ret); + } - return state->phys[port].phy; + return miphy_phy->phy; } static struct phy_ops miphy365x_ops = { @@ -500,95 +535,80 @@ static struct phy_ops miphy365x_ops = { .owner = THIS_MODULE, }; -static int miphy365x_get_base_addr(struct platform_device *pdev, - struct miphy365x_phy *phy, u8 port) +static int miphy365x_of_probe(struct device_node *phynode, + struct miphy365x_phy *miphy_phy) { - struct resource *res; - char type[6]; + of_property_read_u32(phynode, "st,sata-gen", &miphy_phy->sata_gen); + if (!miphy_phy->sata_gen) + miphy_phy->sata_gen = SATA_GEN1; - sprintf(type, "sata%d", port); + miphy_phy->pcie_tx_pol_inv = + of_property_read_bool(phynode, "st,pcie-tx-pol-inv"); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, type); - phy->sata = devm_ioremap_resource(&pdev->dev, res)); - if (!phy->sata) - return -ENOMEM; - - sprintf(type, "pcie%d", port); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, type); - phy->pcie = devm_ioremap_resource(&pdev->dev, res)); - if (!phy->pcie) - return -ENOMEM; - - return 0; -} - -static int miphy365x_of_probe(struct device_node *np, - struct miphy365x_dev *phy_dev) -{ - phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); - if (IS_ERR(phy_dev->regmap)) { - dev_err(phy_dev->dev, "No syscfg phandle specified\n"); - return PTR_ERR(phy_dev->regmap); - } - - of_property_read_u32(np, "st,sata-gen", &phy_dev->sata_gen); - if (!phy_dev->sata_gen) - phy_dev->sata_gen = SATA_GEN1; - - phy_dev->pcie_tx_pol_inv = - of_property_read_bool(np, "st,pcie-tx-pol-inv"); - - phy_dev->sata_tx_pol_inv = - of_property_read_bool(np, "st,sata-tx-pol-inv"); + miphy_phy->sata_tx_pol_inv = + of_property_read_bool(phynode, "st,sata-tx-pol-inv"); return 0; } static int miphy365x_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - struct miphy365x_dev *phy_dev; - struct device *dev = &pdev->dev; + struct device_node *child, *np = pdev->dev.of_node; + struct miphy365x_dev *miphy_dev; struct phy_provider *provider; - u8 port; + struct phy *phy; + int chancount, port = 0; int ret; - phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL); - if (!phy_dev) + miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL); + if (!miphy_dev) return -ENOMEM; - ret = miphy365x_of_probe(np, phy_dev); - if (ret) - return ret; + chancount = of_get_child_count(np); + miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount, + GFP_KERNEL); + if (!miphy_dev->phys) + return -ENOMEM; - phy_dev->dev = dev; + miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(miphy_dev->regmap)) { + dev_err(miphy_dev->dev, "No syscfg phandle specified\n"); + return PTR_ERR(miphy_dev->regmap); + } - dev_set_drvdata(dev, phy_dev); + miphy_dev->dev = &pdev->dev; - mutex_init(&phy_dev->miphy_mutex); + dev_set_drvdata(&pdev->dev, miphy_dev); - for (port = 0; port < ARRAY_SIZE(ports); port++) { - struct phy *phy; + mutex_init(&miphy_dev->miphy_mutex); - phy = devm_phy_create(dev, &miphy365x_ops, NULL); + for_each_child_of_node(np, child) { + struct miphy365x_phy *miphy_phy; + + miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy), + GFP_KERNEL); + if (!miphy_phy) + return -ENOMEM; + + miphy_dev->phys[port] = miphy_phy; + + phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops, NULL); if (IS_ERR(phy)) { - dev_err(dev, "failed to create PHY on port %d\n", port); + dev_err(&pdev->dev, "failed to create PHY\n"); return PTR_ERR(phy); } - phy_dev->phys[port].phy = phy; - phy_dev->phys[port].port = port; + miphy_dev->phys[port]->phy = phy; - ret = miphy365x_get_base_addr(pdev, - &phy_dev->phys[port], port); + ret = miphy365x_of_probe(child, miphy_phy); if (ret) return ret; - phy_set_drvdata(phy, &phy_dev->phys[port]); + phy_set_drvdata(phy, miphy_dev->phys[port]); + port++; } - provider = devm_of_phy_provider_register(dev, miphy365x_xlate); + provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate); if (IS_ERR(provider)) return PTR_ERR(provider); From c5946f9d286ad368329c79107fdf4d825d2091bd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 21 Jul 2014 10:17:44 +0800 Subject: [PATCH 195/211] USB: core: hcd-pci: free IRQ before disabling PCI device when shutting down The assigned IRQ should be freed before calling pci_disable_device() when shutting down system, otherwise it will cause following warning. [ 568.879482] ------------[ cut here ]------------ [ 568.884236] WARNING: CPU: 1 PID: 3300 at /home/konrad/ssd/konrad/xtt-i386/bootstrap/linux-usb/fs/proc/generic.c:521 remove_proc_entry+0x165/0x170() [ 568.897846] remove_proc_entry: removing non-empty directory 'irq/16', leaking at least 'ohci_hcd:usb4' [ 568.907430] Modules linked in: dm_multipath dm_mod iscsi_boot_sysfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi libcrc32c crc32c_generic sg sd_mod crct10dif_generic crc_t10dif crct10dif_common radeon fbcon tileblit ttm font bitblit softcursor ata_generic ahci libahci drm_kms_helper skge r8169 libata mii scsi_mod wmi acpi_cpufreq [ 568.938539] CPU: 1 PID: 3300 Comm: init Tainted: G W 3.16.0-rc5upstream-01651-g03b9189 #1 [ 568.947946] Hardware name: ECS A780GM-A Ultra/A780GM-A Ultra, BIOS 080015 04/01/2010 [ 568.956008] 00000209 ed0f1cd0 c1617946 c175403c ed0f1d00 c1090c3f c1754084 ed0f1d2c [ 568.964068] 00000ce4 c175403c 00000209 c11f22a5 c11f22a5 f755e8c0 ed0f1d78 f755e90d [ 568.972128] ed0f1d18 c1090cde 00000009 ed0f1d10 c1754084 ed0f1d2c ed0f1d60 c11f22a5 [ 568.980194] Call Trace: [ 568.982715] [] dump_stack+0x48/0x60 [ 568.987294] [] warn_slowpath_common+0x7f/0xa0 [ 569.003887] [] warn_slowpath_fmt+0x2e/0x30 [ 569.009092] [] remove_proc_entry+0x165/0x170 [ 569.014476] [] unregister_irq_proc+0xaa/0xc0 [ 569.019858] [] free_desc+0x1f/0x60 [ 569.024346] [] irq_free_descs+0x3a/0x80 [ 569.029283] [] irq_dispose_mapping+0x2d/0x50 [ 569.034666] [] mp_unmap_irq+0x73/0xa0 [ 569.039423] [] acpi_unregister_gsi_ioapic+0x2b/0x40 [ 569.045431] [] acpi_unregister_gsi+0xf/0x20 [ 569.050725] [] acpi_pci_irq_disable+0x4b/0x50 [ 569.056196] [] pcibios_disable_device+0x18/0x20 [ 569.061848] [] do_pci_disable_device+0x4d/0x60 [ 569.067410] [] pci_disable_device+0x47/0xb0 [ 569.077814] [] usb_hcd_pci_shutdown+0x31/0x40 [ 569.083285] [] pci_device_shutdown+0x19/0x50 [ 569.088667] [] device_shutdown+0x14/0x120 [ 569.093777] [] kernel_restart_prepare+0x2d/0x30 [ 569.099429] [] kernel_restart+0xe/0x60 [ 569.109028] [] SYSC_reboot+0x191/0x220 [ 569.159269] [] SyS_reboot+0x1a/0x20 [ 569.163843] [] sysenter_do_call+0x12/0x16 [ 569.168951] ---[ end trace ccc1ec4471c289c9 ]--- Tested-by: Aaron Lu Signed-off-by: Jiang Liu Reviewed-by: Huang Rui Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 82044b5d6113..efc953119ce2 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -380,6 +380,8 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev) if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && hcd->driver->shutdown) { hcd->driver->shutdown(hcd); + if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0) + free_irq(hcd->irq, hcd); pci_disable_device(dev); } } From b1bd3f1a398ef27dd09a594c38dde34472b453af Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Mon, 21 Jul 2014 10:16:53 +0530 Subject: [PATCH 196/211] usb: lvstest: Fix sparse warnings generated by kbuild test bot Following sparse warnings were reported by kbuild test bot drivers/usb/misc/lvstest.c:314:28: sparse: incorrect type in assignment (different base types) drivers/usb/misc/lvstest.c:314:28: expected unsigned short [unsigned] [usertype] portchange drivers/usb/misc/lvstest.c:314:28: got restricted __le16 [usertype] wPortChange drivers/usb/misc/lvstest.c:332:40: sparse: restricted __le16 degrades to integer This patch fixes above warnings. Reported-by: kbuild test robot Signed-off-by: Pratyush Anand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/lvstest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index 02df9a72b990..7d589c156fb1 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -311,7 +311,7 @@ static void lvs_rh_work(struct work_struct *work) if (ret < 4) continue; - portchange = port_status->wPortChange; + portchange = le16_to_cpu(port_status->wPortChange); if (portchange & USB_PORT_STAT_C_LINK_STATE) lvs_rh_clear_port_feature(hdev, i, @@ -329,7 +329,7 @@ static void lvs_rh_work(struct work_struct *work) lvs_rh_clear_port_feature(hdev, i, USB_PORT_FEAT_C_CONNECTION); - if (port_status->wPortStatus & + if (le16_to_cpu(port_status->wPortStatus) & USB_PORT_STAT_CONNECTION) { lvs->present = true; lvs->portnum = i; From 9672f0feb566423deb245032a1c9a7a14dacb6eb Mon Sep 17 00:00:00 2001 From: Amit Virdi Date: Mon, 21 Jul 2014 10:46:18 +0530 Subject: [PATCH 197/211] usb: core: allow zero packet flag for interrupt urbs Section 4.4.7.2 "Interrupt Transfer Bandwidth Requirements" of the USB3.0 spec says: A zero-length data payload is a valid transfer and may be useful for some implementations. So, extend the logic of allowing URB_ZERO_PACKET to interrupt urbs too. Otherwise, the kernel throws warning of BOGUS transfer flags. Signed-off-by: Amit Virdi Acked-by: Hans de Goede Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 991386ceb4ec..c9e8ee81b6b7 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -454,6 +454,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) URB_FREE_BUFFER); switch (xfertype) { case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: if (is_out) allowed |= URB_ZERO_PACKET; /* FALLTHROUGH */ From 16853d7bcb6dd5806534c63051580472b4aa4560 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Tue, 22 Jul 2014 10:09:43 +0800 Subject: [PATCH 198/211] usb: ci_hdrc_imx: Return -EINVAL for missing USB PHY -ENODEV is interpreted by the generic driver probing function as a non-matching driver. This leads to a missing probe failure message. Also a missing USB PHY is more of an invalid configuration of the usb driver because it is necessary. This patch returns -EINVAL if devm_usb_get_phy_by_phandle() returned -ENODEV. Signed-off-by: Markus Pargmann Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 2e58f8dfd311..65444b02bd68 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -133,6 +133,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0); if (IS_ERR(data->phy)) { ret = PTR_ERR(data->phy); + /* Return -EINVAL if no usbphy is available */ + if (ret == -ENODEV) + ret = -EINVAL; goto err_clk; } From 000cb478f3227d34d126004acc5389fb562d0b53 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Tue, 22 Jul 2014 10:09:44 +0800 Subject: [PATCH 199/211] usb: ci_hdrc_imx doc: fsl,usbphy is required fsl,usbphy is no optional property. This patch moves it to the list of required properties. Signed-off-by: Markus Pargmann Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt index a6a32cb7f777..1bae71e9ad47 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt @@ -4,6 +4,7 @@ Required properties: - compatible: Should be "fsl,imx27-usb" - reg: Should contain registers location and length - interrupts: Should contain controller interrupt +- fsl,usbphy: phandle of usb phy that connects to the port Recommended properies: - phy_type: the type of the phy connected to the core. Should be one @@ -12,7 +13,6 @@ Recommended properies: - dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" Optional properties: -- fsl,usbphy: phandler of usb phy that connects to the only one port - fsl,usbmisc: phandler of non-core register device, with one argument that indicate usb controller index - vbus-supply: regulator for vbus From df40f8d3cb12b9a404a0b604fe71a6eb04bf36be Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 22 Jul 2014 10:09:45 +0800 Subject: [PATCH 200/211] usb: chipidea: debug: fix sparse non static symbol warnings Fixes the following sparse warnings: drivers/usb/chipidea/debug.c:211:5: warning: symbol 'ci_otg_show' was not declared. Should it be static? drivers/usb/chipidea/debug.c:334:5: warning: symbol 'ci_registers_show' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 7cccab6ff308..795d6538d630 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -208,7 +208,7 @@ static const struct file_operations ci_requests_fops = { .release = single_release, }; -int ci_otg_show(struct seq_file *s, void *unused) +static int ci_otg_show(struct seq_file *s, void *unused) { struct ci_hdrc *ci = s->private; struct otg_fsm *fsm; @@ -331,7 +331,7 @@ static const struct file_operations ci_role_fops = { .release = single_release, }; -int ci_registers_show(struct seq_file *s, void *unused) +static int ci_registers_show(struct seq_file *s, void *unused) { struct ci_hdrc *ci = s->private; u32 tmp_reg; From 9273b8a270878906540349422ab24558b9d65716 Mon Sep 17 00:00:00 2001 From: Patrick Riphagen Date: Thu, 24 Jul 2014 09:12:52 +0200 Subject: [PATCH 201/211] USB: serial: ftdi_sio: Annotate the current Xsens PID assignments The converters are used in specific products. It can be useful to know which they are exactly. Signed-off-by: Patrick Riphagen Signed-off-by: Frans Klaver Cc: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio_ids.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index c4777bc6aee0..3fc789701e45 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -140,12 +140,12 @@ /* * Xsens Technologies BV products (http://www.xsens.com). */ -#define XSENS_CONVERTER_0_PID 0xD388 -#define XSENS_CONVERTER_1_PID 0xD389 +#define XSENS_CONVERTER_0_PID 0xD388 /* Xsens USB converter */ +#define XSENS_CONVERTER_1_PID 0xD389 /* Xsens Wireless Receiver */ #define XSENS_CONVERTER_2_PID 0xD38A -#define XSENS_CONVERTER_3_PID 0xD38B -#define XSENS_CONVERTER_4_PID 0xD38C -#define XSENS_CONVERTER_5_PID 0xD38D +#define XSENS_CONVERTER_3_PID 0xD38B /* Xsens USB-serial converter */ +#define XSENS_CONVERTER_4_PID 0xD38C /* Xsens Wireless Receiver */ +#define XSENS_CONVERTER_5_PID 0xD38D /* Xsens Awinda Station */ #define XSENS_CONVERTER_6_PID 0xD38E #define XSENS_CONVERTER_7_PID 0xD38F From 4bdcde358b4bda74e356841d351945ca3f2245dd Mon Sep 17 00:00:00 2001 From: Patrick Riphagen Date: Thu, 24 Jul 2014 09:09:50 +0200 Subject: [PATCH 202/211] USB: serial: ftdi_sio: Add support for new Xsens devices This adds support for new Xsens devices, using Xsens' own Vendor ID. Signed-off-by: Patrick Riphagen Signed-off-by: Frans Klaver Cc: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b9035c319766..216ce3078270 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -660,6 +660,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) }, + { USB_DEVICE(XSENS_VID, XSENS_MTW_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 3fc789701e45..1e58d90a0b6c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -140,6 +140,9 @@ /* * Xsens Technologies BV products (http://www.xsens.com). */ +#define XSENS_VID 0x2639 +#define XSENS_CONVERTER_PID 0xD00D /* Xsens USB-serial converter */ +#define XSENS_MTW_PID 0x0200 /* Xsens MTw */ #define XSENS_CONVERTER_0_PID 0xD388 /* Xsens USB converter */ #define XSENS_CONVERTER_1_PID 0xD389 /* Xsens Wireless Receiver */ #define XSENS_CONVERTER_2_PID 0xD38A From cd83ce9e6195aa3ea15ab4db92892802c20df5d0 Mon Sep 17 00:00:00 2001 From: James P Michels III Date: Sun, 27 Jul 2014 13:28:04 -0400 Subject: [PATCH 203/211] usb-core bInterval quirk This patch adds a usb quirk to support devices with interupt endpoints and bInterval values expressed as microframes. The quirk causes the parse endpoint function to modify the reported bInterval to a standards conforming value. There is currently code in the endpoint parser that checks for bIntervals that are outside of the valid range (1-16 for USB 2+ high speed and super speed interupt endpoints). In this case, the code assumes the bInterval is being reported in 1ms frames. As well, the correction is only applied if the original bInterval value is out of the 1-16 range. With this quirk applied to the device, the bInterval will be accurately adjusted from microframes to an exponent. Signed-off-by: James P Michels III Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 11 +++++++++++ drivers/usb/core/quirks.c | 4 ++++ include/linux/usb/quirks.h | 11 +++++++++++ 3 files changed, 26 insertions(+) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 1ab4df1de2da..b2a540b43f97 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -199,6 +199,17 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, if (n == 0) n = 9; /* 32 ms = 2^(9-1) uframes */ j = 16; + + /* + * Adjust bInterval for quirked devices. + * This quirk fixes bIntervals reported in + * linear microframes. + */ + if (to_usb_device(ddev)->quirks & + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) { + n = clamp(fls(d->bInterval), i, j); + i = j = n; + } break; default: /* USB_SPEED_FULL or _LOW */ /* For low-speed, 10 ms is the official minimum. diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 2c9ba4077075..bae636e2a1a3 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -145,6 +145,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Razer - Razer Blade Keyboard */ + { USB_DEVICE(0x1532, 0x0116), .driver_info = + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* BUILDWIN Photo Frame */ { USB_DEVICE(0x1908, 0x1315), .driver_info = USB_QUIRK_HONOR_BNUMINTERFACES }, diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 52f944dfe2fd..55a17b188daa 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -30,4 +30,15 @@ descriptor */ #define USB_QUIRK_DELAY_INIT 0x00000040 +/* + * For high speed and super speed interupt endpoints, the USB 2.0 and + * USB 3.0 spec require the interval in microframes + * (1 microframe = 125 microseconds) to be calculated as + * interval = 2 ^ (bInterval-1). + * + * Devices with this quirk report their bInterval as the result of this + * calculation instead of the exponent variable used in the calculation. + */ +#define USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL 0x00000080 + #endif /* __LINUX_USB_QUIRKS_H */ From 3dbef993c0eb113bf8e85abff8dd57fa33d5bb9b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Jul 2014 17:16:51 +0200 Subject: [PATCH 204/211] uwb/whci: use correct structure type name in sizeof Correct typo in the name of the type given to sizeof. Because it is the size of a pointer that is wanted, the typo has no impact on compilation or execution. This problem was found using Coccinelle (http://coccinelle.lip6.fr/). The semantic patch used can be found in message 0 of this patch series. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/uwb/whci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/uwb/whci.c b/drivers/uwb/whci.c index c9df8ba97dae..46b7cfcdfbca 100644 --- a/drivers/uwb/whci.c +++ b/drivers/uwb/whci.c @@ -175,7 +175,7 @@ static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id) err = -ENOMEM; card = kzalloc(sizeof(struct whci_card) - + sizeof(struct whci_dev *) * (n_caps + 1), + + sizeof(struct umc_dev *) * (n_caps + 1), GFP_KERNEL); if (card == NULL) goto error_kzalloc; From e2875c33787ebda21aeecc1a9d3ff52b3aa413ec Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Aug 2014 17:33:08 +0200 Subject: [PATCH 205/211] uas: Limit qdepth to 32 when connected over usb-2 Some jmicron uas chipsets act up (they disconnect from the bus) when sending more then 32 commands to them at once. Rather then building an ever growing list with usb-id based quirks for devices using this chipset, simply reduce the qdepth to 32 when connected over usb-2. 32 should be plenty to keep things close to maximum possible throughput on usb-2. Cc: stable@vger.kernel.org Tested-and-reported-by: Laszlo T. Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 511b22953167..3f42785f653c 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1026,7 +1026,7 @@ static int uas_configure_endpoints(struct uas_dev_info *devinfo) usb_endpoint_num(&eps[3]->desc)); if (udev->speed != USB_SPEED_SUPER) { - devinfo->qdepth = 256; + devinfo->qdepth = 32; devinfo->use_streams = 0; } else { devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, From 8f873c1ff4ca034626093d03b254e7cb8bb782dd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:01:18 +0200 Subject: [PATCH 206/211] xhci: Blacklist using streams on the Etron EJ168 controller Streams on the EJ168 do not work as they should. I've spend 2 days trying to get them to work, but without success. The first problem is that when ever you ring the stream-ring doorbell, the controller starts executing trbs at the beginning of the first ring segment, event if it ended somewhere else previously. This can be worked around by allowing enqueing only one td (not a problem with how streams are typically used) and then resetting our copies of the enqueueing en dequeueing pointers on a td completion to match what the controller seems to be doing. This way things seem to start working with uas and instead of being able to complete only the very first scsi command, the scsi core can probe the disk. But then things break later on when td-s get enqueued with more then one trb. The controller does seem to increase its dequeue pointer while executing a stream-ring (data transfer events I inserted for debugging do trigger). However execution seems to stop at the final normal trb of a multi trb td, even if there is a data transfer event inserted after the final trb. The first problem alone is a serious deviation from the spec, and esp. dealing with cancellation would have been very tricky if not outright impossible, but the second problem simply is a deal breaker altogether, so this patch simply disables streams. Note this will cause the usb-storage + uas driver pair to automatically switch to using usb-storage instead of uas on these devices, essentially reverting to the 3.14 and earlier behavior when uas was marked CONFIG_BROKEN. https://bugzilla.redhat.com/show_bug.cgi?id=1121288 https://bugzilla.kernel.org/show_bug.cgi?id=80101 Cc: stable@vger.kernel.org # 3.15 Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 4 +++- drivers/usb/host/xhci.c | 3 ++- drivers/usb/host/xhci.h | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index e20520f42753..464049f638c0 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -143,6 +143,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; xhci->quirks |= XHCI_TRUST_TX_LENGTH; + xhci->quirks |= XHCI_BROKEN_STREAMS; } if (pdev->vendor == PCI_VENDOR_ID_RENESAS && pdev->device == 0x0015) @@ -230,7 +231,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto put_usb3_hcd; /* Roothub already marked as USB 3.0 speed */ - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + if (!(xhci->quirks & XHCI_BROKEN_STREAMS) && + HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 0342d9b63977..a0772d362e70 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3148,7 +3148,8 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, num_streams); /* MaxPSASize value 0 (2 streams) means streams are not supported */ - if (HCC_MAX_PSA(xhci->hcc_params) < 4) { + if ((xhci->quirks & XHCI_BROKEN_STREAMS) || + HCC_MAX_PSA(xhci->hcc_params) < 4) { xhci_dbg(xhci, "xHCI controller does not support streams.\n"); return -ENOSYS; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9ffecd56600d..dace5152e179 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1558,6 +1558,8 @@ struct xhci_hcd { #define XHCI_PLAT (1 << 16) #define XHCI_SLOW_SUSPEND (1 << 17) #define XHCI_SPURIOUS_WAKEUP (1 << 18) +/* For controllers with a broken beyond repair streams implementation */ +#define XHCI_BROKEN_STREAMS (1 << 19) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ From 170625e99485aac578c83fb4aa2bcd9f589570ef Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:01:19 +0200 Subject: [PATCH 207/211] xhci: Rename Asrock P67 pci product-id to EJ168 The 7023 product id is the generic product id for the Etron EJ168, it is not specific to the version found on the Asrock P67 motherboard. The same id is e.g. also used on Gigabyte motherboards and on no-name pci-e usb-3 addon cards. Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 464049f638c0..687d36608155 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -33,7 +33,7 @@ #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400 #define PCI_VENDOR_ID_ETRON 0x1b6f -#define PCI_DEVICE_ID_ASROCK_P67 0x7023 +#define PCI_DEVICE_ID_EJ168 0x7023 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 @@ -140,7 +140,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SPURIOUS_REBOOT; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && - pdev->device == PCI_DEVICE_ID_ASROCK_P67) { + pdev->device == PCI_DEVICE_ID_EJ168) { xhci->quirks |= XHCI_RESET_ON_RESUME; xhci->quirks |= XHCI_TRUST_TX_LENGTH; xhci->quirks |= XHCI_BROKEN_STREAMS; From a0ee619f3ce8d8478c0cdd944b6cb24453ab6297 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:01:21 +0200 Subject: [PATCH 208/211] xhci: Add missing checks for xhci_alloc_command failure Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 4 ++++ drivers/usb/host/xhci.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 749fc68eb5c1..60fb52ae864b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1118,6 +1118,10 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, if (xhci->quirks & XHCI_RESET_EP_QUIRK) { struct xhci_command *command; command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + if (!command) { + xhci_warn(xhci, "WARN Cannot submit cfg ep: ENOMEM\n"); + return; + } xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Queueing configure endpoint command"); xhci_queue_configure_endpoint(xhci, command, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a0772d362e70..b6f21175b872 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1553,6 +1553,10 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) */ if (!(ep->ep_state & EP_HALT_PENDING)) { command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); + if (!command) { + ret = -ENOMEM; + goto done; + } ep->ep_state |= EP_HALT_PENDING; ep->stop_cmds_pending++; ep->stop_cmd_timer.expires = jiffies + From cc4deafc86f75f4e716b37fb4ea3572eb1e49e50 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:01:26 +0200 Subject: [PATCH 209/211] uas: Only complain about missing sg if all other checks succeed Don't complain about controllers without sg support if there are other reasons why uas cannot be used anyways. Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas-detect.h | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h index bb05b984d5f6..618b41791744 100644 --- a/drivers/usb/storage/uas-detect.h +++ b/drivers/usb/storage/uas-detect.h @@ -9,32 +9,15 @@ static int uas_is_interface(struct usb_host_interface *intf) intf->desc.bInterfaceProtocol == USB_PR_UAS); } -static int uas_isnt_supported(struct usb_device *udev) -{ - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - dev_warn(&udev->dev, "The driver for the USB controller %s does not " - "support scatter-gather which is\n", - hcd->driver->description); - dev_warn(&udev->dev, "required by the UAS driver. Please try an" - "alternative USB controller if you wish to use UAS.\n"); - return -ENODEV; -} - static int uas_find_uas_alt_setting(struct usb_interface *intf) { int i; - struct usb_device *udev = interface_to_usbdev(intf); - int sg_supported = udev->bus->sg_tablesize != 0; for (i = 0; i < intf->num_altsetting; i++) { struct usb_host_interface *alt = &intf->altsetting[i]; - if (uas_is_interface(alt)) { - if (!sg_supported) - return uas_isnt_supported(udev); + if (uas_is_interface(alt)) return alt->desc.bAlternateSetting; - } } return -ENODEV; @@ -92,5 +75,14 @@ static int uas_use_uas_driver(struct usb_interface *intf, if (r < 0) return 0; + if (udev->bus->sg_tablesize == 0) { + dev_warn(&udev->dev, + "The driver for the USB controller %s does not support scatter-gather which is\n", + hcd->driver->description); + dev_warn(&udev->dev, + "required by the UAS driver. Please try an other USB controller if you wish to use UAS.\n"); + return 0; + } + return 1; } From 43508be512661c905d0320ee73e0b65ef36d2459 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:01:27 +0200 Subject: [PATCH 210/211] uas: Log a warning when we cannot use uas because the hcd lacks streams So that an user who wants to use uas can see why he is not getting uas. Also move the check down so that we don't warn if there are other reasons why uas cannot work. Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas-detect.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h index 618b41791744..503ac5c8d80f 100644 --- a/drivers/usb/storage/uas-detect.h +++ b/drivers/usb/storage/uas-detect.h @@ -64,9 +64,6 @@ static int uas_use_uas_driver(struct usb_interface *intf, if (flags & US_FL_IGNORE_UAS) return 0; - if (udev->speed >= USB_SPEED_SUPER && !hcd->can_do_streams) - return 0; - alt = uas_find_uas_alt_setting(intf); if (alt < 0) return 0; @@ -84,5 +81,14 @@ static int uas_use_uas_driver(struct usb_interface *intf, return 0; } + if (udev->speed >= USB_SPEED_SUPER && !hcd->can_do_streams) { + dev_warn(&udev->dev, + "USB controller %s does not support streams, which are required by the UAS driver.\n", + hcd_to_bus(hcd)->bus_name); + dev_warn(&udev->dev, + "Please try an other USB controller if you wish to use UAS.\n"); + return 0; + } + return 1; } From d310d05f1225d1f6f2bf505255fdf593bfbb3051 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 1 Aug 2014 09:55:20 +0200 Subject: [PATCH 211/211] USB: devio: fix issue with log flooding usbfs allows user space to pass down an URB which sets URB_SHORT_NOT_OK for output URBs. That causes usbcore to log messages without limit for a nonsensical disallowed combination. The fix is to silently drop the attribute in usbfs. The problem is reported to exist since 3.14 https://www.virtualbox.org/ticket/13085 Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 257876ea03a1..0b59731c3021 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1509,7 +1509,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb u = (is_in ? URB_DIR_IN : URB_DIR_OUT); if (uurb->flags & USBDEVFS_URB_ISO_ASAP) u |= URB_ISO_ASAP; - if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) + if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in) u |= URB_SHORT_NOT_OK; if (uurb->flags & USBDEVFS_URB_NO_FSBR) u |= URB_NO_FSBR;