summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTroy Kisky <troy.kisky@boundarydevices.com>2013-10-10 15:28:01 -0700
committerMarek Vasut <marex@denx.de>2013-10-20 23:46:33 +0200
commit1ebf02787a1621143ecde48db86459067f9544e5 (patch)
treea3840ab9c780a5d62c4be1c5c9d42ad4aa288ce4
parent3b59abf583143a9ed11ea0d05fdad02afb996d45 (diff)
usb: gadget: mv_udc: optimize bounce
Only perform one copy, either in the bounce routine for IN transfers, or the debounce rtn for OUT transfer. On out transfers, only copy the number of bytes received from the bounce buffer Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
-rw-r--r--drivers/usb/gadget/mv_udc.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/drivers/usb/gadget/mv_udc.c b/drivers/usb/gadget/mv_udc.c
index 24c3e4f118f..1c5760535e3 100644
--- a/drivers/usb/gadget/mv_udc.c
+++ b/drivers/usb/gadget/mv_udc.c
@@ -261,7 +261,7 @@ static int mv_ep_disable(struct usb_ep *ep)
return 0;
}
-static int mv_bounce(struct mv_ep *ep)
+static int mv_bounce(struct mv_ep *ep, int in)
{
uint32_t addr = (uint32_t)ep->req.buf;
uint32_t ba;
@@ -290,8 +290,8 @@ align:
if (!ep->b_buf)
return -ENOMEM;
}
-
- memcpy(ep->b_buf, ep->req.buf, ep->req.length);
+ if (in)
+ memcpy(ep->b_buf, ep->req.buf, ep->req.length);
flush:
ba = (uint32_t)ep->b_buf;
@@ -300,29 +300,25 @@ flush:
return 0;
}
-static void mv_debounce(struct mv_ep *ep)
+static void mv_debounce(struct mv_ep *ep, int in)
{
uint32_t addr = (uint32_t)ep->req.buf;
uint32_t ba = (uint32_t)ep->b_buf;
+ if (in) {
+ if (addr == ba)
+ return; /* not a bounce */
+ goto free;
+ }
invalidate_dcache_range(ba, ba + ep->b_len);
- /* Input buffer address is not aligned. */
- if (addr & (ARCH_DMA_MINALIGN - 1))
- goto copy;
-
- /* Input buffer length is not aligned. */
- if (ep->req.length & (ARCH_DMA_MINALIGN - 1))
- goto copy;
-
- /* The buffer is well aligned, only invalidate cache. */
- return;
+ if (addr == ba)
+ return; /* not a bounce */
-copy:
memcpy(ep->req.buf, ep->b_buf, ep->req.length);
-
+free:
/* Large payloads use allocated buffer, free it. */
- if (ep->req.length > 64)
+ if (ep->b_buf != ep->b_fast)
free(ep->b_buf);
}
@@ -340,7 +336,7 @@ static int mv_ep_queue(struct usb_ep *ep,
head = mv_get_qh(num, in);
len = req->length;
- ret = mv_bounce(mv_ep);
+ ret = mv_bounce(mv_ep, in);
if (ret)
return ret;
@@ -383,10 +379,9 @@ static void handle_ep_complete(struct mv_ep *ep)
num, in ? "in" : "out", item->info, item->page0);
len = (item->info >> 16) & 0x7fff;
-
- mv_debounce(ep);
-
ep->req.length -= len;
+ mv_debounce(ep, in);
+
DBG("ept%d %s complete %x\n",
num, in ? "in" : "out", len);
ep->req.complete(&ep->ep, &ep->req);