USB controller may access a wrong address for the dTD (endpoint transfer
descriptor) and then hang. This happens a lot when doing tests with
g_ether module and iperf, a tool for measuring maximum TCP and UDP
bandwidth.
This hardware bug is explained in detail by errata number 2858 for i.MX23:
http://cache.freescale.com/files/dsp/doc/errata/IMX23CE.pdf
mv_udc_core fixes this bug by commit daec765. There still may be unfixed
drivers.
Signed-off-by: Christoph Fritz
Signed-off-by: Christian Hemp
---
drivers/usb/gadget/fsl_udc_core.c | 22 ++
drivers/usb/gadget/fsl_usb2_udc.h |6 ++
2 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/gadget/fsl_udc_core.c
b/drivers/usb/gadget/fsl_udc_core.c
index 55abfb6..f9bfafd 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -65,6 +65,9 @@ static struct usb_sys_interface *usb_sys_regs;
/* it is initialized in probe() */
static struct fsl_udc *udc_controller = NULL;
+#ifdef POSTPONE_FREE_LAST_DTD
+static struct ep_td_struct *last_free_td;
+#endif
static const struct usb_endpoint_descriptor
fsl_ep0_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
@@ -180,8 +183,18 @@ static void done(struct fsl_ep *ep, struct fsl_req *req,
int status)
curr_td = next_td;
if (j != req->dtd_count - 1) {
next_td = curr_td->next_td_virt;
+#ifdef POSTPONE_FREE_LAST_DTD
+ dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
+ } else {
+ if (last_free_td != NULL)
+ dma_pool_free(udc->td_pool, last_free_td,
+ last_free_td->td_dma);
+ last_free_td = curr_td;
+ }
+#else
}
dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
+#endif
}
if (req->mapped) {
@@ -2579,6 +2592,10 @@ static int __init fsl_udc_probe(struct platform_device
*pdev)
goto err_unregister;
}
+#ifdef POSTPONE_FREE_LAST_DTD
+ last_free_td = NULL;
+#endif
+
ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
if (ret)
goto err_del_udc;
@@ -2633,6 +2650,11 @@ static int __exit fsl_udc_remove(struct platform_device
*pdev)
kfree(udc_controller->status_req);
kfree(udc_controller->eps);
+#ifdef POSTPONE_FREE_LAST_DTD
+ if (last_free_td != NULL)
+ dma_pool_free(udc_controller->td_pool, last_free_td,
+ last_free_td->td_dma);
+#endif
dma_pool_destroy(udc_controller->td_pool);
free_irq(udc_controller->irq, udc_controller);
iounmap(dr_regs);
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h
b/drivers/usb/gadget/fsl_usb2_udc.h
index e651469..03ae07f 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -4,6 +4,12 @@
#ifndef __FSL_USB2_UDC_H
#define __FSL_USB2_UDC_H
+#if defined CONFIG_ARCH_MX51 || defined CONFIG_SOC_IMX35
+#define POSTPONE_FREE_LAST_DTD
+#else
+#undef POSTPONE_FREE_LAST_DTD
+#endif
+
/* ### define USB registers here
*/
#define USB_MAX_CTRL_PAYLOAD 64
--
1.7.2.5
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev