Skip to contentSkip to conversation

ehci: cosmetic: Define used constants

PATCH Superseded Benoît Thébaudeau 3 participants 25 messages Aug 9, 2012 – Aug 11, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: N/A.
Changes for v3:
- New patch.

 .../drivers/usb/host/ehci-hcd.c                    |  135 +++++++++++---------
 .../drivers/usb/host/ehci.h                        |   75 ++++++++++-
 2 files changed, 150 insertions(+), 60 deletions(-)
drivers/usb/host/ehci-hcd.c +76 -59
index 5b3b906..1977c28 100644
@@ -163,7 +163,7 @@ static int ehci_reset(void)
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&hcor->or_txfilltuning);
-	cmd &= ~TXFIFO_THRESH(0x3f);
+	cmd &= ~TXFIFO_THRESH_MASK;
 	cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
 	ehci_writel(&hcor->or_txfilltuning, cmd);
 #endif
@@ -186,7 +186,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
 	while (idx < QT_BUFFER_CNT) {
 		td->qt_buffer[idx] = cpu_to_hc32(addr);
 		td->qt_buffer_hi[idx] = 0;
-		next = (addr + 4096) & ~4095;
+		next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);
 		delta = next - addr;
 		if (delta >= sz)
 			break;
@@ -208,7 +208,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		   int length, struct devrequest *req)
 {
 	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
-	ALLOC_ALIGN_BUFFER(struct qTD, qtd, 3, USB_DMA_MINALIGN);
+#define QTD_COUNT	3
+	ALLOC_ALIGN_BUFFER(struct qTD, qtd, QTD_COUNT, USB_DMA_MINALIGN);
 	int qtd_counter = 0;
 
 	volatile struct qTD *vtd;
@@ -230,7 +231,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		      le16_to_cpu(req->index));
 
 	memset(qh, 0, sizeof(struct QH));
-	memset(qtd, 0, 3 * sizeof(*qtd));
+	memset(qtd, 0, QTD_COUNT * sizeof(*qtd));
 
 	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
@@ -246,19 +247,20 @@ 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) == 0) ? 1 : 0;
-	endpt = (8 << 28) |
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |
+	    (usb_maxpacket(dev, pipe) << QH_ENDPT1_MAXPKTLEN) |
+	    (0 << QH_ENDPT1_H) |
+	    (QH_ENDPT1_DTC_DT_FROM_QTD << QH_ENDPT1_DTC) |
+	    (usb_pipespeed(pipe) << QH_ENDPT1_EPS) |
+	    (usb_pipeendpoint(pipe) << QH_ENDPT1_ENDPT) |
+	    (0 << QH_ENDPT1_I) | (usb_pipedevice(pipe) << QH_ENDPT1_DEVADDR);
 	qh->qh_endpt1 = cpu_to_hc32(endpt);
-	endpt = (1 << 30) |
-	    (dev->portnr << 23) |
-	    (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
+	endpt = (1 << QH_ENDPT2_MULT) |
+	    (dev->portnr << QH_ENDPT2_PORTNUM) |
+	    (dev->parent->devnum << QH_ENDPT2_HUBADDR) |
+	    (0 << QH_ENDPT2_UFRAMECMASK) | (0 << QH_ENDPT2_UFRAMESMASK);
 	qh->qh_endpt2 = cpu_to_hc32(endpt);
 	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
 
@@ -276,9 +278,12 @@ 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 = (0 << 31) |
-		    (sizeof(*req) << 16) |
-		    (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
+		token = (0 << QT_TOKEN_DT) |
+		    (sizeof(*req) << QT_TOKEN_TOTALBYTES) |
+		    (0 << QT_TOKEN_IOC) | (0 << QT_TOKEN_CPAGE) |
+		    (3 << QT_TOKEN_CERR) |
+		    (QT_TOKEN_PID_SETUP << QT_TOKEN_PID) |
+		    (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS);
 		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
 		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req)) != 0) {
 			printf("unable construct SETUP td\n");
@@ -302,12 +307,14 @@ 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 = (toggle << 31) |
-		    (length << 16) |
-		    ((req == NULL ? 1 : 0) << 15) |
-		    (0 << 12) |
-		    (3 << 10) |
-		    ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
+		token = (toggle << QT_TOKEN_DT) |
+		    (length << QT_TOKEN_TOTALBYTES) |
+		    ((req == NULL) << QT_TOKEN_IOC) |
+		    (0 << QT_TOKEN_CPAGE) |
+		    (3 << QT_TOKEN_CERR) |
+		    ((usb_pipein(pipe) ? QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) <<
+			QT_TOKEN_PID) |
+		    (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS);
 		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
 		if (ehci_td_buffer(&qtd[qtd_counter], buffer, length) != 0) {
 			printf("unable construct DATA td\n");
@@ -328,12 +335,14 @@ 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 = (toggle << 31) |
-		    (0 << 16) |
-		    (1 << 15) |
-		    (0 << 12) |
-		    (3 << 10) |
-		    ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
+		token = (toggle << QT_TOKEN_DT) |
+		    (0 << QT_TOKEN_TOTALBYTES) |
+		    (1 << QT_TOKEN_IOC) |
+		    (0 << QT_TOKEN_CPAGE) |
+		    (3 << QT_TOKEN_CERR) |
+		    ((usb_pipein(pipe) ? QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) <<
+			QT_TOKEN_PID) |
+		    (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS);
 		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
 		/* Update previous qTD! */
 		*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
@@ -346,7 +355,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	flush_dcache_range((uint32_t)qh_list,
 		ALIGN_END_ADDR(struct QH, qh_list, 1));
 	flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1));
-	flush_dcache_range((uint32_t)qtd, ALIGN_END_ADDR(struct qTD, qtd, 3));
+	flush_dcache_range((uint32_t)qtd,
+			   ALIGN_END_ADDR(struct qTD, qtd, QTD_COUNT));
 
 	/* Set async. queue head pointer. */
 	ehci_writel(&hcor->or_asynclistaddr, (uint32_t)qh_list);
@@ -359,10 +369,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	cmd |= CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, STS_ASS,
 			100 * 1000);
 	if (ret < 0) {
-		printf("EHCI fail timeout STD_ASS set\n");
+		printf("EHCI fail timeout STS_ASS set\n");
 		goto fail;
 	}
 
@@ -377,10 +387,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		invalidate_dcache_range((uint32_t)qh,
 			ALIGN_END_ADDR(struct QH, qh, 1));
 		invalidate_dcache_range((uint32_t)qtd,
-			ALIGN_END_ADDR(struct qTD, qtd, 3));
+			ALIGN_END_ADDR(struct qTD, qtd, QTD_COUNT));
 
 		token = hc32_to_cpu(vtd->qt_token);
-		if (!(token & 0x80))
+		if (!(token & (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS)))
 			break;
 		WATCHDOG_RESET();
 	} while (get_timer(ts) < timeout);
@@ -398,50 +408,53 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN));
 
 	/* Check that the TD processing happened */
-	if (token & 0x80) {
+	if (token & (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS))
 		printf("EHCI timed out on TD - token=%#x\n", token);
-	}
 
 	/* Disable async schedule. */
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	cmd &= ~CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0,
 			100 * 1000);
 	if (ret < 0) {
-		printf("EHCI fail timeout STD_ASS reset\n");
+		printf("EHCI fail timeout STS_ASS reset\n");
 		goto fail;
 	}
 
 	token = hc32_to_cpu(qh->qh_overlay.qt_token);
-	if (!(token & 0x80)) {
+	if (!(token & (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS))) {
 		debug("TOKEN=%#x\n", token);
-		switch (token & 0xfc) {
+		switch ((token >> QT_TOKEN_STATUS) & (QT_TOKEN_STATUS_ACTIVE |
+			QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_DATBUFERR |
+			QT_TOKEN_STATUS_BABBLEDET | QT_TOKEN_STATUS_XACTERR |
+			QT_TOKEN_STATUS_MISSEDUFRAME)) {
 		case 0:
-			toggle = token >> 31;
+			toggle = token >> QT_TOKEN_DT;
 			usb_settoggle(dev, usb_pipeendpoint(pipe),
 				       usb_pipeout(pipe), toggle);
 			dev->status = 0;
 			break;
-		case 0x40:
+		case QT_TOKEN_STATUS_HALTED:
 			dev->status = USB_ST_STALLED;
 			break;
-		case 0xa0:
-		case 0x20:
+		case QT_TOKEN_STATUS_ACTIVE | QT_TOKEN_STATUS_DATBUFERR:
+		case QT_TOKEN_STATUS_DATBUFERR:
 			dev->status = USB_ST_BUF_ERR;
 			break;
-		case 0x50:
-		case 0x10:
+		case QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_BABBLEDET:
+		case QT_TOKEN_STATUS_BABBLEDET:
 			dev->status = USB_ST_BABBLE_DET;
 			break;
 		default:
 			dev->status = USB_ST_CRC_ERR;
-			if ((token & 0x40) == 0x40)
+			if (token & (QT_TOKEN_STATUS_HALTED << QT_TOKEN_STATUS))
 				dev->status |= USB_ST_STALLED;
 			break;
 		}
-		dev->act_len = length - ((token >> 16) & 0x7fff);
+		dev->act_len = length - ((token & QT_TOKEN_TOTALBYTES_MASK) >>
+						QT_TOKEN_TOTALBYTES);
 	} else {
 		dev->act_len = 0;
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
@@ -499,12 +512,14 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		case USB_DT_DEVICE:
 			debug("USB_DT_DEVICE request\n");
 			srcptr = &descriptor.device;
-			srclen = 0x12;
+			srclen = descriptor.device.bLength;
 			break;
 		case USB_DT_CONFIG:
 			debug("USB_DT_CONFIG config\n");
 			srcptr = &descriptor.config;
-			srclen = 0x19;
+			srclen = descriptor.config.bLength +
+					descriptor.interface.bLength +
+					descriptor.endpoint.bLength;
 			break;
 		case USB_DT_STRING:
 			debug("USB_DT_STRING config\n");
@@ -539,7 +554,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		case USB_DT_HUB:
 			debug("USB_DT_HUB config\n");
 			srcptr = &descriptor.hub;
-			srclen = 0x8;
+			srclen = descriptor.hub.bLength;
 			break;
 		default:
 			debug("unknown value %x\n", le16_to_cpu(req->value));
@@ -577,13 +592,13 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 
 		if (ehci_is_TDI()) {
-			switch ((reg >> 26) & 3) {
-			case 0:
+			switch ((reg & PORTSC_PSPD_MASK) >> PORTSC_PSPD_OFFS) {
+			case PORTSC_PSPD_FS:
 				break;
-			case 1:
+			case PORTSC_PSPD_LS:
 				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
 				break;
-			case 2:
+			case PORTSC_PSPD_HS:
 			default:
 				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 				break;
@@ -744,11 +759,13 @@ int usb_lowlevel_init(void)
 	/* Set head of reclaim list */
 	memset(qh_list, 0, sizeof(*qh_list));
 	qh_list->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);
-	qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
+	qh_list->qh_endpt1 = cpu_to_hc32((1 << QH_ENDPT1_H) |
+					(USB_SPEED_HIGH << QH_ENDPT1_EPS));
 	qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
 	qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
 	qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
-	qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40);
+	qh_list->qh_overlay.qt_token = cpu_to_hc32(QT_TOKEN_STATUS_HALTED <<
+							QT_TOKEN_STATUS);
 
 	reg = ehci_readl(&hccr->cr_hcsparams);
 	descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
drivers/usb/host/ehci.h +74 -1

111 lines not on this page · raw message

#1 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Dear Beno?t Th?baudeau,

Quoted 61 lines
Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: N/A.
Changes for v3:
- New patch.

 .../drivers/usb/host/ehci-hcd.c                    |  135

+++++++++++--------- .../drivers/usb/host/ehci.h |
75 ++++++++++- 2 files changed, 150 insertions(+), 60 deletions(-)

(quoted diff) +0 -0

u-boot-usb-8d5fb14/drivers/usb/host/ehci-hcd.c index 5b3b906..1977c28 100644

drivers/usb/host/ehci-hcd.c +5 -4
@@ -163,7 +163,7 @@ static int ehci_reset(void)
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&hcor->or_txfilltuning);
-	cmd &= ~TXFIFO_THRESH(0x3f);
+	cmd &= ~TXFIFO_THRESH_MASK;
 	cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
 	ehci_writel(&hcor->or_txfilltuning, cmd);
 #endif
@@ -186,7 +186,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf,
 size_t sz) while (idx < QT_BUFFER_CNT) {
 		td->qt_buffer[idx] = cpu_to_hc32(addr);
 		td->qt_buffer_hi[idx] = 0;
-		next = (addr + 4096) & ~4095;
+		next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);
 		delta = next - addr;
 		if (delta >= sz)
 			break;
@@ -208,7 +208,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long
 pipe, void *buffer, int length, struct devrequest *req)
 {
 	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
-	ALLOC_ALIGN_BUFFER(struct qTD, qtd, 3, USB_DMA_MINALIGN);
+#define QTD_COUNT	3
+	ALLOC_ALIGN_BUFFER(struct qTD, qtd, QTD_COUNT, USB_DMA_MINALIGN);
 	int qtd_counter = 0;
 
 	volatile struct qTD *vtd;
@@ -230,7 +231,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long
 pipe, void *buffer, le16_to_cpu(req->index));
 
 	memset(qh, 0, sizeof(struct QH));
-	memset(qtd, 0, 3 * sizeof(*qtd));
+	memset(qtd, 0, QTD_COUNT * sizeof(*qtd));
 
 	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
@@ -246,19 +247,20 @@ ehci_submit_async(struct usb_device *dev, unsigned

long pipe, void *buffer, */

drivers/usb/host/ehci-hcd.c +0 -2
 	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) |

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, · line 252

Quoted 10 lines
drivers/usb/host/ehci-hcd.c +3 -7
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |

Maybe define it as #deifne QH_ENDPT1(x) ((x) << SEOMTHING) ? [...]

Quoted 7 lines
drivers/usb/host/ehci-hcd.c +1 -1
@@ -398,50 +408,53 @@ ehci_submit_async(struct usb_device *dev, unsigned
 long pipe, void *buffer, ALIGN((uint32_t)buffer + length,
 ARCH_DMA_MINALIGN));
 
 	/* Check that the TD processing happened */
-	if (token & 0x80) {
+	if (token & (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS))

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned · line 420

Quoted 10 lines
drivers/usb/host/ehci-hcd.c +1 -2
 		printf("EHCI timed out on TD - token=%#x\n", token);
-	}
 
 	/* Disable async schedule. */
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	cmd &= ~CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0,

Ooooh, nice catch :)

[...]
The rest is cool.

btw when (I hope you will) resubmitting next time, just submit the whole series under 0/8 patch (or 1/8) of the old one to make it a nice thread.

#2 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Dear Marek Vasut,

Quoted 75 lines

Dear Beno?t Th?baudeau,

Quoted 73 lines
Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: N/A.
Changes for v3:
- New patch.

 .../drivers/usb/host/ehci-hcd.c                    |  135
+++++++++++--------- .../drivers/usb/host/ehci.h
                       |

75 ++++++++++- 2 files changed, 150 insertions(+), 60 deletions(-)

(quoted diff) +0 -0

u-boot-usb-8d5fb14/drivers/usb/host/ehci-hcd.c index 5b3b906..1977c28
100644

drivers/usb/host/ehci-hcd.c +2 -2
@@ -163,7 +163,7 @@ static int ehci_reset(void)
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&hcor->or_txfilltuning);
-	cmd &= ~TXFIFO_THRESH(0x3f);
+	cmd &= ~TXFIFO_THRESH_MASK;
 	cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
 	ehci_writel(&hcor->or_txfilltuning, cmd);
 #endif
@@ -186,7 +186,7 @@ static int ehci_td_buffer(struct qTD *td, void
 *buf,
 size_t sz) while (idx < QT_BUFFER_CNT) {
 		td->qt_buffer[idx] = cpu_to_hc32(addr);
 		td->qt_buffer_hi[idx] = 0;
-		next = (addr + 4096) & ~4095;
+		next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);
 		delta = next - addr;
 		if (delta >= sz)
drivers/usb/host/ehci-hcd.c +0 -0
 			break;
