Commit 61d5b3d6 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'fixes-for-v3.10-rc4' of...

Merge tag 'fixes-for-v3.10-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-linus

Felipe writes:

usb: fixes for v3.10-rc4

Fix for a long standing bug where we would try to free
resources which we never allocated for DWC3's physical
endpoints 0 and 1.

DWC3 also learned that when calling glue layer's ->remove()
method, ordering of the teardown logic matters. This fixes
a bug where we would try to act on bogus PHY resources.

Lastly, MUSB learns about proper URB handling when the URB's
buffer sits in highmen. In order to fix the bug, use_sg flag
is moved down to the URB.
parents e4aa937e ed74df12
...@@ -164,9 +164,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev) ...@@ -164,9 +164,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{ {
struct dwc3_exynos *exynos = platform_get_drvdata(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->usb2_phy);
platform_device_unregister(exynos->usb3_phy); platform_device_unregister(exynos->usb3_phy);
device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
clk_disable_unprepare(exynos->clk); clk_disable_unprepare(exynos->clk);
......
...@@ -196,9 +196,9 @@ static void dwc3_pci_remove(struct pci_dev *pci) ...@@ -196,9 +196,9 @@ static void dwc3_pci_remove(struct pci_dev *pci)
{ {
struct dwc3_pci *glue = pci_get_drvdata(pci); struct dwc3_pci *glue = pci_get_drvdata(pci);
platform_device_unregister(glue->dwc3);
platform_device_unregister(glue->usb2_phy); platform_device_unregister(glue->usb2_phy);
platform_device_unregister(glue->usb3_phy); platform_device_unregister(glue->usb3_phy);
platform_device_unregister(glue->dwc3);
pci_set_drvdata(pci, NULL); pci_set_drvdata(pci, NULL);
pci_disable_device(pci); pci_disable_device(pci);
} }
......
...@@ -1706,11 +1706,19 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) ...@@ -1706,11 +1706,19 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
dep = dwc->eps[epnum]; dep = dwc->eps[epnum];
if (!dep) if (!dep)
continue; continue;
/*
* 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); dwc3_free_trb_pool(dep);
if (epnum != 0 && epnum != 1)
list_del(&dep->endpoint.ep_list); list_del(&dep->endpoint.ep_list);
}
kfree(dep); kfree(dep);
} }
......
...@@ -1232,7 +1232,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) ...@@ -1232,7 +1232,6 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
struct dma_channel *dma; struct dma_channel *dma;
bool transfer_pending = false; bool transfer_pending = false;
static bool use_sg;
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR); tx_csr = musb_readw(epio, MUSB_TXCSR);
...@@ -1463,9 +1462,9 @@ void musb_host_tx(struct musb *musb, u8 epnum) ...@@ -1463,9 +1462,9 @@ void musb_host_tx(struct musb *musb, u8 epnum)
* NULL. * NULL.
*/ */
if (!urb->transfer_buffer) 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 */ /* sg_miter_start is already done in musb_ep_program */
if (!sg_miter_next(&qh->sg_miter)) { if (!sg_miter_next(&qh->sg_miter)) {
dev_err(musb->controller, "error: sg list empty\n"); dev_err(musb->controller, "error: sg list empty\n");
...@@ -1484,9 +1483,9 @@ void musb_host_tx(struct musb *musb, u8 epnum) ...@@ -1484,9 +1483,9 @@ void musb_host_tx(struct musb *musb, u8 epnum)
qh->segsize = length; qh->segsize = length;
if (use_sg) { if (qh->use_sg) {
if (offset + length >= urb->transfer_buffer_length) if (offset + length >= urb->transfer_buffer_length)
use_sg = false; qh->use_sg = false;
} }
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
...@@ -1552,7 +1551,6 @@ void musb_host_rx(struct musb *musb, u8 epnum) ...@@ -1552,7 +1551,6 @@ void musb_host_rx(struct musb *musb, u8 epnum)
bool done = false; bool done = false;
u32 status; u32 status;
struct dma_channel *dma; struct dma_channel *dma;
static bool use_sg;
unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG; unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
...@@ -1878,12 +1876,12 @@ void musb_host_rx(struct musb *musb, u8 epnum) ...@@ -1878,12 +1876,12 @@ void musb_host_rx(struct musb *musb, u8 epnum)
* NULL. * NULL.
*/ */
if (!urb->transfer_buffer) { if (!urb->transfer_buffer) {
use_sg = true; qh->use_sg = true;
sg_miter_start(&qh->sg_miter, urb->sg, 1, sg_miter_start(&qh->sg_miter, urb->sg, 1,
sg_flags); sg_flags);
} }
if (use_sg) { if (qh->use_sg) {
if (!sg_miter_next(&qh->sg_miter)) { if (!sg_miter_next(&qh->sg_miter)) {
dev_err(musb->controller, "error: sg list empty\n"); dev_err(musb->controller, "error: sg list empty\n");
sg_miter_stop(&qh->sg_miter); sg_miter_stop(&qh->sg_miter);
...@@ -1913,8 +1911,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) ...@@ -1913,8 +1911,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
urb->actual_length += xfer_len; urb->actual_length += xfer_len;
qh->offset += xfer_len; qh->offset += xfer_len;
if (done) { if (done) {
if (use_sg) if (qh->use_sg)
use_sg = false; qh->use_sg = false;
if (urb->status == -EINPROGRESS) if (urb->status == -EINPROGRESS)
urb->status = status; urb->status = status;
......
...@@ -74,6 +74,7 @@ struct musb_qh { ...@@ -74,6 +74,7 @@ struct musb_qh {
u16 frame; /* for periodic schedule */ u16 frame; /* for periodic schedule */
unsigned iso_idx; /* in urb->iso_frame_desc[] */ unsigned iso_idx; /* in urb->iso_frame_desc[] */
struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */ 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 */ /* map from control or bulk queue head to the first qh on that ring */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment