From 46cdd1900fa7a1d7afd1f8d051e513105d0cea98 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 29 Mar 2016 12:26:06 +0300 Subject: usb: gadget: udc: at91: use PTR_ERR_OR_ZERO() coccicheck found this pattern which could be converted to PTR_ERR_OR_ZERO(). No functional changes. Acked-by: Nicolas Ferre Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/at91_udc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index d0d18947f58b..8bc78418d40e 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc) udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node, "atmel,matrix"); - if (IS_ERR(udc->matrix)) - return PTR_ERR(udc->matrix); - - return 0; + return PTR_ERR_OR_ZERO(udc->matrix); } static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on) -- cgit v1.2.3 From badf6d47f8a93098c6e05fdeb735b44b61877451 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Mar 2016 17:45:08 +0100 Subject: usb: common: rework CONFIG_USB_COMMON logic The phy-am335x driver selects 'USB_COMMON', but all other drivers use 'depends on' for that symbol, and it depends on USB || USB_GADGET itself, which causes a Kconfig warning: warning: (AM335X_PHY_USB) selects USB_COMMON which has unmet direct dependencies (USB_SUPPORT && (USB || USB_GADGET)) As suggested by Felipe Balbi, this turns the logic around, and makes 'USB_COMMON' selected by everything else that needs it, so we can remove the dependencies. Fixes: 59f042f644c5 ("usb: phy: phy-am335x: bypass first VBUS sensing for host-only mode") Signed-off-by: Arnd Bergmann Acked-by: Felipe Balbi Reviewed-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/phy/Kconfig | 3 ++- drivers/usb/Kconfig | 3 +-- drivers/usb/gadget/Kconfig | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 26566db09de0..e92b97cd6056 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -250,7 +250,8 @@ config PHY_SUN9I_USB tristate "Allwinner sun9i SoC USB PHY driver" depends on ARCH_SUNXI && HAS_IOMEM && OF depends on RESET_CONTROLLER - depends on USB_COMMON + depends on USB_SUPPORT + select USB_COMMON select GENERIC_PHY help Enable this to support the transceiver that is part of Allwinner diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 8ed451dd651e..8689dcba5201 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -31,8 +31,6 @@ if USB_SUPPORT config USB_COMMON tristate - default y - depends on USB || USB_GADGET config USB_ARCH_HAS_HCD def_bool y @@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD config USB tristate "Support for Host-side USB" depends on USB_ARCH_HAS_HCD + select USB_COMMON select NLS # for UTF-8 strings ---help--- Universal Serial Bus (USB) is a specification for a serial bus diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index af5d922a8f5d..2057add439f0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -15,6 +15,7 @@ menuconfig USB_GADGET tristate "USB Gadget Support" + select USB_COMMON select NLS help USB is a master/slave protocol, organized with one master -- cgit v1.2.3 From 5e3bd45f170b43cec3fb85f14ef94f176235c4af Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:34 +0200 Subject: usb: gadged: pch_udc: PCI core handles power state for us There is no need to repeat the work that is already done in the PCI driver core. The patch removes excerpts from suspend and resume callbacks. Note that there is no more calls performed to enable or disable a PCI device during suspend-resume cycle. Nowadays they seems to be superfluous. Someone can read more in [1]. While here, convert PM ops to use modern API. [1] https://www.kernel.org/doc/ols/2009/ols2009-pages-319-330.pdf Signed-off-by: Andy Shevchenko [felipe.balbi@linux.intel.com: fixed build break and checkpatch error ] Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 9571ef54b86b..58fc0adacd79 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -3096,44 +3096,28 @@ static void pch_udc_remove(struct pci_dev *pdev) kfree(dev); } -#ifdef CONFIG_PM -static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pch_udc_suspend(struct device *d) { + struct pci_dev *pdev = to_pci_dev(d); struct pch_udc_dev *dev = pci_get_drvdata(pdev); pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); - pci_disable_device(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - - if (pci_save_state(pdev)) { - dev_err(&pdev->dev, - "%s: could not save PCI config state\n", __func__); - return -ENOMEM; - } - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } -static int pch_udc_resume(struct pci_dev *pdev) +static int pch_udc_resume(struct device *d) { - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__); - return ret; - } - pci_enable_wake(pdev, PCI_D3hot, 0); return 0; } + +static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume); +#define PCH_UDC_PM_OPS (&pch_udc_pm) #else -#define pch_udc_suspend NULL -#define pch_udc_resume NULL -#endif /* CONFIG_PM */ +#define PCH_UDC_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ static int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -3262,9 +3246,10 @@ static struct pci_driver pch_udc_driver = { .id_table = pch_udc_pcidev_id, .probe = pch_udc_probe, .remove = pch_udc_remove, - .suspend = pch_udc_suspend, - .resume = pch_udc_resume, .shutdown = pch_udc_shutdown, + .driver = { + .pm = PCH_UDC_PM_OPS, + }, }; module_pci_driver(pch_udc_driver); -- cgit v1.2.3 From 969733f3768528ce7fb435e90adcb5f7984316ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:35 +0200 Subject: usb: gadget: pch_udc: convert to devres API devres API allows to make error paths cleaner and less error prone. Convert the driver to use it. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 98 +++++++++++----------------------------- 1 file changed, 26 insertions(+), 72 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 58fc0adacd79..82e01f8995c5 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -325,11 +325,8 @@ struct pch_vbus_gpio_data { * @pdev: reference to the PCI device * @ep: array of endpoints * @lock: protects all state - * @active: enabled the PCI device * @stall: stall requested * @prot_stall: protcol stall requested - * @irq_registered: irq registered with system - * @mem_region: device memory mapped * @registered: driver registered with system * @suspended: driver in suspended state * @connected: gadget driver associated @@ -339,12 +336,8 @@ struct pch_vbus_gpio_data { * @data_requests: DMA pool for data requests * @stp_requests: DMA pool for setup requests * @dma_addr: DMA pool for received - * @ep0out_buf: Buffer for DMA * @setup_data: Received setup data - * @phys_addr: of device memory * @base_addr: for mapped device memory - * @bar: Indicates which PCI BAR for USB regs - * @irq: IRQ line for the device * @cfg_data: current cfg, intf, and alt in use * @vbus_gpio: GPIO informaton for detecting VBUS */ @@ -354,11 +347,9 @@ struct pch_udc_dev { struct pci_dev *pdev; struct pch_udc_ep ep[PCH_UDC_EP_NUM]; spinlock_t lock; /* protects all state */ - unsigned active:1, + unsigned stall:1, prot_stall:1, - irq_registered:1, - mem_region:1, suspended:1, connected:1, vbus_session:1, @@ -367,12 +358,8 @@ struct pch_udc_dev { struct pci_pool *data_requests; struct pci_pool *stp_requests; dma_addr_t dma_addr; - void *ep0out_buf; struct usb_ctrlrequest setup_data; - unsigned long phys_addr; void __iomem *base_addr; - unsigned bar; - unsigned irq; struct pch_udc_cfg_data cfg_data; struct pch_vbus_gpio_data vbus_gpio; }; @@ -2949,6 +2936,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) { struct pch_udc_stp_dma_desc *td_stp; struct pch_udc_data_dma_desc *td_data; + void *ep0out_buf; /* DMA setup */ dev->data_requests = pci_pool_create("data_requests", dev->pdev, @@ -2991,10 +2979,11 @@ static int init_dma_pools(struct pch_udc_dev *dev) dev->ep[UDC_EP0IN_IDX].td_data = NULL; dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; - dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL); - if (!dev->ep0out_buf) + ep0out_buf = devm_kzalloc(&dev->pdev->dev, UDC_EP0OUT_BUFF_SIZE * 4, + GFP_KERNEL); + if (!ep0out_buf) return -ENOMEM; - dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf, + dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf, UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); return 0; @@ -3078,22 +3067,10 @@ static void pch_udc_remove(struct pci_dev *pdev) if (dev->dma_addr) dma_unmap_single(&dev->pdev->dev, dev->dma_addr, UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); - kfree(dev->ep0out_buf); pch_vbus_gpio_free(dev); pch_udc_exit(dev); - - if (dev->irq_registered) - free_irq(pdev->irq, dev); - if (dev->base_addr) - iounmap(dev->base_addr); - if (dev->mem_region) - release_mem_region(dev->phys_addr, - pci_resource_len(pdev, dev->bar)); - if (dev->active) - pci_disable_device(pdev); - kfree(dev); } #ifdef CONFIG_PM_SLEEP @@ -3122,69 +3099,46 @@ static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume); static int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - unsigned long resource; - unsigned long len; + int bar; int retval; struct pch_udc_dev *dev; /* init */ - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (!dev) { - pr_err("%s: no memory for device structure\n", __func__); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) return -ENOMEM; - } + /* pci setup */ - if (pci_enable_device(pdev) < 0) { - kfree(dev); - pr_err("%s: pci_enable_device failed\n", __func__); - return -ENODEV; - } - dev->active = 1; + retval = pcim_enable_device(pdev); + if (retval) + return retval; + pci_set_drvdata(pdev, dev); /* Determine BAR based on PCI ID */ if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC) - dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000; + bar = PCH_UDC_PCI_BAR_QUARK_X1000; else - dev->bar = PCH_UDC_PCI_BAR; + bar = PCH_UDC_PCI_BAR; /* PCI resource allocation */ - resource = pci_resource_start(pdev, dev->bar); - len = pci_resource_len(pdev, dev->bar); + retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev)); + if (retval) + return retval; - if (!request_mem_region(resource, len, KBUILD_MODNAME)) { - dev_err(&pdev->dev, "%s: pci device used already\n", __func__); - retval = -EBUSY; - goto finished; - } - dev->phys_addr = resource; - dev->mem_region = 1; + dev->base_addr = pcim_iomap_table(pdev)[bar]; - dev->base_addr = ioremap_nocache(resource, len); - if (!dev->base_addr) { - pr_err("%s: device memory cannot be mapped\n", __func__); - retval = -ENOMEM; - goto finished; - } - if (!pdev->irq) { - dev_err(&pdev->dev, "%s: irq not set\n", __func__); - retval = -ENODEV; - goto finished; - } /* initialize the hardware */ - if (pch_udc_pcd_init(dev)) { - retval = -ENODEV; - goto finished; - } - if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, - dev)) { + if (pch_udc_pcd_init(dev)) + return -ENODEV; + + retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (retval) { dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__, pdev->irq); - retval = -ENODEV; goto finished; } - dev->irq = pdev->irq; - dev->irq_registered = 1; pci_set_master(pdev); pci_try_set_mwi(pdev); -- cgit v1.2.3 From c7b640d2a21c2dd724cd8aa9f0b78d6a3d61d776 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:36 +0200 Subject: usb: gadget: pch_udc: enable MSI if hardware supports Try to enable MSI in case hardware supports it. At least Intel Quark is known SoC which indeed does. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 82e01f8995c5..787f459e9e90 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -3132,6 +3132,8 @@ static int pch_udc_probe(struct pci_dev *pdev, if (pch_udc_pcd_init(dev)) return -ENODEV; + pci_enable_msi(pdev); + retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, dev); if (retval) { -- cgit v1.2.3 From 6b968737c3efe7cdaa5407afec972cd7c7d3ca35 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:37 +0200 Subject: usb: gadged: pch_udc: get rid of redundant assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems there are leftovers of some assignments which are not used anymore. Compiler even warns us about: drivers/usb/gadget/udc/pch_udc.c:2022:22: warning: variable ‘dev’ set \ but not used [-Wunused-but-set-variable] drivers/usb/gadget/udc/pch_udc.c:2639:9: warning: variable ‘ret’ set \ but not used [-Wunused-but-set-variable] Remove them and shut compiler about. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 787f459e9e90..d6d1418bdd63 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1719,14 +1719,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if ((usbep->name == ep0_string) || !ep->ep.desc) return -EINVAL; @@ -1757,12 +1755,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, struct pch_udc_request *req; struct pch_udc_ep *ep; struct pch_udc_data_dma_desc *dma_desc; - struct pch_udc_dev *dev; if (!usbep) return NULL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; req = kzalloc(sizeof *req, gfp); if (!req) return NULL; @@ -1935,12 +1931,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, { struct pch_udc_ep *ep; struct pch_udc_request *req; - struct pch_udc_dev *dev; unsigned long flags; int ret = -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!usbep || !usbreq || (!ep->ep.desc && ep->num)) return ret; req = container_of(usbreq, struct pch_udc_request, req); @@ -1972,14 +1966,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; int ret; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -2017,14 +2009,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; int ret; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -2634,7 +2624,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev) static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) { u32 reg, dev_stat = 0; - int i, ret; + int i; dev_stat = pch_udc_read_device_status(dev); dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >> @@ -2663,7 +2653,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) } dev->stall = 0; spin_lock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); } @@ -2674,7 +2664,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) */ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) { - int i, ret; + int i; u32 reg, dev_stat = 0; dev_stat = pch_udc_read_device_status(dev); @@ -2700,7 +2690,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) /* call gadget zero with setup data received */ spin_lock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); } -- cgit v1.2.3 From e4875bd4829c1a945bc4714ca806a823a169f3a1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:38 +0200 Subject: usb: gadget: pch_udc: sort IDs Sort IDs in groups to be easily found when needed. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index d6d1418bdd63..b2b70d4e2f5b 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -367,8 +367,10 @@ struct pch_udc_dev { #define PCH_UDC_PCI_BAR_QUARK_X1000 0 #define PCH_UDC_PCI_BAR 1 -#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 + #define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939 +#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 + #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D #define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 -- cgit v1.2.3 From 5096c4d3bfa75bdd23c78f799aabd08598afb48f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 Apr 2016 16:53:38 +0900 Subject: usb: gadget: udc: core: Fix argument of dev_err() in usb_gadget_map_request() The argument of dev_err() in usb_gadget_map_request() should be dev instead of &gadget->dev. Fixes: 7ace8fc ("usb: gadget: udc: core: Fix argument of dma_map_single for IOMMU") Cc: # v4.3+ Signed-off-by: Yoshihiro Shimoda --- drivers/usb/gadget/udc/udc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e4e70e11d0f6..c6e76465065a 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -75,7 +75,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget, mapped = dma_map_sg(dev, req->sg, req->num_sgs, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (mapped == 0) { - dev_err(&gadget->dev, "failed to map SGs\n"); + dev_err(dev, "failed to map SGs\n"); return -EFAULT; } -- cgit v1.2.3 From 679ca39fc670a5a95c2b40d2cc8cf2cee2486f7a Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 Apr 2016 16:53:39 +0900 Subject: usb: gadget: udc: core: add usb_gadget_{un}map_request_by_dev() If the following environment, the first argument of DMA API should be set to a DMAC's device structure, not a udc controller's one. - A udc controller needs an external DMAC device (like a DMA Engine). - The external DMAC enables IOMMU. So, this patch add usb_gadget_{un}map_request_by_dev() API to set a DMAC's device structure by a udc controller driver. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/udc-core.c | 24 ++++++++++++++++++------ include/linux/usb/gadget.h | 4 ++++ 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index c6e76465065a..6e8300d6a737 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc, #ifdef CONFIG_HAS_DMA -int usb_gadget_map_request(struct usb_gadget *gadget, +int usb_gadget_map_request_by_dev(struct device *dev, struct usb_request *req, int is_in) { - struct device *dev = gadget->dev.parent; - if (req->length == 0) return 0; @@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget, return 0; } +EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); + +int usb_gadget_map_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); +} EXPORT_SYMBOL_GPL(usb_gadget_map_request); -void usb_gadget_unmap_request(struct usb_gadget *gadget, +void usb_gadget_unmap_request_by_dev(struct device *dev, struct usb_request *req, int is_in) { if (req->length == 0) return; if (req->num_mapped_sgs) { - dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs, + dma_unmap_sg(dev, req->sg, req->num_mapped_sgs, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->num_mapped_sgs = 0; } else { - dma_unmap_single(gadget->dev.parent, req->dma, req->length, + dma_unmap_single(dev, req->dma, req->length, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } } +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); + +void usb_gadget_unmap_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); +} EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); #endif /* CONFIG_HAS_DMA */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 5d4e151c49bf..457651bf45b0 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1223,9 +1223,13 @@ int usb_otg_descriptor_init(struct usb_gadget *gadget, /* utility to simplify map/unmap of usb_requests to/from DMA */ +extern int usb_gadget_map_request_by_dev(struct device *dev, + struct usb_request *req, int is_in); extern int usb_gadget_map_request(struct usb_gadget *gadget, struct usb_request *req, int is_in); +extern void usb_gadget_unmap_request_by_dev(struct device *dev, + struct usb_request *req, int is_in); extern void usb_gadget_unmap_request(struct usb_gadget *gadget, struct usb_request *req, int is_in); -- cgit v1.2.3 From 9bc07890f891267285716c09bfee58e239137d36 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Apr 2016 15:05:12 +0200 Subject: usb: gadget: r8a66597-udc: Deinline pipe_change, save 2176 bytes This function compiles to 298 bytes of machine code, has ~10 callsites. This is a USB 2.0 device, USB 2.0 is limited to ~40 MB/s, so should be almost never CPU bound. No need to optimize for speed this agressively. Signed-off-by: Denys Vlasenko CC: Felipe Balbi CC: linux-usb@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/r8a66597-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index baa0609a429d..8b300e6da7fc 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum, } while ((tmp & mask) != loop); } -static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) +static void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; -- cgit v1.2.3 From 332a5b446b7916d272c2a659a3b20909ce34d2c1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 30 Mar 2016 13:49:14 +0200 Subject: usb: gadget: f_fs: Fix EFAULT generation for async read operations In the current implementation functionfs generates a EFAULT for async read operations if the read buffer size is larger than the URB data size. Since a application does not necessarily know how much data the host side is going to send it typically supplies a buffer larger than the actual data, which will then result in a EFAULT error. This behaviour was introduced while refactoring the code to use iov_iter interface in commit c993c39b8639 ("gadget/function/f_fs.c: use put iov_iter into io_data"). The original code took the minimum over the URB size and the user buffer size and then attempted to copy that many bytes using copy_to_user(). If copy_to_user() could not copy all data a EFAULT error was generated. Restore the original behaviour by only generating a EFAULT error when the number of bytes copied is not the size of the URB and the target buffer has not been fully filled. Commit 342f39a6c8d3 ("usb: gadget: f_fs: fix check in read operation") already fixed the same problem for the synchronous read path. Fixes: c993c39b8639 ("gadget/function/f_fs.c: use put iov_iter into io_data") Acked-by: Michal Nazarewicz Signed-off-by: Lars-Peter Clausen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e21ca2bd6839..2c314c13f9a7 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -650,7 +650,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read && ret > 0) { use_mm(io_data->mm); ret = copy_to_iter(io_data->buf, ret, &io_data->data); - if (iov_iter_count(&io_data->data)) + if (ret != io_data->req->actual && iov_iter_count(&io_data->data)) ret = -EFAULT; unuse_mm(io_data->mm); } -- cgit v1.2.3 From f78bbcae86e676fad9e6c6bb6cd9d9868ba23696 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 8 Apr 2016 10:24:11 +0200 Subject: usb: f_mass_storage: test whether thread is running before starting another MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When binding the function to usb_configuration, check whether the thread is running before starting another one. Without that, when function instance is added to multiple configurations, fsg_bing starts multiple threads with all but the latest one being forgotten by the driver. This leads to obvious thread leaks, possible lockups when trying to halt the machine and possible more issues. This fixes issues with legacy/multi¹ gadget as well as configfs gadgets when mass_storage function is added to multiple configurations. This change also simplifies API since the legacy gadgets no longer need to worry about starting the thread by themselves (which was where bug in legacy/multi was in the first place). N.B., this patch doesn’t address adding single mass_storage function instance to a single configuration twice. Thankfully, there’s no legitimate reason for such setup plus, if I’m not mistaken, configfs gadget doesn’t even allow it to be expressed. ¹ I have no example failure though. Conclusion that legacy/multi has a bug is based purely on me reading the code. Acked-by: Alan Stern Signed-off-by: Michal Nazarewicz Tested-by: Ivaylo Dimitrov Cc: Alan Stern Cc: Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 36 ++++++++++++---------------- drivers/usb/gadget/function/f_mass_storage.h | 2 -- drivers/usb/gadget/legacy/acm_ms.c | 4 ---- drivers/usb/gadget/legacy/mass_storage.c | 4 ---- drivers/usb/gadget/legacy/multi.c | 12 ---------- drivers/usb/gadget/legacy/nokia.c | 7 ------ 6 files changed, 15 insertions(+), 50 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index acf210f16328..5c6d4d7ca605 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, } EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); -int fsg_common_run_thread(struct fsg_common *common) -{ - common->state = FSG_STATE_IDLE; - /* Tell the thread to start working */ - common->thread_task = - kthread_create(fsg_main_thread, common, "file-storage"); - if (IS_ERR(common->thread_task)) { - common->state = FSG_STATE_TERMINATED; - return PTR_ERR(common->thread_task); - } - - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); - - wake_up_process(common->thread_task); - - return 0; -} -EXPORT_SYMBOL_GPL(fsg_common_run_thread); - static void fsg_common_release(struct kref *ref) { struct fsg_common *common = container_of(ref, struct fsg_common, ref); @@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref) if (common->state != FSG_STATE_TERMINATED) { raise_exception(common, FSG_STATE_EXIT); wait_for_completion(&common->thread_notifier); + common->thread_task = NULL; } for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { @@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) if (ret) return ret; fsg_common_set_inquiry_string(fsg->common, NULL, NULL); - ret = fsg_common_run_thread(fsg->common); - if (ret) + } + + if (!common->thread_task) { + common->state = FSG_STATE_IDLE; + common->thread_task = + kthread_create(fsg_main_thread, common, "file-storage"); + if (IS_ERR(common->thread_task)) { + int ret = PTR_ERR(common->thread_task); + common->thread_task = NULL; + common->state = FSG_STATE_TERMINATED; return ret; + } + DBG(common, "I/O thread pid: %d\n", + task_pid_nr(common->thread_task)); + wake_up_process(common->thread_task); } fsg->gadget = gadget; diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index 445df6775609..b6a9918eaefb 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, const char *pn); -int fsg_common_run_thread(struct fsg_common *common); - void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c16089efc322..c39de65a448b 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c) if (status < 0) goto put_msg; - status = fsg_common_run_thread(opts->common); - if (status) - goto remove_acm; - status = usb_add_function(c, f_msg); if (status) goto remove_acm; diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index e61af53c7d2b..125974f32f50 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c) if (IS_ERR(f_msg)) return PTR_ERR(f_msg); - ret = fsg_common_run_thread(opts->common); - if (ret) - goto put_func; - ret = usb_add_function(c, f_msg); if (ret) goto put_func; diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index 229d704a620b..a70a406580ea 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis; static int rndis_do_config(struct usb_configuration *c) { - struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c) goto err_fsg; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - ret = fsg_common_run_thread(fsg_opts->common); - if (ret) - goto err_run; - ret = usb_add_function(c, f_msg_rndis); if (ret) goto err_run; @@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi; static int cdc_do_config(struct usb_configuration *c) { - struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c) goto err_fsg; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - ret = fsg_common_run_thread(fsg_opts->common); - if (ret) - goto err_run; - ret = usb_add_function(c, f_msg_multi); if (ret) goto err_run; diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 09975046c694..b1e535f4022e 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c) struct usb_function *f_ecm; struct usb_function *f_obex2 = NULL; struct usb_function *f_msg; - struct fsg_opts *fsg_opts; int status = 0; int obex1_stat = -1; int obex2_stat = -1; @@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c) goto err_ecm; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - - status = fsg_common_run_thread(fsg_opts->common); - if (status) - goto err_msg; - status = usb_add_function(c, f_msg); if (status) goto err_msg; -- cgit v1.2.3 From 097aa1975e9a5b189d4c6fbc95c0f97e2c49c01e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 18 Apr 2016 12:57:15 +0300 Subject: usb: gadget: pch_udc: don't free devm allocated memory Coccinelle caught this instance of us kfree()ing devm-allocated memory. The solution is just to not do anything in our gadget_release. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index b2b70d4e2f5b..ebc51ec5790a 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -2834,17 +2834,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev) UDC_DEVINT_SI | UDC_DEVINT_SC); } -/** - * gadget_release() - Free the gadget driver private data - * @pdev reference to struct pci_dev - */ -static void gadget_release(struct device *pdev) -{ - struct pch_udc_dev *dev = dev_get_drvdata(pdev); - - kfree(dev); -} - /** * pch_udc_pcd_reinit() - This API initializes the endpoint structures * @dev: Reference to the driver structure @@ -3151,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev, /* Put the device in disconnected state till a driver is bound */ pch_udc_set_disconnect(dev); - retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, - gadget_release); + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); if (retval) goto finished; return 0; -- cgit v1.2.3 From 0878263b68df372e6389b050fc2bd4f6d5b9f332 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 22 Apr 2016 14:53:47 +0300 Subject: usb: gadget: composite: avoid kernel oops with bad gadgets If a gadget driver loaded to a Superspeed-capable peripheral controller, using a Superspeed cable, doesn't provide Superspeed descriptors, we will get a NULL pointer dereference. In order to avoid that situation, we will try to find any valid descriptors we can. If no set of descriptors is passed in, then we'll let that gadget oops anyhow. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index de9ffd60fcfa..3d3cdc5ed20d 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f, { struct usb_descriptor_header **descriptors; + /* + * NOTE: we try to help gadget drivers which might not be setting + * max_speed appropriately. + */ + switch (speed) { case USB_SPEED_SUPER_PLUS: descriptors = f->ssp_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ case USB_SPEED_SUPER: descriptors = f->ss_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ case USB_SPEED_HIGH: descriptors = f->hs_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ default: descriptors = f->fs_descriptors; } + /* + * if we can't find any descriptors at all, then this gadget deserves to + * Oops with a NULL pointer dereference + */ + return descriptors; } -- cgit v1.2.3