@@ -208,7 +208,8 @@ ehci_submit_async(struct usb_device *dev,

unsigned long
pipe, void *buffer, int length, struct devrequest *req)
{

drivers/usb/host/ehci-hcd.c +2 -1
 	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
-	ALLOC_ALIGN_BUFFER(struct qTD, qtd, 3, USB_DMA_MINALIGN);
+#define QTD_COUNT	3
+	ALLOC_ALIGN_BUFFER(struct qTD, qtd, QTD_COUNT, USB_DMA_MINALIGN);
 	int qtd_counter = 0;
 
 	volatile struct qTD *vtd;
@@ -230,7 +231,7 @@ ehci_submit_async(struct usb_device *dev,

unsigned long
pipe, void *buffer, le16_to_cpu(req->index));

drivers/usb/host/ehci-hcd.c +1 -1
 	memset(qh, 0, sizeof(struct QH));
-	memset(qtd, 0, 3 * sizeof(*qtd));
+	memset(qtd, 0, QTD_COUNT * sizeof(*qtd));
 
 	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe),
 	usb_pipeout(pipe));
@@ -246,19 +247,20 @@ ehci_submit_async(struct usb_device *dev,

unsigned
long pipe, void *buffer, */

drivers/usb/host/ehci-hcd.c +0 -7
 	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) |
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
Quoted 8 lines

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, · line 252

Quoted 5 lines
drivers/usb/host/ehci-hcd.c +3 -2
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |

Maybe define it as #deifne QH_ENDPT1(x) ((x) << SEOMTHING) ? [...]

For all of these?

Quoted 21 lines
Quoted 8 lines
drivers/usb/host/ehci-hcd.c +0 -0
@@ -398,50 +408,53 @@ ehci_submit_async(struct usb_device *dev,

unsigned
long pipe, void *buffer, ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN));

drivers/usb/host/ehci-hcd.c +1 -1
 	/* Check that the TD processing happened */
-	if (token & 0x80) {
+	if (token & (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS))

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, · line 419

Quoted 10 lines
drivers/usb/host/ehci-hcd.c +1 -2
 		printf("EHCI timed out on TD - token=%#x\n", token);
-	}
 
 	/* Disable async schedule. */
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	cmd &= ~CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0,

Ooooh, nice catch :)

Quoted 6 lines

[...]
The rest is cool.

btw when (I hope you will) resubmitting next time, just submit the whole series
under 0/8 patch (or 1/8) of the old one to make it a nice thread.

OK, so with 2/8 removed since you have applied it. What is the rule here? I thought that a new version of a patch should be posted as a reply to the previous version so that patchwork could mark the old version as superseded (even if this feature is not yet available for U-Boot). Does it apply only to single patches while series should be replied to the previous 0/n?

And should 3/n be a reply to 2/n, to 0/n (or to 1/n if no 0/n), or to nothing?

I will wait for your review of 8/8.

Best regards,
Beno?t

#3 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Dear Beno?t Th?baudeau,

[...]

Quoted 23 lines
Quoted 7 lines
Quoted 7 lines
(quoted diff) +0 -0
@@ -246,19 +247,20 @@ ehci_submit_async(struct usb_device *dev,

unsigned
long pipe, void *buffer, */

drivers/usb/host/ehci-hcd.c +0 -0
 	qh->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);
 	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
Quoted 15 lines

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, · line 252

Quoted 12 lines
drivers/usb/host/ehci-hcd.c +3 -9
-	     usb_pipeendpoint(pipe) == 0) ? 1 : 0;
-	endpt = (8 << 28) |
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |

Maybe define it as #deifne QH_ENDPT1(x) ((x) << SEOMTHING) ? [...]

Quoted 1 line

For all of these?

Yes, do you not think it's better than define the offsets only?

Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
(quoted diff) +0 -0
@@ -398,50 +408,53 @@ ehci_submit_async(struct usb_device *dev,

unsigned
long pipe, void *buffer, ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN));

(quoted diff) +1 -1
 	/* Check that the TD processing happened */
 
-	if (token & 0x80) {
+	if (token & (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS))
 
 		printf("EHCI timed out on TD - token=%#x\n", token);

Review

Quoted 10 lines
(quoted diff) +1 -2
 
-	}
 
 	/* Disable async schedule. */
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	cmd &= ~CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0,

Ooooh, nice catch :)

Quoted 8 lines
Quoted 6 lines

[...]
The rest is cool.

btw when (I hope you will) resubmitting next time, just submit the whole series
under 0/8 patch (or 1/8) of the old one to make it a nice thread.

OK, so with 2/8 removed since you have applied it.

Yes

Quoted 3 lines

What is the rule here? I
thought that a new version of a patch should be posted as a reply to the previous version so that patchwork could mark the old version as superseded

Yes, unless the series changed so much (aka. too much reordering etc), that it's easier to repost it in reply to the first patch in the series.

Quoted 2 lines

(even if this feature is not yet available for U-Boot). Does it apply only to single patches while series should be replied to the previous 0/n?

I didn't figure out these gems in patchwork myself. I'm not a big fan of PW either.

Quoted 2 lines

And should 3/n be a reply to 2/n, to 0/n (or to 1/n if no 0/n), or to nothing?

Just use the standard threading git send-email does.

Quoted 1 line

I will wait for your review of 8/8.

I think it's fine to just resend it so I'll either pick first 7 or all 8. First 7 are certain once we agree on the above stuff :)

Quoted 2 lines

Best regards,
Beno?t

Best regards,
Marek Vasut

#4 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Dear Marek Vasut,

Quoted 24 lines
Quoted 24 lines
Quoted 23 lines
Quoted 10 lines
(quoted diff) +0 -0
@@ -246,19 +247,20 @@ ehci_submit_async(struct usb_device *dev,

unsigned
long pipe, void *buffer, */

drivers/usb/host/ehci-hcd.c +0 -2
 	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) |

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, · line 252

Quoted 10 lines
drivers/usb/host/ehci-hcd.c +3 -7
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |

Maybe define it as #deifne QH_ENDPT1(x) ((x) << SEOMTHING) ? [...]

Quoted 3 lines
Quoted 1 line

For all of these?

Yes, do you not think it's better than define the offsets only?

Yes, I hesitated with this solution when writing this code.

Where the offset is needed, I can instead write additional extraction macros.

Quoted 59 lines
Quoted 27 lines
Quoted 27 lines
Quoted 11 lines
(quoted diff) +0 -0
@@ -398,50 +408,53 @@ ehci_submit_async(struct usb_device *dev,

unsigned
long pipe, void *buffer, ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN));

(quoted diff) +1 -1
 	/* Check that the TD processing happened */
 
-	if (token & 0x80) {
+	if (token & (QT_TOKEN_STATUS_ACTIVE << QT_TOKEN_STATUS))
 
 		printf("EHCI timed out on TD - token=%#x\n", token);

Review

Quoted 10 lines
(quoted diff) +1 -2
 
-	}
 
 	/* Disable async schedule. */
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	cmd &= ~CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0,

Ooooh, nice catch :)

[...]
The rest is cool.

Quoted 6 lines
Quoted 4 lines

btw when (I hope you will) resubmitting next time, just submit the
whole series
under 0/8 patch (or 1/8) of the old one to make it a nice thread.

OK, so with 2/8 removed since you have applied it.

Yes

Quoted 5 lines

What is the rule here? I
thought that a new version of a patch should be posted as a reply to the
previous version so that patchwork could mark the old version as superseded

Yes, unless the series changed so much (aka. too much reordering etc), that it's
easier to repost it in reply to the first patch in the series.

Quoted 4 lines

(even if this feature is not yet available for U-Boot). Does it apply only
to single patches while series should be replied to the previous 0/n?

I didn't figure out these gems in patchwork myself. I'm not a big fan of PW
either.

Quoted 3 lines

And should 3/n be a reply to 2/n, to 0/n (or to 1/n if no 0/n), or to
nothing?

Quoted 7 lines

Just use the standard threading git send-email does.

Quoted 1 line

I will wait for your review of 8/8.

I think it's fine to just resend it so I'll either pick first 7 or all 8. First
7 are certain once we agree on the above stuff :)

OK.

Best regards,
Beno?t

#5 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Dear Beno?t Th?baudeau,

Quoted 26 lines

Dear Marek Vasut,

Quoted 24 lines
Quoted 24 lines
Quoted 23 lines
Quoted 10 lines
(quoted diff) +0 -0
@@ -246,19 +247,20 @@ ehci_submit_async(struct usb_device *dev,

unsigned
long pipe, void *buffer, */

drivers/usb/host/ehci-hcd.c +0 -2
 	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) |

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, · line 252

Quoted 10 lines
drivers/usb/host/ehci-hcd.c +3 -7
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |

Maybe define it as #deifne QH_ENDPT1(x) ((x) << SEOMTHING) ? [...]

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

For all of these?

Yes, do you not think it's better than define the offsets only?

