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>
This commit is contained in:
Benoît Thébaudeau 2012-08-10 18:27:23 +02:00 committed by Marek Vasut
parent 3e8581bb95
commit db19134615

View file

@ -215,7 +215,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
volatile struct qTD *vtd; volatile struct qTD *vtd;
unsigned long ts; unsigned long ts;
uint32_t *tdp; uint32_t *tdp;
uint32_t endpt, token, usbsts; uint32_t endpt, maxpacket, token, usbsts;
uint32_t c, toggle; uint32_t c, toggle;
uint32_t cmd; uint32_t cmd;
int timeout; 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->value), le16_to_cpu(req->value),
le16_to_cpu(req->index)); le16_to_cpu(req->index));
#define PKT_ALIGN 512
/* /*
* The USB transfer is split into qTD transfers. Eeach qTD transfer is * The USB transfer is split into qTD transfers. Eeach qTD transfer is
* described by a transfer descriptor (the qTD). The qTDs form a linked * 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) { if (length > 0 || req == NULL) {
/* /*
* Determine the qTD transfer size that will be used for the * Determine the qTD transfer size that will be used for the
* data payload (not considering the final qTD transfer, which * data payload (not considering the first qTD transfer, which
* may be shorter). * 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 * In order to keep each packet within a qTD transfer, the qTD
* transfer size is aligned to EHCI_PAGE_SIZE, which is a * transfer size is aligned to PKT_ALIGN, which is a multiple of
* multiple of wMaxPacketSize (except in some cases for * wMaxPacketSize (except in some cases for interrupt transfers,
* interrupt transfers, see comment in submit_int_msg()). * 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. * QT_BUFFER_CNT full pages will be used.
*/ */
int xfr_sz = QT_BUFFER_CNT; int xfr_sz = QT_BUFFER_CNT;
/* /*
* However, if the input buffer is not page-aligned, the qTD * However, if the input buffer is not aligned to PKT_ALIGN, the
* transfer size will be one page shorter, and the first qTD * qTD transfer size will be one page shorter, and the first qTD
* data buffer of each transfer will be page-unaligned. * 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--; xfr_sz--;
/* Convert the qTD transfer size to bytes. */ /* Convert the qTD transfer size to bytes. */
xfr_sz *= EHCI_PAGE_SIZE; xfr_sz *= EHCI_PAGE_SIZE;
/* /*
* Determine the number of qTDs that will be required for the * Approximate by excess the number of qTDs that will be
* data payload. This value has to be rounded up since the final * required for the data payload. The exact formula is way more
* qTD transfer may be shorter than the regular qTD transfer * complicated and saves at most 2 qTDs, i.e. a total of 128
* size that has just been computed. * bytes.
*/ */
qtd_count += DIV_ROUND_UP(length, xfr_sz); qtd_count += 2 + length / xfr_sz;
/* ZLPs also need a qTD. */
if (!qtd_count)
qtd_count++;
} }
/* /*
* Threshold value based on the worst-case total size of the qTDs to allocate * Threshold value based on the worst-case total size of the allocated qTDs for
* for a mass-storage transfer of 65535 blocks of 512 bytes. * 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 #warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI
#endif #endif
qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD)); 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); qh->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);
c = usb_pipespeed(pipe) != USB_SPEED_HIGH && !usb_pipeendpoint(pipe); c = usb_pipespeed(pipe) != USB_SPEED_HIGH && !usb_pipeendpoint(pipe);
maxpacket = usb_maxpacket(dev, pipe);
endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | 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_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) |
QH_ENDPT1_EPS(usb_pipespeed(pipe)) | QH_ENDPT1_EPS(usb_pipespeed(pipe)) |
QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) | 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); xfr_bytes -= (uint32_t)buf_ptr & (EHCI_PAGE_SIZE - 1);
/* /*
* In order to keep each packet within a qTD transfer, * 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 * This transfer may be shorter than the available qTD
* transfer size that has just been computed. * 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! */ /* Update previous qTD! */
*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
tdp = &qtd[qtd_counter++].qt_next; 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; buf_ptr += xfr_bytes;
left_length -= xfr_bytes; left_length -= xfr_bytes;
} while (left_length > 0); } 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_next = cpu_to_hc32(QT_NEXT_TERMINATE);
qtd[qtd_counter].qt_altnext = 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_IOC(1) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) |
QT_TOKEN_PID(usb_pipein(pipe) ? QT_TOKEN_PID(usb_pipein(pipe) ?
QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) | 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. * because bInterval is ignored.
* *
* Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2 * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2
* if several qTDs are required, while the USB specification does not * <= PKT_ALIGN if several qTDs are required, while the USB
* constrain this for interrupt transfers. That means that * specification does not constrain this for interrupt transfers. That
* ehci_submit_async() would support interrupt transfers requiring * means that ehci_submit_async() would support interrupt transfers
* several transactions only as long as the transfer size does not * requiring several transactions only as long as the transfer size does
* require more than a single qTD. * not require more than a single qTD.
*/ */
if (length > usb_maxpacket(dev, pipe)) { if (length > usb_maxpacket(dev, pipe)) {
printf("%s: Interrupt transfers requiring several transactions " printf("%s: Interrupt transfers requiring several transactions "