diff options
| author | Benoît Thébaudeau <benoit.thebaudeau@advansee.com> | 2012-08-10 18:27:23 +0200 | 
|---|---|---|
| committer | Marek Vasut <marex@denx.de> | 2012-09-01 16:21:52 +0200 | 
| commit | db19134615dda7e4b0b511c65e92507ab0a530d6 (patch) | |
| tree | b8800a56f86274118ec5323835d91e7c779d5a72 | |
| parent | 3e8581bb95899e21b01d86e9fe5ad7358bbef142 (diff) | |
| download | olio-uboot-2014.01-db19134615dda7e4b0b511c65e92507ab0a530d6.tar.xz olio-uboot-2014.01-db19134615dda7e4b0b511c65e92507ab0a530d6.zip | |
ehci: Optimize qTD allocations
Relax the qTD transfer alignment constraints in order to need less qTDs for
buffers that are aligned to 512 bytes but not to pages.
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
Cc: Marek Vasut <marex@denx.de>
Cc: Ilya Yanok <ilya.yanok@cogentembedded.com>
Cc: Stefan Herbrechtsmeier <stefan@herbrechtsmeier.net>
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 67 | 
1 files changed, 37 insertions, 30 deletions
| diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a0ef5db43..18b4bc654 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -215,7 +215,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  	volatile struct qTD *vtd;  	unsigned long ts;  	uint32_t *tdp; -	uint32_t endpt, token, usbsts; +	uint32_t endpt, maxpacket, token, usbsts;  	uint32_t c, toggle;  	uint32_t cmd;  	int timeout; @@ -230,6 +230,7 @@ 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)); +#define PKT_ALIGN	512  	/*  	 * The USB transfer is split into qTD transfers. Eeach qTD transfer is  	 * described by a transfer descriptor (the qTD). The qTDs form a linked @@ -251,43 +252,41 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  	if (length > 0 || req == NULL) {  		/*  		 * Determine the qTD transfer size that will be used for the -		 * data payload (not considering the final qTD transfer, which -		 * may be shorter). +		 * data payload (not considering the first qTD transfer, which +		 * may be longer or shorter, and the final one, which may be +		 * shorter).  		 *  		 * In order to keep each packet within a qTD transfer, the qTD -		 * transfer size is aligned to EHCI_PAGE_SIZE, which is a -		 * multiple of wMaxPacketSize (except in some cases for -		 * interrupt transfers, see comment in submit_int_msg()). +		 * transfer size is aligned to PKT_ALIGN, which is a multiple of +		 * wMaxPacketSize (except in some cases for interrupt transfers, +		 * see comment in submit_int_msg()).  		 * -		 * By default, i.e. if the input buffer is page-aligned, +		 * By default, i.e. if the input buffer is aligned to PKT_ALIGN,  		 * QT_BUFFER_CNT full pages will be used.  		 */  		int xfr_sz = QT_BUFFER_CNT;  		/* -		 * However, if the input buffer is not page-aligned, the qTD -		 * transfer size will be one page shorter, and the first qTD +		 * However, if the input buffer is not aligned to PKT_ALIGN, the +		 * qTD transfer size will be one page shorter, and the first qTD  		 * data buffer of each transfer will be page-unaligned.  		 */ -		if ((uint32_t)buffer & (EHCI_PAGE_SIZE - 1)) +		if ((uint32_t)buffer & (PKT_ALIGN - 1))  			xfr_sz--;  		/* Convert the qTD transfer size to bytes. */  		xfr_sz *= EHCI_PAGE_SIZE;  		/* -		 * Determine the number of qTDs that will be required for the -		 * data payload. This value has to be rounded up since the final -		 * qTD transfer may be shorter than the regular qTD transfer -		 * size that has just been computed. +		 * Approximate by excess the number of qTDs that will be +		 * required for the data payload. The exact formula is way more +		 * complicated and saves at most 2 qTDs, i.e. a total of 128 +		 * bytes.  		 */ -		qtd_count += DIV_ROUND_UP(length, xfr_sz); -		/* ZLPs also need a qTD. */ -		if (!qtd_count) -			qtd_count++; +		qtd_count += 2 + length / xfr_sz;  	}  /* - * Threshold value based on the worst-case total size of the qTDs to allocate - * for a mass-storage transfer of 65535 blocks of 512 bytes. + * Threshold value based on the worst-case total size of the allocated qTDs for + * a mass-storage transfer of 65535 blocks of 512 bytes.   */ -#if CONFIG_SYS_MALLOC_LEN <= 128 * 1024 +#if CONFIG_SYS_MALLOC_LEN <= 64 + 128 * 1024  #warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI  #endif  	qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD)); @@ -313,8 +312,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  	 */  	qh->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);  	c = usb_pipespeed(pipe) != USB_SPEED_HIGH && !usb_pipeendpoint(pipe); +	maxpacket = usb_maxpacket(dev, pipe);  	endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | -		QH_ENDPT1_MAXPKTLEN(usb_maxpacket(dev, pipe)) | QH_ENDPT1_H(0) | +		QH_ENDPT1_MAXPKTLEN(maxpacket) | QH_ENDPT1_H(0) |  		QH_ENDPT1_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) |  		QH_ENDPT1_EPS(usb_pipespeed(pipe)) |  		QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) | @@ -373,9 +373,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  			xfr_bytes -= (uint32_t)buf_ptr & (EHCI_PAGE_SIZE - 1);  			/*  			 * In order to keep each packet within a qTD transfer, -			 * align the qTD transfer size to EHCI_PAGE_SIZE. +			 * align the qTD transfer size to PKT_ALIGN.  			 */ -			xfr_bytes &= ~(EHCI_PAGE_SIZE - 1); +			xfr_bytes &= ~(PKT_ALIGN - 1);  			/*  			 * This transfer may be shorter than the available qTD  			 * transfer size that has just been computed. @@ -411,6 +411,13 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  			/* Update previous qTD! */  			*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);  			tdp = &qtd[qtd_counter++].qt_next; +			/* +			 * Data toggle has to be adjusted since the qTD transfer +			 * size is not always an even multiple of +			 * wMaxPacketSize. +			 */ +			if ((xfr_bytes / maxpacket) & 1) +				toggle ^= 1;  			buf_ptr += xfr_bytes;  			left_length -= xfr_bytes;  		} while (left_length > 0); @@ -426,7 +433,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		 */  		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);  		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); -		token = QT_TOKEN_DT(toggle) | QT_TOKEN_TOTALBYTES(0) | +		token = QT_TOKEN_DT(1) | QT_TOKEN_TOTALBYTES(0) |  			QT_TOKEN_IOC(1) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) |  			QT_TOKEN_PID(usb_pipein(pipe) ?  				QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) | @@ -931,11 +938,11 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,  	 * because bInterval is ignored.  	 *  	 * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2 -	 * if several qTDs are required, while the USB specification does not -	 * constrain this for interrupt transfers. That means that -	 * ehci_submit_async() would support interrupt transfers requiring -	 * several transactions only as long as the transfer size does not -	 * require more than a single qTD. +	 * <= PKT_ALIGN if several qTDs are required, while the USB +	 * specification does not constrain this for interrupt transfers. That +	 * means that ehci_submit_async() would support interrupt transfers +	 * requiring several transactions only as long as the transfer size does +	 * not require more than a single qTD.  	 */  	if (length > usb_maxpacket(dev, pipe)) {  		printf("%s: Interrupt transfers requiring several transactions " |