diff options
author | Krishna Yarlagadda <kyarlagadda@nvidia.com> | 2012-06-18 20:39:34 +0530 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-07-27 15:36:06 -0700 |
commit | 5c84dc32d54f8bbda99f8a4e1fd7300e6b5a50b3 (patch) | |
tree | 4cb4c16d6408c2b03d40da303ec61cebbf9c773d /drivers/usb | |
parent | 7e7cb6ad913a379204c1858d2a409fa748592895 (diff) |
USB: gadget: tegra: SW WAR for dTD issue
SW WAR implementation for h/w issue observed on all tegra platforms
Adding a dTD to a Primed Endpoint May Not Get Recognized
TD freeing will be delayed until next TD is completed
Bug 1002166
Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-on: http://git-master/r/109562
(cherry picked from commit 8603480606af20444ed91e3010a22cc02edacb78)
Change-Id: I875d06eb2db78a18858590645df631478f3201bb
Reviewed-on: http://git-master/r/116972
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Tested-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/tegra_udc.c | 34 | ||||
-rw-r--r-- | drivers/usb/gadget/tegra_udc.h | 4 |
2 files changed, 32 insertions, 6 deletions
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c index 47e2e97984a4..db5b72856e8e 100644 --- a/drivers/usb/gadget/tegra_udc.c +++ b/drivers/usb/gadget/tegra_udc.c @@ -129,8 +129,9 @@ static void done(struct tegra_ep *ep, struct tegra_req *req, int status) { struct tegra_udc *udc = NULL; unsigned char stopped = ep->stopped; - struct ep_td_struct *curr_td, *next_td; + struct ep_td_struct *curr_td, *next_td = 0; int j; + int count; BUG_ON(!(in_irq() || irqs_disabled())); udc = (struct tegra_udc *)ep->udc; /* Removed the req from tegra_ep->queue */ @@ -143,12 +144,19 @@ static void done(struct tegra_ep *ep, struct tegra_req *req, int status) status = req->req.status; /* Free dtd for the request */ - next_td = req->head; - for (j = 0; j < req->dtd_count; j++) { + count = 0; + if (ep->last_td) { + next_td = ep->last_td; + count = ep->last_dtd_count; + } + ep->last_td = req->head; + ep->last_dtd_count = req->dtd_count; + + for (j = 0; j < count; j++) { curr_td = next_td; - if (j != req->dtd_count - 1) + if (j != count - 1) { next_td = curr_td->next_td_virt; - + } dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); } @@ -568,6 +576,8 @@ static int tegra_ep_enable(struct usb_ep *_ep, ep->ep.maxpacket = max; ep->desc = desc; ep->stopped = 0; + ep->last_td = 0; + ep->last_dtd_count = 0; /* Controller related setup * Init EPx Queue Head (Ep Capabilites field in QH @@ -610,6 +620,8 @@ static int tegra_ep_disable(struct usb_ep *_ep) unsigned long flags = 0; u32 epctrl; int ep_num; + struct ep_td_struct *curr_td, *next_td; + int j; ep = container_of(_ep, struct tegra_ep, ep); if (!_ep || !ep->desc) { @@ -638,6 +650,18 @@ static int tegra_ep_disable(struct usb_ep *_ep) ep->desc = NULL; ep->stopped = 1; + if (ep->last_td) { + next_td = ep->last_td; + for (j = 0; j < ep->last_dtd_count; j++) { + curr_td = next_td; + dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); + if (j != ep->last_dtd_count - 1) { + next_td = curr_td->next_td_virt; + } + } + } + ep->last_td =0; + ep->last_dtd_count = 0; spin_unlock_irqrestore(&udc->lock, flags); VDBG("disabled %s OK", _ep->name); diff --git a/drivers/usb/gadget/tegra_udc.h b/drivers/usb/gadget/tegra_udc.h index e94543fd98e3..50e2a3193648 100644 --- a/drivers/usb/gadget/tegra_udc.h +++ b/drivers/usb/gadget/tegra_udc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 NVIDIA Corporation + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * Description: * High-speed USB device controller driver. @@ -390,6 +390,8 @@ struct tegra_ep { struct ep_queue_head *qh; const struct usb_endpoint_descriptor *desc; struct usb_gadget *gadget; + struct ep_td_struct *last_td; + int last_dtd_count; char name[14]; unsigned stopped:1; |