diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 7d03549c3339ecc5ebdc5025db1d9f3b6d42f148..11c627ce60224754978bf495e40cd94496c3b7c7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -903,7 +903,8 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* already started */ break; case QH_STATE_IDLE: - WARN_ON(1); + /* QH might be waiting for a Clear-TT-Buffer */ + qh_completions(ehci, qh); break; } break; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 9a1384747f3bc8ca092b226d6de8fed5d6850276..b27380505576d9489e6aff7cd426a9fd64f176b5 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -940,6 +940,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head->qh_next.qh = qh; head->hw_next = dma; + qh_get(qh); qh->xacterrs = QH_XACTERR_MAX; qh->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ @@ -1080,7 +1081,7 @@ submit_async ( * the HC and TT handle it when the TT has a buffer ready. */ if (likely (qh->qh_state == QH_STATE_IDLE)) - qh_link_async (ehci, qh_get (qh)); + qh_link_async(ehci, qh); done: spin_unlock_irqrestore (&ehci->lock, flags); if (unlikely (qh == NULL)) @@ -1115,8 +1116,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) qh_link_async (ehci, qh); else { - qh_put (qh); // refcount from async list - /* it's not free to turn the async schedule on/off; leave it * active but idle for a while once it empties. */ @@ -1124,6 +1123,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) && ehci->async->qh_next.qh == NULL) timer_action (ehci, TIMER_ASYNC_OFF); } + qh_put(qh); /* refcount from async list */ if (next) { ehci->reclaim = NULL;