Yes, I hesitated with this solution when writing this code.

Where the offset is needed, I can instead write additional extraction macros.

Oh, there're places where the offset is needed? What about adding both BIT(x) and BIT_OFFSET in such cases ? And BIT(x) (x << BIT_OFFSET) in that case.

[...]

Best regards,
Marek Vasut

#6 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Dear Marek Vasut,

Quoted 29 lines
Quoted 29 lines
Quoted 28 lines
Quoted 25 lines
Quoted 9 lines
Quoted 9 lines
(quoted diff) +0 -0
@@ -246,19 +247,20 @@ ehci_submit_async(struct usb_device
 *dev,

unsigned
long pipe, void *buffer, */

(quoted diff) +0 -0
 	qh->qh_link = cpu_to_hc32((uint32_t)qh_list |
 	QH_LINK_TYPE_QH);
 	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
Quoted 15 lines

drivers/usb/host/ehci-hcd.c ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, · line 252

Quoted 12 lines
drivers/usb/host/ehci-hcd.c +3 -9
-	     usb_pipeendpoint(pipe) == 0) ? 1 : 0;
-	endpt = (8 << 28) |
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |

Maybe define it as #deifne QH_ENDPT1(x) ((x) << SEOMTHING) ? [...]

Quoted 1 line

For all of these?

Yes, do you not think it's better than define the offsets only?

Quoted 7 lines
Quoted 5 lines

Yes, I hesitated with this solution when writing this code.

Where the offset is needed, I can instead write additional extraction
macros.

Oh, there're places where the offset is needed?

Yes, I think.

Quoted 4 lines

What about adding
both BIT(x)
and BIT_OFFSET in such cases ? And BIT(x) (x << BIT_OFFSET) in that case.

I would prefer:
#define FIELD(fldval) (((fldval) & MASK) << OFFSET)
#define GET_FIELD(regval) (((regval) >> OFFSET) & MASK)

Are you OK with that?

Best regards,
Beno?t

#7 lore raw

PATCH v3 1/8 ehci: cosmetic: Define used constants

Dear Beno?t Th?baudeau,

Quoted 41 lines

Dear Marek Vasut,

Quoted 29 lines
Quoted 29 lines
Quoted 28 lines
Quoted 25 lines
Quoted 9 lines
Quoted 9 lines
(quoted diff) +0 -0
@@ -246,19 +247,20 @@ ehci_submit_async(struct usb_device
 *dev,

unsigned
long pipe, void *buffer, */

(quoted diff) +0 -0
 	qh->qh_link = cpu_to_hc32((uint32_t)qh_list |
 	QH_LINK_TYPE_QH);
 	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
Quoted 15 lines

Review

Quoted 12 lines
(quoted diff) +3 -9
-	     usb_pipeendpoint(pipe) == 0) ? 1 : 0;
-	endpt = (8 << 28) |
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	     usb_pipeendpoint(pipe) == 0);
+	endpt = (8 << QH_ENDPT1_RL) |
+	    (c << QH_ENDPT1_C) |

Maybe define it as #deifne QH_ENDPT1(x) ((x) << SEOMTHING) ? [...]

Quoted 1 line

For all of these?

Yes, do you not think it's better than define the offsets only?

Quoted 7 lines
Quoted 5 lines

Yes, I hesitated with this solution when writing this code.

Where the offset is needed, I can instead write additional extraction
macros.

Oh, there're places where the offset is needed?

Yes, I think.

Quoted 8 lines
Quoted 4 lines

What about adding
both BIT(x)
and BIT_OFFSET in such cases ? And BIT(x) (x << BIT_OFFSET) in that case.

I would prefer:
#define FIELD(fldval) (((fldval) & MASK) << OFFSET)
#define GET_FIELD(regval) (((regval) >> OFFSET) & MASK)

Yes of course.

Quoted 4 lines

Are you OK with that?

Best regards,
Beno?t

Best regards,
Marek Vasut

#9 lore raw

PATCH v4 1/7 ehci: cosmetic: Define used constants

Make some light cosmetic code cleanup by the way.

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: N/A.
Changes for v3:
- New patch.
Changes for v4:
- Use accessor macros rather than offsets and masks.
- More code cleanup.

 .../drivers/usb/host/ehci-hcd.c                    |  138 ++++++++++----------
 .../drivers/usb/host/ehci.h                        |   49 ++++++-
 2 files changed, 118 insertions(+), 69 deletions(-)
drivers/usb/host/ehci-hcd.c +70 -68
index 2a00389..00a155b 100644
@@ -163,7 +163,7 @@ static int ehci_reset(void)
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&hcor->or_txfilltuning);
-	cmd &= ~TXFIFO_THRESH(0x3f);
+	cmd &= ~TXFIFO_THRESH_MASK;
 	cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
 	ehci_writel(&hcor->or_txfilltuning, cmd);
 #endif
@@ -186,7 +186,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
 	while (idx < QT_BUFFER_CNT) {
 		td->qt_buffer[idx] = cpu_to_hc32(addr);
 		td->qt_buffer_hi[idx] = 0;
-		next = (addr + 4096) & ~4095;
+		next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);
 		delta = next - addr;
 		if (delta >= sz)
 			break;
@@ -208,7 +208,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		   int length, struct devrequest *req)
 {
 	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
-	ALLOC_ALIGN_BUFFER(struct qTD, qtd, 3, USB_DMA_MINALIGN);
+#define QTD_COUNT	3
+	ALLOC_ALIGN_BUFFER(struct qTD, qtd, QTD_COUNT, USB_DMA_MINALIGN);
 	int qtd_counter = 0;
 
 	volatile struct qTD *vtd;
@@ -230,7 +231,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		      le16_to_cpu(req->index));
 
 	memset(qh, 0, sizeof(struct QH));
-	memset(qtd, 0, 3 * sizeof(*qtd));
+	memset(qtd, 0, QTD_COUNT * sizeof(*qtd));
 
 	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
@@ -245,20 +246,17 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	 * - qh_overlay.qt_altnext
 	 */
 	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) |
-	    (c << 27) |
-	    (usb_maxpacket(dev, pipe) << 16) |
-	    (0 << 15) |
-	    (1 << 14) |
-	    (usb_pipespeed(pipe) << 12) |
-	    (usb_pipeendpoint(pipe) << 8) |
-	    (0 << 7) | (usb_pipedevice(pipe) << 0);
+	c = usb_pipespeed(pipe) != USB_SPEED_HIGH && !usb_pipeendpoint(pipe);
+	endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) |
+		QH_ENDPT1_MAXPKTLEN(usb_maxpacket(dev, pipe)) | 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) |
+		QH_ENDPT1_DEVADDR(usb_pipedevice(pipe));
 	qh->qh_endpt1 = cpu_to_hc32(endpt);
-	endpt = (1 << 30) |
-	    (dev->portnr << 23) |
-	    (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
+	endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_PORTNUM(dev->portnr) |
+		QH_ENDPT2_HUBADDR(dev->parent->devnum) |
+		QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0);
 	qh->qh_endpt2 = cpu_to_hc32(endpt);
 	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
 
@@ -276,12 +274,13 @@ 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 = (0 << 31) |
-		    (sizeof(*req) << 16) |
-		    (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
+		token = QT_TOKEN_DT(0) | QT_TOKEN_TOTALBYTES(sizeof(*req)) |
+			QT_TOKEN_IOC(0) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) |
+			QT_TOKEN_PID(QT_TOKEN_PID_SETUP) |
+			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
 		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
-		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req)) != 0) {
-			printf("unable construct SETUP td\n");
+		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req))) {
+			printf("unable to construct SETUP TD\n");
 			goto fail;
 		}
 		/* Update previous qTD! */
@@ -302,15 +301,14 @@ 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 = (toggle << 31) |
-		    (length << 16) |
-		    ((req == NULL ? 1 : 0) << 15) |
-		    (0 << 12) |
-		    (3 << 10) |
-		    ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
+		token = QT_TOKEN_DT(toggle) | QT_TOKEN_TOTALBYTES(length) |
+			QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) |
+			QT_TOKEN_CERR(3) | QT_TOKEN_PID(usb_pipein(pipe) ?
+				QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) |
+			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
 		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
