[patch 03/12] USB: musb_host: fix urb_dequeue() method

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Sergei Shtylyov <sshtylyov@xxxxxxxxxxxxx>

The urb_dequeue() method "forgets" to unlink 'struct musb_qh' from the control/
bulk schedule list when an URB being cancelled is the only one queued to its
endpoint, which will cause musb_advance_schedule() to "block" once it reaches
'struct musb_qh' with now empty URB list, and so URBs queued for other control/
bulk endpoints after the one being dequeued will not be served. Hence add code
to unlink and free 'struct musb_qh' if its URB list emptied to this method and
remove now useless check from musb_advance_schedule().

The only exception case is when we're called from the driver's callback --
musb_giveback() doesn't expect us to pull out 'qh' from under it (it'll kill
this qh later anyway) and we want to keep around a qh with is_ready flag clear
because some drivers like usbaudio.c do submit a new URB after cancelling all
pending ones which leads to URB being started when it shouldn't be and started
all over again after the control returns to musb_giveback()...

Signed-off-by: Sergei Shtylyov <sshtylyov@xxxxxxxxxxxxx>
Cc: Felipe Balbi <felipe.balbi@xxxxxxxxx>
Cc: David Brownell <dbrownell@xxxxxxxxxxxxxxxxxxxxx>


---
 drivers/usb/musb/musb_host.c |   16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -431,7 +431,7 @@ musb_advance_schedule(struct musb *musb,
 	else
 		qh = musb_giveback(qh, urb, urb->status);
 
-	if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) {
+	if (qh != NULL && qh->is_ready) {
 		DBG(4, "... next ep%d %cX urb %p\n",
 				hw_ep->epnum, is_in ? 'R' : 'T',
 				next_urb(qh));
@@ -2071,7 +2071,19 @@ static int musb_urb_dequeue(struct usb_h
 		ret = 0;
 		qh->is_ready = 0;
 		__musb_giveback(musb, urb, 0);
-		qh->is_ready = ready;
+
+		/*
+		 * If the URB list has emptied, it's time to kill this qh.
+		 * However, if this was called from the driver callback,
+		 * we don't really want to do it now, deferring it until
+		 * we return to musb_giveback(), or bad things will happen...
+		 */
+		if (ready && list_empty(&qh->hep->urb_list)) {
+			qh->hep->hcpriv = NULL;
+			list_del(&qh->ring);
+			kfree(qh);
+		} else
+			qh->is_ready = ready;
 	} else
 		ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
 done:

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux