From be9d39881fc4fa39a64b6eed6bab5d9ee5125344 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 2 Jun 2015 13:03:36 -0500 Subject: [PATCH 01/11] usb: musb: host: rely on port_mode to call musb_start() Currently, we're calling musb_start() twice for DRD ports in some situations. This has been observed to cause enumeration issues after suspend/resume cycles with AM335x. In order to fix the problem, we just have to fix the check on musb_has_gadget() so that it only returns true if current mode is Host and ignore the fact that we have or not a gadget driver loaded. Fixes: ae44df2e21b5 (usb: musb: call musb_start() only once in OTG mode) Cc: Sebastian Andrzej Siewior Cc: # v3.11+ Tested-by: Sekhar Nori Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_virthub.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 30842bc195f5..92d5f718659b 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -275,9 +275,7 @@ static int musb_has_gadget(struct musb *musb) #ifdef CONFIG_USB_MUSB_HOST return 1; #else - if (musb->port_mode == MUSB_PORT_MODE_HOST) - return 1; - return musb->g.dev.driver != NULL; + return musb->port_mode == MUSB_PORT_MODE_HOST; #endif } From b58e6ceef96f2fbcb1698b0a7c7df59fdea0aa32 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Mon, 29 Jun 2015 11:05:28 +0200 Subject: [PATCH 02/11] usb: dwc2: host: allocate qh before atomic enqueue To avoid sleep while atomic bugs, allocate qh before calling dwc2_hcd_urb_enqueue. qh pointer can be used directly now instead of passing ep->hcpriv as double pointer. Acked-by: John Youn Tested-by: Heiko Stuebner Tested-by: Doug Anderson Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 31 ++++++++++++++++++++--- drivers/usb/dwc2/hcd.h | 5 +++- drivers/usb/dwc2/hcd_queue.c | 49 +++++++++--------------------------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index b10377c65064..80bce711bc14 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -359,7 +359,7 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg) /* Caller must hold driver lock */ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, - struct dwc2_hcd_urb *urb, void **ep_handle, + struct dwc2_hcd_urb *urb, struct dwc2_qh *qh, gfp_t mem_flags) { struct dwc2_qtd *qtd; @@ -391,8 +391,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, return -ENOMEM; dwc2_hcd_qtd_init(qtd, urb); - retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle, - mem_flags); + retval = dwc2_hcd_qtd_add(hsotg, qtd, qh); if (retval) { dev_err(hsotg->dev, "DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n", @@ -2445,6 +2444,8 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, u32 tflags = 0; void *buf; unsigned long flags; + struct dwc2_qh *qh; + bool qh_allocated = false; if (dbg_urb(urb)) { dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n"); @@ -2523,13 +2524,24 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, urb->iso_frame_desc[i].length); urb->hcpriv = dwc2_urb; + qh = (struct dwc2_qh *) ep->hcpriv; + /* Create QH for the endpoint if it doesn't exist */ + if (!qh) { + qh = dwc2_hcd_qh_create(hsotg, dwc2_urb, mem_flags); + if (!qh) { + retval = -ENOMEM; + goto fail0; + } + ep->hcpriv = qh; + qh_allocated = true; + } spin_lock_irqsave(&hsotg->lock, flags); retval = usb_hcd_link_urb_to_ep(hcd, urb); if (retval) goto fail1; - retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags); + retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, mem_flags); if (retval) goto fail2; @@ -2549,6 +2561,17 @@ fail2: fail1: spin_unlock_irqrestore(&hsotg->lock, flags); urb->hcpriv = NULL; + if (qh_allocated) { + struct dwc2_qtd *qtd2, *qtd2_tmp; + + ep->hcpriv = NULL; + dwc2_hcd_qh_unlink(hsotg, qh); + /* Free each QTD in the QH's QTD list */ + list_for_each_entry_safe(qtd2, qtd2_tmp, &qh->qtd_list, + qtd_list_entry) + dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh); + dwc2_hcd_qh_free(hsotg, qh); + } fail0: kfree(dwc2_urb); diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 7b5841c40033..fc1054965552 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -463,6 +463,9 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, /* Schedule Queue Functions */ /* Implemented in hcd_queue.c */ extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg); +extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, + struct dwc2_hcd_urb *urb, + gfp_t mem_flags); extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); @@ -471,7 +474,7 @@ extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb); extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, - struct dwc2_qh **qh, gfp_t mem_flags); + struct dwc2_qh *qh); /* Unlinks and frees a QTD */ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 9b5c36256627..3ad63d392e13 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -191,7 +191,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * * Return: Pointer to the newly allocated QH, or NULL on error */ -static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, +struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, struct dwc2_hcd_urb *urb, gfp_t mem_flags) { @@ -767,57 +767,32 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb) * * @hsotg: The DWC HCD structure * @qtd: The QTD to add - * @qh: Out parameter to return queue head - * @atomic_alloc: Flag to do atomic alloc if needed + * @qh: Queue head to add qtd to * * Return: 0 if successful, negative error code otherwise * - * Finds the correct QH to place the QTD into. If it does not find a QH, it - * will create a new QH. If the QH to which the QTD is added is not currently - * scheduled, it is placed into the proper schedule based on its EP type. + * If the QH to which the QTD is added is not currently scheduled, it is placed + * into the proper schedule based on its EP type. */ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, - struct dwc2_qh **qh, gfp_t mem_flags) + struct dwc2_qh *qh) { - struct dwc2_hcd_urb *urb = qtd->urb; - int allocated = 0; int retval; - /* - * Get the QH which holds the QTD-list to insert to. Create QH if it - * doesn't exist. - */ - if (*qh == NULL) { - *qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags); - if (*qh == NULL) - return -ENOMEM; - allocated = 1; + if (unlikely(!qh)) { + dev_err(hsotg->dev, "%s: Invalid QH\n", __func__); + retval = -EINVAL; + goto fail; } - retval = dwc2_hcd_qh_add(hsotg, *qh); + retval = dwc2_hcd_qh_add(hsotg, qh); if (retval) goto fail; - qtd->qh = *qh; - list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list); + qtd->qh = qh; + list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list); return 0; - fail: - if (allocated) { - struct dwc2_qtd *qtd2, *qtd2_tmp; - struct dwc2_qh *qh_tmp = *qh; - - *qh = NULL; - dwc2_hcd_qh_unlink(hsotg, qh_tmp); - - /* Free each QTD in the QH's QTD list */ - list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list, - qtd_list_entry) - dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp); - - dwc2_hcd_qh_free(hsotg, qh_tmp); - } - return retval; } From b5a468a6aa1ca9176594cd603760d80fa1e8b15e Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Mon, 29 Jun 2015 11:05:29 +0200 Subject: [PATCH 03/11] usb: dwc2: host: allocate qtd before atomic enqueue To avoid sleep while atomic bugs, allocate qtd before calling dwc2_hcd_urb_enqueue. No need to pass mem_flags to dwc2_hcd_urb_enqueue any more as no memory allocations are done in it. Acked-by: John Youn Tested-by: Heiko Stuebner Tested-by: Doug Anderson Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 80bce711bc14..f845c41fe9e5 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -360,9 +360,8 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg) /* Caller must hold driver lock */ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, struct dwc2_hcd_urb *urb, struct dwc2_qh *qh, - gfp_t mem_flags) + struct dwc2_qtd *qtd) { - struct dwc2_qtd *qtd; u32 intr_mask; int retval; int dev_speed; @@ -386,9 +385,8 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, return -ENODEV; } - qtd = kzalloc(sizeof(*qtd), mem_flags); if (!qtd) - return -ENOMEM; + return -EINVAL; dwc2_hcd_qtd_init(qtd, urb); retval = dwc2_hcd_qtd_add(hsotg, qtd, qh); @@ -396,7 +394,6 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, dev_err(hsotg->dev, "DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n", retval); - kfree(qtd); return retval; } @@ -2446,6 +2443,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, unsigned long flags; struct dwc2_qh *qh; bool qh_allocated = false; + struct dwc2_qtd *qtd; if (dbg_urb(urb)) { dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n"); @@ -2536,15 +2534,21 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, qh_allocated = true; } + qtd = kzalloc(sizeof(*qtd), mem_flags); + if (!qtd) { + retval = -ENOMEM; + goto fail1; + } + spin_lock_irqsave(&hsotg->lock, flags); retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) - goto fail1; - - retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, mem_flags); if (retval) goto fail2; + retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, qtd); + if (retval) + goto fail3; + if (alloc_bandwidth) { dwc2_allocate_bus_bandwidth(hcd, dwc2_hcd_get_ep_bandwidth(hsotg, ep), @@ -2555,12 +2559,14 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, return 0; -fail2: +fail3: dwc2_urb->priv = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); -fail1: +fail2: spin_unlock_irqrestore(&hsotg->lock, flags); urb->hcpriv = NULL; + kfree(qtd); +fail1: if (qh_allocated) { struct dwc2_qtd *qtd2, *qtd2_tmp; From cc1e204cb092da8495fe2c24bdc4543c259d6b34 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Mon, 29 Jun 2015 11:05:30 +0200 Subject: [PATCH 04/11] usb: dwc2: embed storage for reg backup in struct dwc2_hsotg Register backup function can be called from atomic context. Instead of using atomic memory pool, embed backup storage space in struct dwc2_hsotg. Also add a valid flag in each struct as NULL pointer can't be used as the content validity check any more. Acked-by: John Youn Tested-by: Heiko Stuebner Tested-by: Doug Anderson Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.c | 55 +++++++++++------------------------------ drivers/usb/dwc2/core.h | 9 ++++--- 2 files changed, 21 insertions(+), 43 deletions(-) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index e5b546f1152e..c3cc1a78d1e2 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -72,17 +72,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "%s\n", __func__); /* Backup Host regs */ - hr = hsotg->hr_backup; - if (!hr) { - hr = devm_kzalloc(hsotg->dev, sizeof(*hr), GFP_KERNEL); - if (!hr) { - dev_err(hsotg->dev, "%s: can't allocate host regs\n", - __func__); - return -ENOMEM; - } - - hsotg->hr_backup = hr; - } + hr = &hsotg->hr_backup; hr->hcfg = readl(hsotg->regs + HCFG); hr->haintmsk = readl(hsotg->regs + HAINTMSK); for (i = 0; i < hsotg->core_params->host_channels; ++i) @@ -90,6 +80,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) hr->hprt0 = readl(hsotg->regs + HPRT0); hr->hfir = readl(hsotg->regs + HFIR); + hr->valid = true; return 0; } @@ -109,12 +100,13 @@ static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "%s\n", __func__); /* Restore host regs */ - hr = hsotg->hr_backup; - if (!hr) { + hr = &hsotg->hr_backup; + if (!hr->valid) { dev_err(hsotg->dev, "%s: no host registers to restore\n", __func__); return -EINVAL; } + hr->valid = false; writel(hr->hcfg, hsotg->regs + HCFG); writel(hr->haintmsk, hsotg->regs + HAINTMSK); @@ -152,17 +144,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "%s\n", __func__); /* Backup dev regs */ - dr = hsotg->dr_backup; - if (!dr) { - dr = devm_kzalloc(hsotg->dev, sizeof(*dr), GFP_KERNEL); - if (!dr) { - dev_err(hsotg->dev, "%s: can't allocate device regs\n", - __func__); - return -ENOMEM; - } - - hsotg->dr_backup = dr; - } + dr = &hsotg->dr_backup; dr->dcfg = readl(hsotg->regs + DCFG); dr->dctl = readl(hsotg->regs + DCTL); @@ -195,7 +177,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) dr->doeptsiz[i] = readl(hsotg->regs + DOEPTSIZ(i)); dr->doepdma[i] = readl(hsotg->regs + DOEPDMA(i)); } - + dr->valid = true; return 0; } @@ -215,12 +197,13 @@ static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "%s\n", __func__); /* Restore dev regs */ - dr = hsotg->dr_backup; - if (!dr) { + dr = &hsotg->dr_backup; + if (!dr->valid) { dev_err(hsotg->dev, "%s: no device registers to restore\n", __func__); return -EINVAL; } + dr->valid = false; writel(dr->dcfg, hsotg->regs + DCFG); writel(dr->dctl, hsotg->regs + DCTL); @@ -268,17 +251,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) int i; /* Backup global regs */ - gr = hsotg->gr_backup; - if (!gr) { - gr = devm_kzalloc(hsotg->dev, sizeof(*gr), GFP_KERNEL); - if (!gr) { - dev_err(hsotg->dev, "%s: can't allocate global regs\n", - __func__); - return -ENOMEM; - } - - hsotg->gr_backup = gr; - } + gr = &hsotg->gr_backup; gr->gotgctl = readl(hsotg->regs + GOTGCTL); gr->gintmsk = readl(hsotg->regs + GINTMSK); @@ -291,6 +264,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) for (i = 0; i < MAX_EPS_CHANNELS; i++) gr->dtxfsiz[i] = readl(hsotg->regs + DPTXFSIZN(i)); + gr->valid = true; return 0; } @@ -309,12 +283,13 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "%s\n", __func__); /* Restore global regs */ - gr = hsotg->gr_backup; - if (!gr) { + gr = &hsotg->gr_backup; + if (!gr->valid) { dev_err(hsotg->dev, "%s: no global registers to restore\n", __func__); return -EINVAL; } + gr->valid = false; writel(0xffffffff, hsotg->regs + GINTSTS); writel(gr->gotgctl, hsotg->regs + GOTGCTL); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 53b8de03f102..0ed87620941b 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -492,6 +492,7 @@ struct dwc2_gregs_backup { u32 gdfifocfg; u32 dtxfsiz[MAX_EPS_CHANNELS]; u32 gpwrdn; + bool valid; }; /** @@ -521,6 +522,7 @@ struct dwc2_dregs_backup { u32 doepctl[MAX_EPS_CHANNELS]; u32 doeptsiz[MAX_EPS_CHANNELS]; u32 doepdma[MAX_EPS_CHANNELS]; + bool valid; }; /** @@ -538,6 +540,7 @@ struct dwc2_hregs_backup { u32 hcintmsk[MAX_EPS_CHANNELS]; u32 hprt0; u32 hfir; + bool valid; }; /** @@ -705,9 +708,9 @@ struct dwc2_hsotg { struct work_struct wf_otg; struct timer_list wkp_timer; enum dwc2_lx_state lx_state; - struct dwc2_gregs_backup *gr_backup; - struct dwc2_dregs_backup *dr_backup; - struct dwc2_hregs_backup *hr_backup; + struct dwc2_gregs_backup gr_backup; + struct dwc2_dregs_backup dr_backup; + struct dwc2_hregs_backup hr_backup; struct dentry *debug_root; struct debugfs_regset32 *regset; From 43cacb03aabe62158d8e5da876054c7d48fc9963 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 1 Jul 2015 22:03:09 -0500 Subject: [PATCH 05/11] usb: dwc3: core: avoid NULL pointer dereference commit 3e10a2ce98d1 ("usb: dwc3: add hsphy_interface property") introduced a possible NULL pointer dereference because dwc->hsphy_interface can be NULL. In order to fix it, all we have to do is guard strncmp() against a NULL argument. Fixes: 3e10a2ce98d1 ("usb: dwc3: add hsphy_interface property") Tested-by: Murali Karicheri Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 5c110d8e293b..ff5773c66b84 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -446,10 +446,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc) /* Select the HS PHY interface */ switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI: - if (!strncmp(dwc->hsphy_interface, "utmi", 4)) { + if (dwc->hsphy_interface && + !strncmp(dwc->hsphy_interface, "utmi", 4)) { reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI; break; - } else if (!strncmp(dwc->hsphy_interface, "ulpi", 4)) { + } else if (dwc->hsphy_interface && + !strncmp(dwc->hsphy_interface, "ulpi", 4)) { reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } else { From 8515bac01a983d277148e4fcc5f235bf603de577 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 19 Jun 2015 23:56:34 +0200 Subject: [PATCH 06/11] usb: f_mass_storage: limit number of reported LUNs Mass storage function created via configfs always reports eight LUNs to the hosts even if only one LUN has been configured. Adjust the number when the USB function is allocated based on LUNs that user has created. Cc: Tested-by: Gregory CLEMENT Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index d2259c663996..f936268d26c6 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2786,7 +2786,7 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns) return -EINVAL; } - curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); + curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL); if (unlikely(!curlun)) return -ENOMEM; @@ -2796,8 +2796,6 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns) common->luns = curlun; common->nluns = nluns; - pr_info("Number of LUNs=%d\n", common->nluns); - return 0; } EXPORT_SYMBOL_GPL(fsg_common_set_nluns); @@ -3563,14 +3561,26 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) struct fsg_opts *opts = fsg_opts_from_func_inst(fi); struct fsg_common *common = opts->common; struct fsg_dev *fsg; + unsigned nluns, i; fsg = kzalloc(sizeof(*fsg), GFP_KERNEL); if (unlikely(!fsg)) return ERR_PTR(-ENOMEM); mutex_lock(&opts->lock); + if (!opts->refcnt) { + for (nluns = i = 0; i < FSG_MAX_LUNS; ++i) + if (common->luns[i]) + nluns = i + 1; + if (!nluns) + pr_warn("No LUNS defined, continuing anyway\n"); + else + common->nluns = nluns; + pr_info("Number of LUNs=%u\n", common->nluns); + } opts->refcnt++; mutex_unlock(&opts->lock); + fsg->function.name = FSG_DRIVER_DESC; fsg->function.bind = fsg_bind; fsg->function.unbind = fsg_unbind; From 4088acf1e845aba35f30fb91dee10649edbd0e84 Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Mon, 18 May 2015 16:02:07 +0100 Subject: [PATCH 07/11] usb: gadget: f_fs: do not set cancel function on synchronous {read,write} do not try to set cancel function in synchronous operations in ffs_epfile_{read,write}_iter. Cc: # v4.0+ Acked-by: Al Viro Signed-off-by: Rui Miguel Silva Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 45b8c8b338df..6e7be91e6097 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -924,7 +924,8 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) kiocb->private = p; - kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + if (p->aio) + kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); res = ffs_epfile_io(kiocb->ki_filp, p); if (res == -EIOCBQUEUED) @@ -968,7 +969,8 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) kiocb->private = p; - kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + if (p->aio) + kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); res = ffs_epfile_io(kiocb->ki_filp, p); if (res == -EIOCBQUEUED) From b4c21f0bdd2c0cd5d5be1bb56f0a28dae5041eed Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 11 Jun 2015 22:12:11 +0530 Subject: [PATCH 08/11] usb: gadget: composite: Fix NULL pointer dereference commit f563d230903210acc ("usb: gadget: composite: add req_match method to usb_function") accesses cdev->config even before set config is invoked causing a NULL pointer dereferencing error while running Lecroy Mass Storage Compliance test. Fix it here by accessing cdev->config only if it is non NULL. Fixes: commit f563d230903210acc ("usb: gadget: composite: add req_match method to usb_function"). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 4e3447bbd097..58b4657fc721 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1758,10 +1758,13 @@ unknown: * take such requests too, if that's ever needed: to work * in config 0, etc. */ - list_for_each_entry(f, &cdev->config->functions, list) - if (f->req_match && f->req_match(f, ctrl)) - goto try_fun_setup; - f = NULL; + if (cdev->config) { + list_for_each_entry(f, &cdev->config->functions, list) + if (f->req_match && f->req_match(f, ctrl)) + goto try_fun_setup; + f = NULL; + } + switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) From 2184fe636b4e310cba52251971cee82cb2407a68 Mon Sep 17 00:00:00 2001 From: Takeshi Yoshimura Date: Sun, 14 Jun 2015 16:09:23 +0900 Subject: [PATCH 09/11] usb: gadget: udc: fix free_irq() after request_irq() failed My static checker detected the mistake. I fix this by changing "goto err_irq" to "goto err_req". The label err_irq is not used now so this patch also removes it. Signed-off-by: Takeshi Yoshimura Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fotg210-udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index e547ea7f56b1..1137e3384218 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -1171,7 +1171,7 @@ static int fotg210_udc_probe(struct platform_device *pdev) udc_name, fotg210); if (ret < 0) { pr_err("request_irq error (%d)\n", ret); - goto err_irq; + goto err_req; } ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget); @@ -1183,7 +1183,6 @@ static int fotg210_udc_probe(struct platform_device *pdev) return 0; err_add_udc: -err_irq: free_irq(ires->start, fotg210); err_req: From 543aa4867d4a2dff5fc11e1b688197ee3bad7f89 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 15 Jun 2015 04:37:00 +0000 Subject: [PATCH 10/11] usb: phy: mxs: suspend to RAM causes NULL pointer dereference Triggering suspend to RAM via sysfs on a i.MX28 causes a NULL pointer dereference. This patch avoids the oops in mxs_phy_get_vbus_status() by aborting since there is no syscon available. Signed-off-by: Stefan Wahren Fixes: efdbd3a5d6e ("usb: phy: mxs: do not set PWD.RXPWD1PT1 for low speed connection") CC: # 4.0 Acked-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mxs-usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 8f7cb068d29b..3fcc0483a081 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -217,6 +217,9 @@ static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy) { unsigned int vbus_value; + if (!mxs_phy->regmap_anatop) + return false; + if (mxs_phy->port_id == 0) regmap_read(mxs_phy->regmap_anatop, ANADIG_USB1_VBUS_DET_STAT, From b2e2c94b878be2500d4d42c1f52a2fa1fe7648b4 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 3 Jul 2015 14:02:29 +0200 Subject: [PATCH 11/11] usb: gadget: f_midi: fix error recovery path In case kstrdup() fails the resources to release are midi->in_port[] and midi. No cards have been registered, so no need to unregister any. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 6316aa5b1c49..ad50a67c1465 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1145,7 +1145,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) if (opts->id && !midi->id) { status = -ENOMEM; mutex_unlock(&opts->lock); - goto kstrdup_fail; + goto setup_fail; } midi->in_ports = opts->in_ports; midi->out_ports = opts->out_ports; @@ -1164,8 +1164,6 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) return &midi->func; -kstrdup_fail: - f_midi_unregister_card(midi); setup_fail: for (--i; i >= 0; i--) kfree(midi->in_port[i]);