# RE: \[PATCH v2\] usb: fsl\_udc: errata - postpone freeing current dTD

- From: Chen Peter-B29397 \<hidden\>
- Date: 2012-05-21 07:26:07 
- List: linuxppc-dev
- Page: https://ratatoskr.run/linuxppc-dev/2012/05/9469387
- Thread: https://ratatoskr.run/linuxppc-dev/2012/05/9469338/t.md

```text
=20
>=20
> 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.
>=20
> This hardware bug is explained in detail by errata number 2858 for i.MX23=
:
> http://cache.freescale.com/files/dsp/doc/errata/IMX23CE.pdf
>=20

> 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.
>=20
> Signed-off-by: Christoph Fritz <redacted>
> Signed-off-by: Christian Hemp <redacted>
> ---
>  drivers/usb/gadget/fsl_udc_core.c |   15 ++++++++++++++-
>  1 files changed, 14 insertions(+), 1 deletions(-)
>=20
> 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 =3D NULL;
>=20
> +static struct ep_td_struct *last_free_td;
> +
>  static const struct usb_endpoint_descriptor
>  fsl_ep0_desc =3D {
>  	.bLength =3D		USB_DT_ENDPOINT_SIZE,
> @@ -180,8 +182,13 @@ static void done(struct fsl_ep *ep, struct fsl_req
> *req, int status)
>  		curr_td =3D next_td;
>  		if (j !=3D req->dtd_count - 1) {
>  			next_td =3D curr_td->next_td_virt;
> +			dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
> +		} else {
> +			if (last_free_td !=3D NULL)
> +				dma_pool_free(udc->td_pool, last_free_td,
> +						last_free_td->td_dma);
> +			last_free_td =3D curr_td;
>  		}
> -		dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
>  	}
>=20
>  	if (req->mapped) {
> @@ -2579,6 +2586,8 @@ static int __init fsl_udc_probe(struct
> platform_device *pdev)
>  		goto err_unregister;
>  	}
>=20
> +	last_free_td =3D NULL;
> +
>  	ret =3D 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);
>=20
> +	if (last_free_td !=3D 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 <redacted>
> --
> 1.7.2.5
>=20
>=20
```
