usb: ci13xxx_udc: Add delay upon hardware dequeue failure
A delay is observed between when the HW generates the
ENDPTCOMPLETE interrupt and updating the dTD status bits. This
delay is causing the request ending up in lying in the DCD queue
which leads to data stall on that particular endpoints.
As temporary workaround add 10 micro second delay upon dequeue failure
and make a call to hardware dequeue again which might help this case.
Change-Id: Ic97fa259b2e2f0a5c53cb49106f42960b4514164
Signed-off-by: Anji jonnala <anjir@codeaurora.org>
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 9d268d1..7dc7377 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1405,8 +1405,15 @@
mEp = &udc->ci13xxx_ep[ep_num];
n = hw_ep_bit(mEp->num, mEp->dir);
+ pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s"
+ "dTD_update_fail_count: %lu"
+ "mEp->dTD_update_fail_count: %lu\n", __func__,
+ hw_cread(CAP_ENDPTPRIME, ~0),
+ hw_cread(CAP_ENDPTSTAT, ~0),
+ mEp->num, mEp->dir ? "IN" : "OUT",
+ udc->dTD_update_fail_count,
+ mEp->dTD_update_fail_count);
- pr_info("ep#%d dir:%s\n", mEp->num, mEp->dir ? "IN" : "OUT");
pr_info("QH: cap:%08x cur:%08x next:%08x token:%08x\n",
mEp->qh.ptr->cap, mEp->qh.ptr->curr,
mEp->qh.ptr->td.next, mEp->qh.ptr->td.token);
@@ -2017,17 +2024,35 @@
struct ci13xxx_req *mReq, *mReqTemp;
struct ci13xxx_ep *mEpTemp = mEp;
int uninitialized_var(retval);
+ int req_dequeue = 1;
+ struct ci13xxx *udc = _udc;
trace("%p", mEp);
if (list_empty(&mEp->qh.queue))
- return -EINVAL;
+ return 0;
list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
queue) {
+dequeue:
retval = _hardware_dequeue(mEp, mReq);
- if (retval < 0)
+ if (retval < 0) {
+ /*
+ * FIXME: don't know exact delay
+ * required for HW to update dTD status
+ * bits. This is a temporary workaround till
+ * HW designers come back on this.
+ */
+ if (retval == -EBUSY && req_dequeue && mEp->dir == 0) {
+ req_dequeue = 0;
+ udc->dTD_update_fail_count++;
+ mEp->dTD_update_fail_count++;
+ udelay(10);
+ goto dequeue;
+ }
break;
+ }
+ req_dequeue = 0;
list_del_init(&mReq->queue);
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (mReq->req.complete != NULL) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index c37a717..b917fe9 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -98,6 +98,7 @@
spinlock_t *lock;
struct device *device;
struct dma_pool *td_pool;
+ unsigned long dTD_update_fail_count;
};
struct ci13xxx;
@@ -139,6 +140,7 @@
int vbus_active; /* is VBUS active */
int softconnect; /* is pull-up enable allowed */
struct otg_transceiver *transceiver; /* Transceiver struct */
+ unsigned long dTD_update_fail_count;
};
/******************************************************************************