-		if (ehci_td_buffer(&qtd[qtd_counter], buffer, length) != 0) {
-			printf("unable construct DATA td\n");
+		if (ehci_td_buffer(&qtd[qtd_counter], buffer, length)) {
+			printf("unable to construct DATA TD\n");
 			goto fail;
 		}
 		/* Update previous qTD! */
@@ -328,12 +326,11 @@ 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 = (toggle << 31) |
-		    (0 << 16) |
-		    (1 << 15) |
-		    (0 << 12) |
-		    (3 << 10) |
-		    ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
+		token = QT_TOKEN_DT(toggle) | 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) |
+			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
 		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
 		/* Update previous qTD! */
 		*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
@@ -346,7 +343,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	flush_dcache_range((uint32_t)qh_list,
 		ALIGN_END_ADDR(struct QH, qh_list, 1));
 	flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1));
-	flush_dcache_range((uint32_t)qtd, ALIGN_END_ADDR(struct qTD, qtd, 3));
+	flush_dcache_range((uint32_t)qtd,
+			   ALIGN_END_ADDR(struct qTD, qtd, QTD_COUNT));
 
 	/* Set async. queue head pointer. */
 	ehci_writel(&hcor->or_asynclistaddr, (uint32_t)qh_list);
@@ -359,10 +357,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	cmd |= CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, STS_ASS,
 			100 * 1000);
 	if (ret < 0) {
-		printf("EHCI fail timeout STD_ASS set\n");
+		printf("EHCI fail timeout STS_ASS set\n");
 		goto fail;
 	}
 
@@ -377,10 +375,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		invalidate_dcache_range((uint32_t)qh,
 			ALIGN_END_ADDR(struct QH, qh, 1));
 		invalidate_dcache_range((uint32_t)qtd,
-			ALIGN_END_ADDR(struct qTD, qtd, 3));
+			ALIGN_END_ADDR(struct qTD, qtd, QTD_COUNT));
 
 		token = hc32_to_cpu(vtd->qt_token);
-		if (!(token & 0x80))
+		if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE))
 			break;
 		WATCHDOG_RESET();
 	} while (get_timer(ts) < timeout);
@@ -398,50 +396,50 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN));
 
 	/* Check that the TD processing happened */
-	if (token & 0x80) {
+	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
 		printf("EHCI timed out on TD - token=%#x\n", token);
-	}
 
 	/* Disable async schedule. */
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	cmd &= ~CMD_ASE;
 	ehci_writel(&hcor->or_usbcmd, cmd);
 
-	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0,
 			100 * 1000);
 	if (ret < 0) {
-		printf("EHCI fail timeout STD_ASS reset\n");
+		printf("EHCI fail timeout STS_ASS reset\n");
 		goto fail;
 	}
 
 	token = hc32_to_cpu(qh->qh_overlay.qt_token);
-	if (!(token & 0x80)) {
+	if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) {
 		debug("TOKEN=%#x\n", token);
-		switch (token & 0xfc) {
+		switch (QT_TOKEN_GET_STATUS(token) &
+			~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) {
 		case 0:
-			toggle = token >> 31;
+			toggle = QT_TOKEN_GET_DT(token);
 			usb_settoggle(dev, usb_pipeendpoint(pipe),
 				       usb_pipeout(pipe), toggle);
 			dev->status = 0;
 			break;
-		case 0x40:
+		case QT_TOKEN_STATUS_HALTED:
 			dev->status = USB_ST_STALLED;
 			break;
-		case 0xa0:
-		case 0x20:
+		case QT_TOKEN_STATUS_ACTIVE | QT_TOKEN_STATUS_DATBUFERR:
+		case QT_TOKEN_STATUS_DATBUFERR:
 			dev->status = USB_ST_BUF_ERR;
 			break;
-		case 0x50:
-		case 0x10:
+		case QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_BABBLEDET:
+		case QT_TOKEN_STATUS_BABBLEDET:
 			dev->status = USB_ST_BABBLE_DET;
 			break;
 		default:
 			dev->status = USB_ST_CRC_ERR;
-			if ((token & 0x40) == 0x40)
+			if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_HALTED)
 				dev->status |= USB_ST_STALLED;
 			break;
 		}
-		dev->act_len = length - ((token >> 16) & 0x7fff);
+		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
@@ -499,12 +497,14 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		case USB_DT_DEVICE:
 			debug("USB_DT_DEVICE request\n");
 			srcptr = &descriptor.device;
-			srclen = 0x12;
+			srclen = descriptor.device.bLength;
 			break;
 		case USB_DT_CONFIG:
 			debug("USB_DT_CONFIG config\n");
 			srcptr = &descriptor.config;
-			srclen = 0x19;
+			srclen = descriptor.config.bLength +
+					descriptor.interface.bLength +
+					descriptor.endpoint.bLength;
 			break;
 		case USB_DT_STRING:
 			debug("USB_DT_STRING config\n");
@@ -539,7 +539,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		case USB_DT_HUB:
 			debug("USB_DT_HUB config\n");
 			srcptr = &descriptor.hub;
-			srclen = 0x8;
+			srclen = descriptor.hub.bLength;
 			break;
 		default:
 			debug("unknown value %x\n", le16_to_cpu(req->value));
@@ -577,13 +577,13 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 
 		if (ehci_is_TDI()) {
-			switch ((reg >> 26) & 3) {
-			case 0:
+			switch (PORTSC_PSPD(reg)) {
+			case PORTSC_PSPD_FS:
 				break;
-			case 1:
+			case PORTSC_PSPD_LS:
 				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
 				break;
-			case 2:
+			case PORTSC_PSPD_HS:
 			default:
 				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 				break;
@@ -729,26 +729,28 @@ int usb_lowlevel_init(void)
 	uint32_t reg;
 	uint32_t cmd;
 
-	if (ehci_hcd_init() != 0)
+	if (ehci_hcd_init())
 		return -1;
 
 	/* EHCI spec section 4.1 */
-	if (ehci_reset() != 0)
+	if (ehci_reset())
 		return -1;
 
 #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
-	if (ehci_hcd_init() != 0)
+	if (ehci_hcd_init())
 		return -1;
 #endif
 
 	/* Set head of reclaim list */
 	memset(qh_list, 0, sizeof(*qh_list));
 	qh_list->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);
-	qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
+	qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) |
+						QH_ENDPT1_EPS(USB_SPEED_HIGH));
 	qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
 	qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
 	qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
-	qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40);
+	qh_list->qh_overlay.qt_token =
+			cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));
 
 	reg = ehci_readl(&hccr->cr_hcsparams);
 	descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
@@ -808,7 +810,7 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	}
 
 	if (usb_pipedevice(pipe) == rootdev) {
-		if (rootdev == 0)
+		if (!rootdev)
 			dev->speed = USB_SPEED_HIGH;
 		return ehci_submit_root(dev, pipe, buffer, length, setup);
 	}
drivers/usb/host/ehci.h +48 -1

85 lines not on this page · raw message

#10 lore raw

PATCH v4 2/7 ehci-hcd: Boost transfer speed

In reply to Benoît Thébaudeau

This patch takes advantage of the hardware EHCI qTD queuing mechanism to avoid software and transfer splitting overhead so as to make transfers as fast as possible.

The only drawback is a call to memalign. However, this is fast compared to the transfer timings, and the heap size to allocate is small, e.g. 128 kiB in the worst case for a transfer length of 65535 packets of 512 bytes.

Tested on i.MX25, i.MX35 and i.MX51. In my test conditions, the speed gain was very significant (several times faster), which is really appreciable when accessing large files.

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2:
- Use DIV_ROUND_UP to make code more readable.
Changes for v3:
- Remove extra unalignment term in the computation of qtd_count.
- Fix ZLP support.
- Add #warning if CONFIG_SYS_MALLOC_LEN is likely to be too small.
- Make code more readable.
- Add comments.
Changes for v4: None.

 .../drivers/usb/host/ehci-hcd.c                    |  167 ++++++++++++++++----
 1 file changed, 138 insertions(+), 29 deletions(-)
drivers/usb/host/ehci-hcd.c +138 -29
index 00a155b..a0ef5db 100644
@@ -208,8 +208,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		   int length, struct devrequest *req)
 {
 	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
-#define QTD_COUNT	3
-	ALLOC_ALIGN_BUFFER(struct qTD, qtd, QTD_COUNT, USB_DMA_MINALIGN);
+	struct qTD *qtd;
+	int qtd_count = 0;
 	int qtd_counter = 0;
 
 	volatile struct qTD *vtd;
@@ -230,8 +230,74 @@ 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));
 
