summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/udc/aspeed-vhub/epn.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2018-07-12 15:05:02 +1000
committerFelipe Balbi <felipe.balbi@linux.intel.com>2018-07-17 10:12:51 +0300
commitbb2863369562b3f0320fc7d8a96a5cde4b50aaea (patch)
tree63fda94e45b6e6c6fa9a74c7564de8a8303659c4 /drivers/usb/gadget/udc/aspeed-vhub/epn.c
parent9566a7c72f4f09b094c5517556d2b5f36a11b4ef (diff)
downloadlinux-stable-bb2863369562b3f0320fc7d8a96a5cde4b50aaea.tar.gz
linux-stable-bb2863369562b3f0320fc7d8a96a5cde4b50aaea.tar.bz2
linux-stable-bb2863369562b3f0320fc7d8a96a5cde4b50aaea.zip
usb: gadget: aspeed: Workaround memory ordering issue
The Aspeed SoC has a memory ordering issue that (thankfully) only affects the USB gadget device. A read back is necessary after writing to memory and before letting the device DMA from it. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/gadget/udc/aspeed-vhub/epn.c')
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/epn.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
index 80c9feac5147..5939eb1e97f2 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
@@ -66,11 +66,16 @@ static void ast_vhub_epn_kick(struct ast_vhub_ep *ep, struct ast_vhub_req *req)
if (!req->req.dma) {
/* For IN transfers, copy data over first */
- if (ep->epn.is_in)
+ if (ep->epn.is_in) {
memcpy(ep->buf, req->req.buf + act, chunk);
+ vhub_dma_workaround(ep->buf);
+ }
writel(ep->buf_dma, ep->epn.regs + AST_VHUB_EP_DESC_BASE);
- } else
+ } else {
+ if (ep->epn.is_in)
+ vhub_dma_workaround(req->req.buf);
writel(req->req.dma + act, ep->epn.regs + AST_VHUB_EP_DESC_BASE);
+ }
/* Start DMA */
req->active = true;
@@ -161,6 +166,7 @@ static inline unsigned int ast_vhub_count_free_descs(struct ast_vhub_ep *ep)
static void ast_vhub_epn_kick_desc(struct ast_vhub_ep *ep,
struct ast_vhub_req *req)
{
+ struct ast_vhub_desc *desc = NULL;
unsigned int act = req->act_count;
unsigned int len = req->req.length;
unsigned int chunk;
@@ -177,7 +183,6 @@ static void ast_vhub_epn_kick_desc(struct ast_vhub_ep *ep,
/* While we can create descriptors */
while (ast_vhub_count_free_descs(ep) && req->last_desc < 0) {
- struct ast_vhub_desc *desc;
unsigned int d_num;
/* Grab next free descriptor */
@@ -227,6 +232,9 @@ static void ast_vhub_epn_kick_desc(struct ast_vhub_ep *ep,
req->act_count = act = act + chunk;
}
+ if (likely(desc))
+ vhub_dma_workaround(desc);
+
/* Tell HW about new descriptors */
writel(VHUB_EP_DMA_SET_CPU_WPTR(ep->epn.d_next),
ep->epn.regs + AST_VHUB_EP_DESC_STATUS);