summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorKrishna Yarlagadda <kyarlagadda@nvidia.com>2012-06-18 20:39:34 +0530
committerSimone Willett <swillett@nvidia.com>2012-07-27 15:36:06 -0700
commit5c84dc32d54f8bbda99f8a4e1fd7300e6b5a50b3 (patch)
tree4cb4c16d6408c2b03d40da303ec61cebbf9c773d /drivers/usb
parent7e7cb6ad913a379204c1858d2a409fa748592895 (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.c34
-rw-r--r--drivers/usb/gadget/tegra_udc.h4
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;