]> git.karo-electronics.de Git - linux-beck.git/commitdiff
usb: gadget: mv_udc: fix dtd dma confusion
authorNeil Zhang <zhangwm@marvell.com>
Wed, 12 Oct 2011 08:49:36 +0000 (16:49 +0800)
committerFelipe Balbi <balbi@ti.com>
Thu, 13 Oct 2011 17:42:06 +0000 (20:42 +0300)
The controller will prime failure sometimes when do the iperf test.
Add delay to wait controller release dtd dma before we free it.
Then the issue is gone.

Signed-off-by: Neil Zhang <zhangwm@marvell.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/mv_udc_core.c

index ffa6f3097a649dcd80ec32bffe82896e5b245bde..9d960f1f7c7f01b45988a86cccaccac8db1fb0f7 100644 (file)
@@ -138,6 +138,7 @@ static int process_ep_req(struct mv_udc *udc, int index,
        int i, direction;
        int retval = 0;
        u32 errors;
+       u32 bit_pos;
 
        curr_dqh = &udc->ep_dqh[index];
        direction = index % 2;
@@ -155,10 +156,20 @@ static int process_ep_req(struct mv_udc *udc, int index,
 
                errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK;
                if (!errors) {
-                       remaining_length +=
+                       remaining_length =
                                (curr_dtd->size_ioc_sts & DTD_PACKET_SIZE)
                                        >> DTD_LENGTH_BIT_POS;
                        actual -= remaining_length;
+
+                       if (remaining_length) {
+                               if (direction) {
+                                       dev_dbg(&udc->dev->dev,
+                                               "TX dTD remains data\n");
+                                       retval = -EPROTO;
+                                       break;
+                               } else
+                                       break;
+                       }
                } else {
                        dev_info(&udc->dev->dev,
                                "complete_tr error: ep=%d %s: error = 0x%x\n",
@@ -180,6 +191,20 @@ static int process_ep_req(struct mv_udc *udc, int index,
        if (retval)
                return retval;
 
+       if (direction == EP_DIR_OUT)
+               bit_pos = 1 << curr_req->ep->ep_num;
+       else
+               bit_pos = 1 << (16 + curr_req->ep->ep_num);
+
+       while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) {
+               if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) {
+                       while (readl(&udc->op_regs->epstatus) & bit_pos)
+                               udelay(1);
+                       break;
+               }
+               udelay(1);
+       }
+
        curr_req->req.actual = actual;
 
        return 0;