From f28c42c576b293b3a1daaed8ca2775ebc2fe5398 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 24 May 2013 14:29:20 +0800 Subject: [PATCH 1/4] usb: dwc3: pci: PHY should be deleted later than dwc3 core If the glue layer is removed first (core layer later), it deletes the phy device first, then the core device. But at core's removal, it still uses PHY's resources, it may cause kernel's oops. It is much like the problem Paul Zimmerman reported at: http://marc.info/?l=linux-usb&m=136547502011472&w=2. Besides, it is reasonable the PHY is deleted at last as the controller is the PHY's user. Signed-off-by: Peter Chen Cc: Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 227d4a7acad7..eba9e2baf32b 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -196,9 +196,9 @@ static void dwc3_pci_remove(struct pci_dev *pci) { struct dwc3_pci *glue = pci_get_drvdata(pci); + platform_device_unregister(glue->dwc3); platform_device_unregister(glue->usb2_phy); platform_device_unregister(glue->usb3_phy); - platform_device_unregister(glue->dwc3); pci_set_drvdata(pci, NULL); pci_disable_device(pci); } From 022d0547aa8b00ff5035ba6207ebc2c08ea0a51f Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 24 May 2013 14:30:16 +0800 Subject: [PATCH 2/4] usb: dwc3: exynos: PHY should be deleted later than dwc3 core If the glue layer is removed first (core layer later), it deletes the phy device first, then the core device. But at core's removal, it still uses PHY's resources, it may cause kernel's oops. It is much like the problem Paul Zimmerman reported at: http://marc.info/?l=linux-usb&m=136547502011472&w=2. Besides, it is reasonable the PHY is deleted at last as the controller is the PHY's user. Signed-off-by: Peter Chen Cc: Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-exynos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 929e7dd6e58b..8ce9d7fd6cfc 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -164,9 +164,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev) { struct dwc3_exynos *exynos = platform_get_drvdata(pdev); + device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb3_phy); - device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); clk_disable_unprepare(exynos->clk); From 5bf8fae33d14cc5c3c53a926f9079f92c8b082b0 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Mon, 27 May 2013 14:35:49 +0530 Subject: [PATCH 3/4] usb: dwc3: gadget: free trb pool only from epnum 2 we never allocate a TRB pool for physical endpoints 0 and 1 so trying to free it (a invalid TRB pool pointer) will lead us in a warning while removing dwc3.ko module. In order to fix the situation, all we have to do is skip dwc3_free_trb_pool() for physical endpoints 0 and 1 just as we while deleting endpoints from the endpoints list. Cc: stable@vger.kernel.org Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2b6e7e001207..b5e5b35df49c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1706,11 +1706,19 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) dep = dwc->eps[epnum]; if (!dep) continue; - - dwc3_free_trb_pool(dep); - - if (epnum != 0 && epnum != 1) + /* + * Physical endpoints 0 and 1 are special; they form the + * bi-directional USB endpoint 0. + * + * For those two physical endpoints, we don't allocate a TRB + * pool nor do we add them the endpoints list. Due to that, we + * shouldn't do these two operations otherwise we would end up + * with all sorts of bugs when removing dwc3.ko. + */ + if (epnum != 0 && epnum != 1) { + dwc3_free_trb_pool(dep); list_del(&dep->endpoint.ep_list); + } kfree(dep); } From ed74df12dc3e07a37d99aab60211496e871488a0 Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Wed, 24 Apr 2013 08:38:48 +0200 Subject: [PATCH 4/4] usb: musb: make use_sg flag URB specific Since highmem PIO URB handling was introduced in: 8e8a551 usb: musb: host: Handle highmem in PIO mode when a URB is being handled it may happen that the static use_sg flag was set by a previous URB with buffer in highmem. This leads to error in handling the present URB. Fix this by making the use_sg flag URB specific. Cc: stable # 3.7+ Acked-by: Linus Walleij Signed-off-by: Virupax Sadashivpetimath Signed-off-by: Fabio Baltieri Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_host.c | 18 ++++++++---------- drivers/usb/musb/musb_host.h | 1 + 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 8914dec49f01..9d3044bdebe5 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1232,7 +1232,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) void __iomem *mbase = musb->mregs; struct dma_channel *dma; bool transfer_pending = false; - static bool use_sg; musb_ep_select(mbase, epnum); tx_csr = musb_readw(epio, MUSB_TXCSR); @@ -1463,9 +1462,9 @@ done: * NULL. */ if (!urb->transfer_buffer) - use_sg = true; + qh->use_sg = true; - if (use_sg) { + if (qh->use_sg) { /* sg_miter_start is already done in musb_ep_program */ if (!sg_miter_next(&qh->sg_miter)) { dev_err(musb->controller, "error: sg list empty\n"); @@ -1484,9 +1483,9 @@ done: qh->segsize = length; - if (use_sg) { + if (qh->use_sg) { if (offset + length >= urb->transfer_buffer_length) - use_sg = false; + qh->use_sg = false; } musb_ep_select(mbase, epnum); @@ -1552,7 +1551,6 @@ void musb_host_rx(struct musb *musb, u8 epnum) bool done = false; u32 status; struct dma_channel *dma; - static bool use_sg; unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG; musb_ep_select(mbase, epnum); @@ -1878,12 +1876,12 @@ void musb_host_rx(struct musb *musb, u8 epnum) * NULL. */ if (!urb->transfer_buffer) { - use_sg = true; + qh->use_sg = true; sg_miter_start(&qh->sg_miter, urb->sg, 1, sg_flags); } - if (use_sg) { + if (qh->use_sg) { if (!sg_miter_next(&qh->sg_miter)) { dev_err(musb->controller, "error: sg list empty\n"); sg_miter_stop(&qh->sg_miter); @@ -1913,8 +1911,8 @@ finish: urb->actual_length += xfer_len; qh->offset += xfer_len; if (done) { - if (use_sg) - use_sg = false; + if (qh->use_sg) + qh->use_sg = false; if (urb->status == -EINPROGRESS) urb->status = status; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 5a9c8feec10c..738f7eb60df9 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -74,6 +74,7 @@ struct musb_qh { u16 frame; /* for periodic schedule */ unsigned iso_idx; /* in urb->iso_frame_desc[] */ struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */ + bool use_sg; /* to track urb using sglist */ }; /* map from control or bulk queue head to the first qh on that ring */