mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-20 17:08:52 +09:00
usb: ehci: poll_int_queue check real qtd, not the overlay
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@redhat.com>
This commit is contained in:
parent
ea7b30c589
commit
415548d884
@ -1297,6 +1297,7 @@ fail1:
|
|||||||
void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
|
void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
|
||||||
{
|
{
|
||||||
struct QH *cur = queue->current;
|
struct QH *cur = queue->current;
|
||||||
|
struct qTD *cur_td;
|
||||||
|
|
||||||
/* depleted queue */
|
/* depleted queue */
|
||||||
if (cur == NULL) {
|
if (cur == NULL) {
|
||||||
@ -1304,20 +1305,21 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* still active */
|
/* still active */
|
||||||
invalidate_dcache_range((uint32_t)cur,
|
cur_td = &queue->tds[queue->current - queue->first];
|
||||||
ALIGN_END_ADDR(struct QH, cur, 1));
|
invalidate_dcache_range((uint32_t)cur_td,
|
||||||
if (cur->qh_overlay.qt_token & cpu_to_hc32(0x80)) {
|
ALIGN_END_ADDR(struct qTD, cur_td, 1));
|
||||||
debug("Exit poll_int_queue with no completed intr transfer. "
|
if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) &
|
||||||
"token is %x\n", cur->qh_overlay.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;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(cur->qh_link & QH_LINK_TERMINATE))
|
if (!(cur->qh_link & QH_LINK_TERMINATE))
|
||||||
queue->current++;
|
queue->current++;
|
||||||
else
|
else
|
||||||
queue->current = NULL;
|
queue->current = NULL;
|
||||||
debug("Exit poll_int_queue with completed intr transfer. "
|
debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
|
||||||
"token is %x at %p (first at %p)\n", cur->qh_overlay.qt_token,
|
hc32_to_cpu(cur_td->qt_token), cur, queue->first);
|
||||||
&cur->qh_overlay.qt_token, queue->first);
|
|
||||||
return cur->buffer;
|
return cur->buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user