+	/*
+	 * The USB transfer is split into qTD transfers. Eeach qTD transfer is
+	 * described by a transfer descriptor (the qTD). The qTDs form a linked
+	 * list with a queue head (QH).
+	 *
+	 * Each qTD transfer starts with a new USB packet, i.e. a packet cannot
+	 * have its beginning in a qTD transfer and its end in the following
+	 * one, so the qTD transfer lengths have to be chosen accordingly.
+	 *
+	 * Each qTD transfer uses up to QT_BUFFER_CNT data buffers, mapped to
+	 * single pages. The first data buffer can start at any offset within a
+	 * page (not considering the cache-line alignment issues), while the
+	 * following buffers must be page-aligned. There is no alignment
+	 * constraint on the size of a qTD transfer.
+	 */
+	if (req != NULL)
+		/* 1 qTD will be needed for SETUP, and 1 for ACK. */
+		qtd_count += 1 + 1;
+	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).
+		 *
+		 * 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()).
+		 *
+		 * By default, i.e. if the input buffer is page-aligned,
+		 * 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
+		 * data buffer of each transfer will be page-unaligned.
+		 */
+		if ((uint32_t)buffer & (EHCI_PAGE_SIZE - 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.
+		 */
+		qtd_count += DIV_ROUND_UP(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
+ * for a mass-storage transfer of 65535 blocks of 512 bytes.
+ */
+#if CONFIG_SYS_MALLOC_LEN <= 128 * 1024
+#warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI
+#endif
+	qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD));
+	if (qtd == NULL) {
+		printf("unable to allocate TDs\n");
+		return -1;
+	}
+
 	memset(qh, 0, sizeof(struct QH));
-	memset(qtd, 0, QTD_COUNT * sizeof(*qtd));
+	memset(qtd, 0, qtd_count * sizeof(*qtd));
 
 	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
@@ -290,30 +356,64 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	}
 
 	if (length > 0 || req == NULL) {
-		/*
-		 * Setup request qTD (3.5 in ehci-r10.pdf)
-		 *
-		 *   qt_next ................ 03-00 H
-		 *   qt_altnext ............. 07-04 H
-		 *   qt_token ............... 0B-08 H
-		 *
-		 *   [ buffer, buffer_hi ] loaded with "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(length) |
-			QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) |
-			QT_TOKEN_CERR(3) | QT_TOKEN_PID(usb_pipein(pipe) ?
-				QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) |
-			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
-		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
-		if (ehci_td_buffer(&qtd[qtd_counter], buffer, length)) {
-			printf("unable to construct DATA TD\n");
-			goto fail;
-		}
-		/* Update previous qTD! */
-		*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
-		tdp = &qtd[qtd_counter++].qt_next;
+		uint8_t *buf_ptr = buffer;
+		int left_length = length;
+
+		do {
+			/*
+			 * Determine the size of this qTD transfer. By default,
+			 * QT_BUFFER_CNT full pages can be used.
+			 */
+			int xfr_bytes = QT_BUFFER_CNT * EHCI_PAGE_SIZE;
+			/*
+			 * However, if the input buffer is not page-aligned, the
+			 * portion of the first page before the buffer start
+			 * offset within that page is unusable.
+			 */
+			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.
+			 */
+			xfr_bytes &= ~(EHCI_PAGE_SIZE - 1);
+			/*
+			 * This transfer may be shorter than the available qTD
+			 * transfer size that has just been computed.
+			 */
+			xfr_bytes = min(xfr_bytes, left_length);
+
+			/*
+			 * Setup request qTD (3.5 in ehci-r10.pdf)
+			 *
+			 *   qt_next ................ 03-00 H
+			 *   qt_altnext ............. 07-04 H
+			 *   qt_token ............... 0B-08 H
+			 *
+			 *   [ buffer, buffer_hi ] loaded with "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(xfr_bytes) |
+				QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) |
+				QT_TOKEN_CERR(3) |
+				QT_TOKEN_PID(usb_pipein(pipe) ?
+					QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) |
+				QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
+			qtd[qtd_counter].qt_token = cpu_to_hc32(token);
+			if (ehci_td_buffer(&qtd[qtd_counter], buf_ptr,
+						xfr_bytes)) {
+				printf("unable to construct DATA TD\n");
+				goto fail;
+			}
+			/* Update previous qTD! */
+			*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
+			tdp = &qtd[qtd_counter++].qt_next;
+			buf_ptr += xfr_bytes;
+			left_length -= xfr_bytes;
+		} while (left_length > 0);
 	}
 
 	if (req != NULL) {
@@ -344,7 +444,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		ALIGN_END_ADDR(struct QH, qh_list, 1));
 	flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1));
 	flush_dcache_range((uint32_t)qtd,
-			   ALIGN_END_ADDR(struct qTD, qtd, QTD_COUNT));
+			   ALIGN_END_ADDR(struct qTD, qtd, qtd_count));
 
 	/* Set async. queue head pointer. */
 	ehci_writel(&hcor->or_asynclistaddr, (uint32_t)qh_list);
@@ -375,7 +475,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		invalidate_dcache_range((uint32_t)qh,
 			ALIGN_END_ADDR(struct QH, qh, 1));
 		invalidate_dcache_range((uint32_t)qtd,
-			ALIGN_END_ADDR(struct qTD, qtd, QTD_COUNT));
+			ALIGN_END_ADDR(struct qTD, qtd, qtd_count));
 
 		token = hc32_to_cpu(vtd->qt_token);
 		if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE))
@@ -448,9 +548,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		      ehci_readl(&hcor->or_portsc[1]));
 	}
 
+	free(qtd);
 	return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
 
 fail:
+	free(qtd);
 	return -1;
 }
 
