[U-Boot] [PATCH] ehci-hcd.c, musb_core, usb.h: Add USB_DMA_MINALIGN define for cache alignment

Marek Vasut marex at denx.de
Wed Jul 4 22:24:58 CEST 2012


Dear Ilya Yanok,

> From: Tom Rini <trini at ti.com>
> 
> The USB spec says that 32 bytes is the minimum required alignment.
> However on some platforms we have a larger minimum requirement for cache
> coherency.  In those cases, use that value rather than the USB spec
> minimum.  We add a cpp check to <usb.h> to define USB_DMA_MINALIGN and
> make use of it in ehci-hcd.c and musb_core.h.  We cannot use MAX() here
> as we are not allowed to have tests inside of align(...).
> 
> Cc: Marek Vasut <marex at denx.de>
> Signed-off-by: Tom Rini <trini at ti.com>
> [ilya.yanok]: fix size alignment, drop (incorrect) rounding
> when invalidating the buffer. If we got unaligned buffer from the
> upper layer -- that's definetely a bug so it's good to buzz
> about it. But we have to align the buffer length -- upper layers
> should take care to reserve enough space.
> Signed-off-by: Ilya Yanok <ilya.yanok at cogentembedded.com>
> ---
> Changes from Tom's V4:
>  - Internal buffers should be not only address but also size aligned
>  - Don't try to fix unalignment of external buffer
>  - Fix also debug() checks in ehci_td_buffer() (though size check is
>    meaningless: in the current API only size of transfer is passed
>    which is not always the same as size of underlying buffer and
>    can be unaligned.
> 
>  No bounce-buffering is implemented so unaligned buffers coming from
> the upper layers will still result in invalidate_dcache_range() vows.
> But I tested it with unaligned fatload and got strange result: no
> errors from invalidate_dcache_range, I got "EHCI timed out on TD"
> errors instead (the same situtation without this patch and cache
> disabled). Looks like unaligned buffers are problem for EHCI even
> without cache involved...
> Aligned fatload works like a charm.
> 
>  drivers/usb/host/ehci-hcd.c  |   89
> +++++++++++++++++++++++++----------------- drivers/usb/musb/musb_core.h | 
>   2 +-
>  include/usb.h                |   10 +++++
>  3 files changed, 65 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index 04300be..74a5c76 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -34,7 +34,9 @@ struct ehci_hccr *hccr;	/* R/O registers, not need for
> volatile */ volatile struct ehci_hcor *hcor;
> 
>  static uint16_t portreset;
> -static struct QH qh_list __attribute__((aligned(32)));
> +static char __qh_list[ALIGN(sizeof(struct QH), USB_DMA_MINALIGN)]
> +			__attribute__((aligned(USB_DMA_MINALIGN)));
> +static struct QH *qh_list = (struct QH *)__qh_list;

Maybe we should create DEFINE_ALIGNED_VARIABLE as a common.h macro?

>  static struct descriptor {
>  	struct usb_hub_descriptor hub;
> @@ -172,13 +174,13 @@ static int ehci_td_buffer(struct qTD *td, void *buf,
> size_t sz) {
>  	uint32_t delta, next;
>  	uint32_t addr = (uint32_t)buf;
> -	size_t rsz = roundup(sz, 32);
> +	size_t rsz = roundup(sz, USB_DMA_MINALIGN);
>  	int idx;
> 
>  	if (sz != rsz)
>  		debug("EHCI-HCD: Misaligned buffer size (%08x)\n", sz);
> 
> -	if (addr & 31)
> +	if (addr != ALIGN(addr, USB_DMA_MINALIGN))
>  		debug("EHCI-HCD: Misaligned buffer address (%p)\n", buf);

Good :)

>  	idx = 0;
> @@ -207,8 +209,12 @@ static int
>  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void
> *buffer, int length, struct devrequest *req)
>  {
> -	static struct QH qh __attribute__((aligned(32)));
> -	static struct qTD qtd[3] __attribute__((aligned (32)));
> +	static char *__qh[ALIGN(sizeof(struct QH), USB_DMA_MINALIGN)]
> +				__attribute__((aligned(USB_DMA_MINALIGN)));
> +	struct QH *qh = (struct QH *)__qh;
> +	static char *__qtd[ALIGN(3*sizeof(struct qTD), USB_DMA_MINALIGN)]
> +				__attribute__((aligned(USB_DMA_MINALIGN)));
> +	struct qTD *qtd = (struct qTD *)__qtd;
>  	int qtd_counter = 0;
> 
>  	volatile struct qTD *vtd;
> @@ -229,8 +235,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long
> pipe, void *buffer, le16_to_cpu(req->value), le16_to_cpu(req->value),
>  		      le16_to_cpu(req->index));
> 
> -	memset(&qh, 0, sizeof(struct QH));
> -	memset(qtd, 0, sizeof(qtd));
> +	memset(qh, 0, sizeof(struct QH));
> +	memset(qtd, 0, 3 * sizeof(*qtd));
> 
>  	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
> 
> @@ -244,7 +250,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long
> pipe, void *buffer, *   qh_overlay.qt_next ...... 13-10 H
>  	 * - qh_overlay.qt_altnext
>  	 */
> -	qh.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
> +	qh->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);
>  	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
>  	     usb_pipeendpoint(pipe) == 0) ? 1 : 0;
>  	endpt = (8 << 28) |
> @@ -255,14 +261,14 @@ ehci_submit_async(struct usb_device *dev, unsigned
> long pipe, void *buffer, (usb_pipespeed(pipe) << 12) |
>  	    (usb_pipeendpoint(pipe) << 8) |
>  	    (0 << 7) | (usb_pipedevice(pipe) << 0);
> -	qh.qh_endpt1 = cpu_to_hc32(endpt);
> +	qh->qh_endpt1 = cpu_to_hc32(endpt);
>  	endpt = (1 << 30) |
>  	    (dev->portnr << 23) |
>  	    (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
> -	qh.qh_endpt2 = cpu_to_hc32(endpt);
> -	qh.qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
> +	qh->qh_endpt2 = cpu_to_hc32(endpt);
> +	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
> 
> -	tdp = &qh.qh_overlay.qt_next;
> +	tdp = &qh->qh_overlay.qt_next;
> 
>  	if (req != NULL) {
>  		/*
> @@ -340,13 +346,15 @@ ehci_submit_async(struct usb_device *dev, unsigned
> long pipe, void *buffer, tdp = &qtd[qtd_counter++].qt_next;
>  	}
> 
> -	qh_list.qh_link = cpu_to_hc32((uint32_t)&qh | QH_LINK_TYPE_QH);
> +	qh_list->qh_link = cpu_to_hc32((uint32_t)qh | QH_LINK_TYPE_QH);
> 
>  	/* Flush dcache */
> -	flush_dcache_range((uint32_t)&qh_list,
> -		(uint32_t)&qh_list + sizeof(struct QH));
> -	flush_dcache_range((uint32_t)&qh, (uint32_t)&qh + sizeof(struct QH));
> -	flush_dcache_range((uint32_t)qtd, (uint32_t)qtd + sizeof(qtd));
> +	flush_dcache_range((uint32_t)qh_list,
> +		(uint32_t)qh_list + ALIGN(sizeof(struct QH), USB_DMA_MINALIGN));
> +	flush_dcache_range((uint32_t)qh, (uint32_t)qh +
> +		ALIGN(sizeof(struct QH), USB_DMA_MINALIGN));
> +	flush_dcache_range((uint32_t)qtd, (uint32_t)qtd +
> +		ALIGN(3*sizeof(*qtd), USB_DMA_MINALIGN));

Maybe we should make a macro for those things here to prevent such spaghetti of 
code ?

[...]

Minor things really, otherwise it's really good :)


More information about the U-Boot mailing list