Message ID | 20120521065722.GA4363@mars (mailing list archive) |
---|---|
State | Not Applicable |
Delegated to: | Kumar Gala |
Headers | show |
> > 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 > > All (?) SOCs with an IP from chipidea suffer from this problem. > mv_udc_core fixes this bug by commit daec765. There still may be > unfixed drivers. > > Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com> > Signed-off-by: Christian Hemp <c.hemp@phytec.de> > --- > drivers/usb/gadget/fsl_udc_core.c | 15 ++++++++++++++- > 1 files changed, 14 insertions(+), 1 deletions(-) > > diff --git a/drivers/usb/gadget/fsl_udc_core.c > b/drivers/usb/gadget/fsl_udc_core.c > index 55abfb6..72f2139 100644 > --- a/drivers/usb/gadget/fsl_udc_core.c > +++ b/drivers/usb/gadget/fsl_udc_core.c > @@ -65,6 +65,8 @@ static struct usb_sys_interface *usb_sys_regs; > /* it is initialized in probe() */ > static struct fsl_udc *udc_controller = NULL; > > +static struct ep_td_struct *last_free_td; > + > static const struct usb_endpoint_descriptor > fsl_ep0_desc = { > .bLength = USB_DT_ENDPOINT_SIZE, > @@ -180,8 +182,13 @@ 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; > + 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; > } > - dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); > } > > if (req->mapped) { > @@ -2579,6 +2586,8 @@ static int __init fsl_udc_probe(struct > platform_device *pdev) > goto err_unregister; > } > > + last_free_td = NULL; > + > ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); > if (ret) > goto err_del_udc; > @@ -2633,6 +2642,10 @@ static int __exit fsl_udc_remove(struct > platform_device *pdev) > kfree(udc_controller->status_req); > kfree(udc_controller->eps); > > + if (last_free_td != NULL) > + dma_pool_free(udc_controller->td_pool, last_free_td, > + last_free_td->td_dma); > + > dma_pool_destroy(udc_controller->td_pool); > free_irq(udc_controller->irq, udc_controller); > iounmap(dr_regs); Reviewed-by: Peter Chen <peter.chen@freescale.com> > -- > 1.7.2.5 > >
Hi, On Mon, May 21, 2012 at 08:57:22AM +0200, Christoph Fritz wrote: > 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 > > All (?) SOCs with an IP from chipidea suffer from this problem. > mv_udc_core fixes this bug by commit daec765. There still may be > unfixed drivers. > > Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com> > Signed-off-by: Christian Hemp <c.hemp@phytec.de> > --- > drivers/usb/gadget/fsl_udc_core.c | 15 ++++++++++++++- > 1 files changed, 14 insertions(+), 1 deletions(-) > > diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c > index 55abfb6..72f2139 100644 > --- a/drivers/usb/gadget/fsl_udc_core.c > +++ b/drivers/usb/gadget/fsl_udc_core.c > @@ -65,6 +65,8 @@ static struct usb_sys_interface *usb_sys_regs; > /* it is initialized in probe() */ > static struct fsl_udc *udc_controller = NULL; > > +static struct ep_td_struct *last_free_td; I don't want to see global variables anymore. In fact, please convert this to the new udc_start()/udc_stop() calls and use the generic map/unmap routines. That'll help you get rid of a bunch of useless code on the driver. After that you should remove all <asm/*> header includes and drop the ARCH dependency. You can also drop the big-/little-endian helpers as you can make use of generic writel()/readl() routines. Please make sure these series comes in with enough time to reach v3.6 merge window in about 3 months. You can put this fix together on that series after you drop the global.
This series updates USB gadget driver fsl-usb2-udc. Christoph Fritz (7): usb: gadget: fsl_udc: simplify driver init usb: gadget: fsl_udc: protect fsl_pullup() with spin_lock usb: gadget: fsl_udc: convert to new ulc style usb: gadget: fsl_udc: drop ARCH dependency usb: gadget: fsl_udc: postpone freeing current dTD usb: gadget: fsl_udc: purge global pointer usb_sys_regs usb: gadget: fsl_udc: purge global pointer dr_regs drivers/usb/gadget/fsl_udc_core.c | 755 ++++++++++++++++--------------------- drivers/usb/gadget/fsl_usb2_udc.h | 4 + 2 files changed, 322 insertions(+), 437 deletions(-)
Hi Christoph, What system are you working on? If it's i.MX you should use/work on the chipidea driver instead. Sascha On Fri, Oct 19, 2012 at 12:22:36PM +0200, Christoph Fritz wrote: > This series updates USB gadget driver fsl-usb2-udc. > > Christoph Fritz (7): > usb: gadget: fsl_udc: simplify driver init > usb: gadget: fsl_udc: protect fsl_pullup() with spin_lock > usb: gadget: fsl_udc: convert to new ulc style > usb: gadget: fsl_udc: drop ARCH dependency > usb: gadget: fsl_udc: postpone freeing current dTD > usb: gadget: fsl_udc: purge global pointer usb_sys_regs > usb: gadget: fsl_udc: purge global pointer dr_regs > > drivers/usb/gadget/fsl_udc_core.c | 755 ++++++++++++++++--------------------- > drivers/usb/gadget/fsl_usb2_udc.h | 4 + > 2 files changed, 322 insertions(+), 437 deletions(-) > > -- > 1.7.2.5 > >
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 55abfb6..72f2139 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -65,6 +65,8 @@ static struct usb_sys_interface *usb_sys_regs; /* it is initialized in probe() */ static struct fsl_udc *udc_controller = NULL; +static struct ep_td_struct *last_free_td; + static const struct usb_endpoint_descriptor fsl_ep0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -180,8 +182,13 @@ 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; + 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; } - dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); } if (req->mapped) { @@ -2579,6 +2586,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err_unregister; } + last_free_td = NULL; + ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); if (ret) goto err_del_udc; @@ -2633,6 +2642,10 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) kfree(udc_controller->status_req); kfree(udc_controller->eps); + if (last_free_td != NULL) + dma_pool_free(udc_controller->td_pool, last_free_td, + last_free_td->td_dma); + dma_pool_destroy(udc_controller->td_pool); free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs);