[U-Boot] [PATCH fix for v2014.10 3/5] usb: ehci: poll_int_queue check real qtd, not the overlay

Hans de Goede hdegoede at redhat.com
Sat Sep 20 16:51:24 CEST 2014


When we first start an int queue, the qh's overlay area is all zeros. This
gets filled by the hc with the actual qtd values as soon as it advances
the queue, but we may call poll_int_queue before then, in which case we
would think the transfer has completed as the hc has not yet copied the
qt_token to the overlay, so the active flag is not set.

This fixes this by checking the actual qtd token, rather then the overlay.
This also fixes a (theoretical) race where we see the completion in the
overlay and free and re-use the qtd before the hc has completed writing back
the overlay to the actual qtd.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 drivers/usb/host/ehci-hcd.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1a0ddc3..635a3b4 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1297,6 +1297,7 @@ fail1:
 void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
 {
 	struct QH *cur = queue->current;
+	struct qTD *cur_td;
 
 	/* depleted queue */
 	if (cur == NULL) {
@@ -1304,20 +1305,21 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
 		return NULL;
 	}
 	/* still active */
-	invalidate_dcache_range((uint32_t)cur,
-				ALIGN_END_ADDR(struct QH, cur, 1));
-	if (cur->qh_overlay.qt_token & cpu_to_hc32(0x80)) {
-		debug("Exit poll_int_queue with no completed intr transfer. "
-		      "token is %x\n", cur->qh_overlay.qt_token);
+	cur_td = &queue->tds[queue->current - queue->first];
+	invalidate_dcache_range((uint32_t)cur_td,
+				ALIGN_END_ADDR(struct qTD, cur_td, 1));
+	if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) &
+			QT_TOKEN_STATUS_ACTIVE) {
+		debug("Exit poll_int_queue with no completed intr transfer. token is %x\n",
+		      hc32_to_cpu(cur_td->qt_token));
 		return NULL;
 	}
 	if (!(cur->qh_link & QH_LINK_TERMINATE))
 		queue->current++;
 	else
 		queue->current = NULL;
-	debug("Exit poll_int_queue with completed intr transfer. "
-	      "token is %x at %p (first at %p)\n", cur->qh_overlay.qt_token,
-	      &cur->qh_overlay.qt_token, queue->first);
+	debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
+	      hc32_to_cpu(cur_td->qt_token), cur, queue->first);
 	return cur->buffer;
 }
 
-- 
2.1.0



More information about the U-Boot mailing list