@@ -827,6 +929,13 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	/*
 	 * Interrupt transfers requiring several transactions are not supported
 	 * 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.
 	 */
 	if (length > usb_maxpacket(dev, pipe)) {
 		printf("%s: Interrupt transfers requiring several transactions "
#11 lore raw

v4 cover ehci: Improve performance

In reply to Benoît Thébaudeau

Beno?t Th?baudeau
Application Engineer
benoit.thebaudeau at advansee.com
+33 2 40 50 21 73
ADVANSEE SARL
9, rue Alfred Kastler
CS 30750
44307 Nantes CEDEX 3
France

----- Original Message -----

Quoted 16 lines

From: "Beno?t Th?baudeau" <[email protected]>
To: u-boot at lists.denx.de
Cc: "Marek Vasut" <[email protected]>, "Ilya Yanok" <[email protected]>, "Stefan Herbrechtsmeier" <[email protected]>
Sent: Friday, August 10, 2012 6:21:37 PM
Subject: [PATCH v4 0/7] ehci: Improve performance

Hi all,

This series aims at improving EHCI performance. There is also some code cleanup
BTW.

Best regards,
Beno?t

#12 lore raw

PATCH v4 3/7 usb_storage: Restore non-EHCI support

In reply to Benoît Thébaudeau

The commit 5dd95cf made the MSC driver EHCI-specific. This patch restores a basic support of non-EHCI HCDs, like before that commit.

The fallback transfer size is certainly not optimal, but at least it should work like before.

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: None.
Changes for v3:
- Patch swapped with the currently following one.
Changes for v4: None.

 .../common/usb_storage.c                           |    4 ++++
 1 file changed, 4 insertions(+)
common/usb_storage.c +4 -0
index bdc306f..0cd6399 100644
@@ -155,11 +155,15 @@ struct us_data {
 	trans_cmnd	transport;		/* transport routine */
 };
 
+#ifdef CONFIG_USB_EHCI
 /*
  * The U-Boot EHCI driver cannot handle more than 5 page aligned buffers
  * of 4096 bytes in a transfer without running itself out of qt_buffers
  */
 #define USB_MAX_XFER_BLK(start, blksz)	(((4096 * 5) - (start % 4096)) / blksz)
+#else
+#define USB_MAX_XFER_BLK(start, blksz)	20
+#endif
 
 static struct us_data usb_stor[USB_MAX_STOR_DEV];
 
#13 lore raw

PATCH v4 4/7 usb_storage: Remove EHCI constraints

In reply to Benoît Thébaudeau

Now that the EHCI driver allocates its qTDs from the heap, the MSC driver is only limited by the SCSI commands it uses.

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: None.
Changes for v3:
- Patch swapped with the currently preceding one.
Changes for v4: None.

 .../common/usb_storage.c                           |   33 +++++++++-----------
 1 file changed, 15 insertions(+), 18 deletions(-)
common/usb_storage.c +15 -18
index 0cd6399..822bd64 100644
@@ -157,12 +157,13 @@ struct us_data {
 
 #ifdef CONFIG_USB_EHCI
 /*
- * The U-Boot EHCI driver cannot handle more than 5 page aligned buffers
- * of 4096 bytes in a transfer without running itself out of qt_buffers
+ * The U-Boot EHCI driver can handle any transfer length as long as there is
+ * enough free heap space left, but the SCSI READ(10) and WRITE(10) commands are
+ * limited to 65535 bytes.
  */
-#define USB_MAX_XFER_BLK(start, blksz)	(((4096 * 5) - (start % 4096)) / blksz)
+#define USB_MAX_XFER_BLK	65535
 #else
-#define USB_MAX_XFER_BLK(start, blksz)	20
+#define USB_MAX_XFER_BLK	20
 #endif
 
 static struct us_data usb_stor[USB_MAX_STOR_DEV];
@@ -1050,7 +1051,7 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor,
 unsigned long usb_stor_read(int device, unsigned long blknr,
 			    unsigned long blkcnt, void *buffer)
 {
-	unsigned long start, blks, buf_addr, max_xfer_blk;
+	unsigned long start, blks, buf_addr;
 	unsigned short smallblks;
 	struct usb_device *dev;
 	struct us_data *ss;
@@ -1092,14 +1093,12 @@ unsigned long usb_stor_read(int device, unsigned long blknr,
 		/* XXX need some comment here */
 		retry = 2;
 		srb->pdata = (unsigned char *)buf_addr;
-		max_xfer_blk = USB_MAX_XFER_BLK(buf_addr,
-						usb_dev_desc[device].blksz);
-		if (blks > max_xfer_blk)
-			smallblks = (unsigned short) max_xfer_blk;
+		if (blks > USB_MAX_XFER_BLK)
+			smallblks = USB_MAX_XFER_BLK;
 		else
 			smallblks = (unsigned short) blks;
 retry_it:
-		if (smallblks == max_xfer_blk)
+		if (smallblks == USB_MAX_XFER_BLK)
 			usb_show_progress();
 		srb->datalen = usb_dev_desc[device].blksz * smallblks;
 		srb->pdata = (unsigned char *)buf_addr;
@@ -1120,7 +1119,7 @@ retry_it:
 			start, smallblks, buf_addr);
 
 	usb_disable_asynch(0); /* asynch transfer allowed */
-	if (blkcnt >= max_xfer_blk)
+	if (blkcnt >= USB_MAX_XFER_BLK)
 		debug("\n");
 	return blkcnt;
 }
@@ -1128,7 +1127,7 @@ retry_it:
 unsigned long usb_stor_write(int device, unsigned long blknr,
 				unsigned long blkcnt, const void *buffer)
 {
-	unsigned long start, blks, buf_addr, max_xfer_blk;
+	unsigned long start, blks, buf_addr;
 	unsigned short smallblks;
 	struct usb_device *dev;
 	struct us_data *ss;
@@ -1173,14 +1172,12 @@ unsigned long usb_stor_write(int device, unsigned long blknr,
 		 */
 		retry = 2;
 		srb->pdata = (unsigned char *)buf_addr;
-		max_xfer_blk = USB_MAX_XFER_BLK(buf_addr,
-						usb_dev_desc[device].blksz);
-		if (blks > max_xfer_blk)
-			smallblks = (unsigned short) max_xfer_blk;
+		if (blks > USB_MAX_XFER_BLK)
+			smallblks = USB_MAX_XFER_BLK;
 		else
 			smallblks = (unsigned short) blks;
 retry_it:
-		if (smallblks == max_xfer_blk)
+		if (smallblks == USB_MAX_XFER_BLK)
 			usb_show_progress();
 		srb->datalen = usb_dev_desc[device].blksz * smallblks;
 		srb->pdata = (unsigned char *)buf_addr;
@@ -1201,7 +1198,7 @@ retry_it:
 			start, smallblks, buf_addr);
 
 	usb_disable_asynch(0); /* asynch transfer allowed */
-	if (blkcnt >= max_xfer_blk)
+	if (blkcnt >= USB_MAX_XFER_BLK)
 		debug("\n");
 	return blkcnt;
 
#14 lore raw

PATCH v4 4/7 usb_storage: Remove EHCI constraints

Hi Benoit,

Quoted 12 lines · Beno?t Th?baudeau
(quoted diff) +0 -0

u-boot-usb-4f8254e/common/usb_storage.c
index 0cd6399..822bd64 100644

common/usb_storage.c +1 -2
@@ -157,12 +157,13 @@ struct us_data {
 
 #ifdef CONFIG_USB_EHCI
 /*
- * The U-Boot EHCI driver cannot handle more than 5 page aligned buffers
- * of 4096 bytes in a transfer without running itself out of qt_buffers
+ * The U-Boot EHCI driver can handle any transfer length as long as there
Quoted 5 lines

is
+ * enough free heap space left, but the SCSI READ(10) and WRITE(10) commands are
+ * limited to 65535 bytes.

bytes?

Quoted 5 lines

*/
-#define USB_MAX_XFER_BLK(start, blksz) (((4096 * 5) - (start % 4096)) / blksz)
+#define USB_MAX_XFER_BLK 65535

But here you limit it to 65535 _blocks_, right? One of the two should be wrong ;)

Regards, Ilya.

#15 lore raw

PATCH v4 4/7 usb_storage: Remove EHCI constraints

Hi Ilya,

Quoted 42 lines · Ilya Yanok

Hi Benoit,

Quoted 26 lines · Beno?t Th?baudeau
(quoted diff) +0 -0

u-boot-usb-4f8254e/common/usb_storage.c

index 0cd6399..822bd64 100644

--- u-boot-usb-4f8254e.orig/common/usb_storage.c

+++ u-boot-usb-4f8254e/common/usb_storage.c

(quoted diff) +0 -1
@@ -157,12 +157,13 @@ struct us_data {
 
 
 #ifdef CONFIG_USB_EHCI
 
 /*
 
- * The U-Boot EHCI driver cannot handle more than 5 page aligned

buffers

- * of 4096 bytes in a transfer without running itself out of qt_buffers

+ * The U-Boot EHCI driver can handle any transfer length as long as
there is

Quoted 5 lines

+ * enough free heap space left, but the SCSI READ(10) and WRITE(10)
commands are

+ * limited to 65535 bytes.

bytes?

Quoted 1 line

*/

Quoted 8 lines
Quoted 4 lines

-#define USB_MAX_XFER_BLK(start, blksz) (((4096 * 5) - (start % 4096)) / blksz)

+#define USB_MAX_XFER_BLK 65535

But here you limit it to 65535 _blocks_, right? One of the two should be wrong ;)

Argh, it was a typo in the comment. Thanks for catching this. I meant "blocks" of course. Marek, can you fix this comment on-the-fly when applying?

Best regards,
Beno?t

#16 lore raw

PATCH v4 4/7 usb_storage: Remove EHCI constraints

Dear Beno?t Th?baudeau,

Quoted 47 lines

Hi Ilya,

Quoted 44 lines · Ilya Yanok

Hi Benoit,

On Fri, Aug 10, 2012 at 8:23 PM, Beno?t Th?baudeau <

Quoted 26 lines · benoit.thebaudeau at advansee.com > wrote:
(quoted diff) +0 -0

u-boot-usb-4f8254e/common/usb_storage.c

index 0cd6399..822bd64 100644

--- u-boot-usb-4f8254e.orig/common/usb_storage.c

+++ u-boot-usb-4f8254e/common/usb_storage.c

(quoted diff) +0 -1
@@ -157,12 +157,13 @@ struct us_data {
 
 
 #ifdef CONFIG_USB_EHCI
 
 /*
 
- * The U-Boot EHCI driver cannot handle more than 5 page aligned

buffers

- * of 4096 bytes in a transfer without running itself out of qt_buffers

+ * The U-Boot EHCI driver can handle any transfer length as long as
there is

Quoted 5 lines

+ * enough free heap space left, but the SCSI READ(10) and WRITE(10)
commands are

+ * limited to 65535 bytes.

bytes?

Quoted 5 lines

*/

-#define USB_MAX_XFER_BLK(start, blksz) (((4096 * 5) - (start % 4096)) / blksz)

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

+#define USB_MAX_XFER_BLK 65535

But here you limit it to 65535 _blocks_, right? One of the two should be wrong ;)

Argh, it was a typo in the comment. Thanks for catching this. I meant "blocks" of course. Marek, can you fix this comment on-the-fly when applying?

Roger, will do!

Quoted 2 lines

Best regards,
Beno?t

Best regards,
Marek Vasut

#17 lore raw

PATCH v4 5/7 usb_storage: Adjust time-outs

In reply to Benoît Thébaudeau

Adjust time-out value for the new EHCI mechanism.

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: None.
Changes for v3: None.
Changes for v4: None.

 .../common/usb_storage.c                           |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
common/usb_storage.c +1 -1
index 822bd64..f0798b2 100644
@@ -712,7 +712,7 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
 	else
 		pipe = pipeout;
 	result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
-			      &data_actlen, USB_CNTL_TIMEOUT * 5);
+			      &data_actlen, USB_CNTL_TIMEOUT * 100);
 	/* special handling of STALL in DATA phase */
 	if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
 		USB_STOR_PRINTF("DATA:stall\n");
#18 lore raw

PATCH v4 5/7 usb_storage: Adjust time-outs

Hi Benoit,

Quoted 2 lines · Beno?t Th?baudeau

Adjust time-out value for the new EHCI mechanism.

Could you please be a bit more specific? ;)

How this timeout is related to the new mechanism? Is it really EHCI specific? If it is, that's hardcoding of lower layer details again, I think that's undesirable...

But generally this series looks really good. Thanks a lot!

Regards, Ilya.

#19 lore raw

PATCH v4 5/7 usb_storage: Adjust time-outs

Hi Ilya,

Quoted 5 lines · Ilya Yanok

Hi Benoit,

On Fri, Aug 10, 2012 at 8:23 PM, Beno?t Th?baudeau < benoit.thebaudeau at advansee.com > wrote:

Quoted 8 lines
Quoted 1 line

Adjust time-out value for the new EHCI mechanism.

Could you please be a bit more specific? ;)

