Commit a9c17430 authored by Michael Grzeschik's avatar Michael Grzeschik Committed by Greg Kroah-Hartman

usb: chipidea: udc: fix memory access of shared memory on armv5 machines

The udc uses an shared dma memory space between hard and software. This
memory layout is described in ci13xxx_qh and ci13xxx_td which are marked
with the attribute ((packed)).

The compiler currently does not know about the alignment of the memory
layout, and will create strb and ldrb operations.

The Datasheet of the synopsys core describes, that some operations on
the mapped memory need to be atomic double word operations. I.e. the
next pointer addressing in the qhead, as otherwise the hardware will
read wrong data and totally stuck.

This is also possible while working with the current active td queue,
and preparing the td->ptr.next in software while the hardware is still
working with the current active td which is supposed to be changed:

writeb(0xde, &td->ptr.next + 0x0); /* strb */
writeb(0xad, &td->ptr.next + 0x1); /* strb */

<----- hardware reads value of td->ptr.next and get stuck!

writeb(0xbe, &td->ptr.next + 0x2); /* strb */
writeb(0xef, &td->ptr.next + 0x3); /* strb */

This appeares on armv5 machines where the hardware does not support
unaligned 32bit operations.

This patch adds the attribute ((aligned(4))) to the structures to tell
the compiler to use 32bit operations. It also adds an wmb() for the
prepared TD data before it gets enqueued into the qhead.

Cc: stable <stable@vger.kernel.org> # v3.5
Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Reviewed-by: default avatarFelipe Balbi <balbi@ti.com>
Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 369a9a9d
...@@ -435,6 +435,8 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) ...@@ -435,6 +435,8 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
mReq->ptr->page[i] = cpu_to_le32(page); mReq->ptr->page[i] = cpu_to_le32(page);
} }
wmb();
if (!list_empty(&mEp->qh.queue)) { if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req *mReqPrev; struct ci13xxx_req *mReqPrev;
int n = hw_ep_bit(mEp->num, mEp->dir); int n = hw_ep_bit(mEp->num, mEp->dir);
......
...@@ -40,7 +40,7 @@ struct ci13xxx_td { ...@@ -40,7 +40,7 @@ struct ci13xxx_td {
#define TD_CURR_OFFSET (0x0FFFUL << 0) #define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0) #define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0) #define TD_RESERVED_MASK (0x0FFFUL << 0)
} __attribute__ ((packed)); } __attribute__ ((packed, aligned(4)));
/* DMA layout of queue heads */ /* DMA layout of queue heads */
struct ci13xxx_qh { struct ci13xxx_qh {
...@@ -57,7 +57,7 @@ struct ci13xxx_qh { ...@@ -57,7 +57,7 @@ struct ci13xxx_qh {
/* 9 */ /* 9 */
u32 RESERVED; u32 RESERVED;
struct usb_ctrlrequest setup; struct usb_ctrlrequest setup;
} __attribute__ ((packed)); } __attribute__ ((packed, aligned(4)));
/** /**
* struct ci13xxx_req - usb request representation * struct ci13xxx_req - usb request representation
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment