Patchwork usb: fsl_udc: errata - postpone freeing current dTD

login
register
mail settings
Submitter Christoph Fritz
Date May 20, 2012, 11:17 p.m.
Message ID <20120520231724.GA7941@mars>
Download mbox | patch
Permalink /patch/160296/
State Superseded
Delegated to: Kumar Gala
Headers show

Comments

Christoph Fritz - May 20, 2012, 11:17 p.m.
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 <chf.fritz@googlemail.com>
Signed-off-by: Christian Hemp <c.hemp@phytec.de>
---
 drivers/usb/gadget/fsl_udc_core.c |   22 ++++++++++++++++++++++
 drivers/usb/gadget/fsl_usb2_udc.h |    6 ++++++
 2 files changed, 28 insertions(+), 0 deletions(-)
Chen Peter-B29397 - May 21, 2012, 1:05 a.m.
> 
> 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
> 

Does this patch fix your problem?
 
> +#if defined CONFIG_ARCH_MX51 || defined CONFIG_SOC_IMX35
> +#define POSTPONE_FREE_LAST_DTD
> +#else
> +#undef POSTPONE_FREE_LAST_DTD
> +#endif
> +
All i.mx SoC has this problem, if PowerPC also has this problem, you can 
delete #if defined. Else, you can define it for all i.mx SoC 
(CONFIG_ARCH_MXC | CONFIG_ARCH_MXS)

>  /* ### define USB registers here
>   */
>  #define USB_MAX_CTRL_PAYLOAD		64
> --
> 1.7.2.5
> 
>
Christoph Fritz - May 21, 2012, 6:53 a.m.
Hi Chen,

On Mon, 2012-05-21 at 01:05 +0000, Chen Peter-B29397 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
> > 
> 
> Does this patch fix your problem?

yes, it does! :-)

> > +#if defined CONFIG_ARCH_MX51 || defined CONFIG_SOC_IMX35
> > +#define POSTPONE_FREE_LAST_DTD
> > +#else
> > +#undef POSTPONE_FREE_LAST_DTD
> > +#endif
> > +
> All i.mx SoC has this problem, if PowerPC also has this problem, you can 
> delete #if defined. Else, you can define it for all i.mx SoC 
> (CONFIG_ARCH_MXC | CONFIG_ARCH_MXS)

I was unsure about this too. I can only test imx35. And mx51 was defined
in your tree. So these two should be defined anyway.

Marvell doesn't use any defines in mv_udc_core for their fix, so I would
be fine without ifdefs too. Any objections? Please see next mail with
patch v2.


Thanks,
 -- Christoph

Patch

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