How this timeout is related to the new mechanism? Is it really EHCI specific? If it is, that's hardcoding of lower layer details again, I think that's undesirable...

Well, I did this specific patch a very long time ago, and I don't remember the details. I know that things did not work without it in my test conditions at that time. I've just run again all my tests with the current code on all my platforms without this patch, and everything works fine. So it was perhaps a device-related issue rather than an EHCI-related one. Since the rationale for this patch is no longer clear and things work fine without it, we can probably drop it. I let you and Marek decide.

Quoted 1 line

But generally this series looks really good. Thanks a lot!

Great. You're welcome.

Best regards,
Beno?t

#20 lore raw

PATCH v4 6/7 usb_stor_BBB_transport: Do not delay when not required

In reply to Benoît Thébaudeau

There is a 5-ms delay in usb_stor_BBB_transport, which occurs every 10 kiB of data for fragmented fatload usb, i.e. roughly 500 ms of delay per MiB. This adds up to quite a bit of delay if you're loading a large ramdisk.

The purpose of this delay should be to debounce the 5-V/100-mA USB power up. This patch skips the delay if the device has already been queried as ready.

Rework following the review:
- Rebase against the latest u-boot-usb master.
- Replace typedef with #define.
- Use the existing flags struct field instead of adding a new field.
- Remove the setter function.
- Remove the typecasts.

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>
Cc Jim Shimer <[email protected]>

---
Changes for v2: N/A.
Changes for v3:
- New patch.
Changes for v4: None.

 .../common/usb_storage.c                           |   11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
common/usb_storage.c +9 -2
index f0798b2..b000f09 100644
@@ -136,6 +136,7 @@ struct us_data {
 	struct usb_device *pusb_dev;	 /* this usb_device */
 
 	unsigned int	flags;			/* from filter initially */
+#	define USB_READY	(1 << 0)
 	unsigned char	ifnum;			/* interface number */
 	unsigned char	ep_in;			/* in endpoint */
 	unsigned char	ep_out;			/* out ....... */
@@ -698,7 +699,8 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
 		usb_stor_BBB_reset(us);
 		return USB_STOR_TRANSPORT_FAILED;
 	}
-	mdelay(5);
+	if (!(us->flags & USB_READY))
+		mdelay(5);
 	pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
 	pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
 	/* DATA phase + error handling */
@@ -963,8 +965,10 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
 		srb->cmd[1] = srb->lun << 5;
 		srb->datalen = 0;
 		srb->cmdlen = 12;
-		if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
+		if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
+			ss->flags |= USB_READY;
 			return 0;
+		}
 		usb_request_sense(srb, ss);
 		mdelay(100);
 	} while (retries--);
@@ -1114,6 +1118,7 @@ retry_it:
 		blks -= smallblks;
 		buf_addr += srb->datalen;
 	} while (blks != 0);
+	ss->flags &= ~USB_READY;
 
 	USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",
 			start, smallblks, buf_addr);
@@ -1193,6 +1198,7 @@ retry_it:
 		blks -= smallblks;
 		buf_addr += srb->datalen;
 	} while (blks != 0);
+	ss->flags &= ~USB_READY;
 
 	USB_STOR_PRINTF("usb_write: end startblk %lx, blccnt %x buffer %lx\n",
 			start, smallblks, buf_addr);
@@ -1404,6 +1410,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
 		cap[0] = 2880;
 		cap[1] = 0x200;
 	}
+	ss->flags &= ~USB_READY;
 	USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n", cap[0],
 			cap[1]);
 #if 0
#21 lore raw

PATCH v4 7/7 ehci: Optimize qTD allocations

In reply to Benoît Thébaudeau

Relax the qTD transfer alignment constraints in order to need less qTDs for buffers that are aligned to 512 bytes but not to pages.

Cc Marek Vasut <[email protected]>
Cc Ilya Yanok <[email protected]>
Cc Stefan Herbrechtsmeier <[email protected]>

---
Changes for v2: N/A.
Changes for v3:
- New patch.
Changes for v4:
- Optimize away the qtd_toggle variable.

 .../drivers/usb/host/ehci-hcd.c                    |   67 +++++++++++---------
 1 file changed, 37 insertions(+), 30 deletions(-)
drivers/usb/host/ehci-hcd.c +37 -30
index a0ef5db..18b4bc6 100644
@@ -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 "
#22 lore raw

v4 cover ehci: Improve performance

In reply to Benoît Thébaudeau

Dear Beno?t Th?baudeau,

Quoted 7 lines

Hi all,

This series aims at improving EHCI performance. There is also some code cleanup BTW.

Best regards,
Beno?t

Applied all but 5/7 and pushed. Since we all have vacations etc etc, this will appear in the mainline around start of september.

Thanks a lot for this awesome patchset! _Great_ work guys!

Best regards,
Marek Vasut

#23 lore raw

v4 cover ehci: Improve performance

Dear Marek Vasut,

Quoted 8 lines

Dear Beno?t Th?baudeau,

Quoted 6 lines

Hi all,

This series aims at improving EHCI performance. There is also some code
cleanup BTW.

Quoted 6 lines
Quoted 2 lines

Best regards,
Beno?t

Applied all but 5/7 and pushed. Since we all have vacations etc etc, this will
appear in the mainline around start of september.

Thanks. But will it make it for next release since September is after the official end of the current merge window?

I also have series for ehci-mxc and ehci-mx5 that I will try to post next week. They fix many things, add new features and add support for i.MX25 and i.MX35.

Quoted 1 line

Thanks a lot for this awesome patchset! _Great_ work guys!

Thanks.

Best regards,
Beno?t

#24 lore raw

v4 cover ehci: Improve performance

Dear Beno?t Th?baudeau,

Quoted 13 lines

Dear Marek Vasut,

Quoted 11 lines

Dear Beno?t Th?baudeau,

Quoted 8 lines

Hi all,

This series aims at improving EHCI performance. There is also some code
cleanup BTW.

Best regards,
Beno?t

Quoted 6 lines
Quoted 3 lines

Applied all but 5/7 and pushed. Since we all have vacations etc etc, this will
appear in the mainline around start of september.

Thanks. But will it make it for next release since September is after the official end of the current merge window?

If it's properly tested, I'll try to persuade WD to pull it in (and then the same round of horror as during the last release will repeat ;-) )

Quoted 3 lines

I also have series for ehci-mxc and ehci-mx5 that I will try to post next week. They fix many things, add new features and add support for i.MX25 and i.MX35.

Cool!

Quoted 6 lines
Quoted 1 line

Thanks a lot for this awesome patchset! _Great_ work guys!

Thanks.

Best regards,
Beno?t

Best regards,
Marek Vasut