The urb_dequeue() method "forgets" to unlink 'struct musb_qh' from the control or bulk schedule list when an URB being cancelled is the only one queued to its endpoint. That will cause musb_advance_schedule() to "block" once it reaches 'struct musb_qh' with now empty URB list, and so URBs queued to other endpoints after this one will not be served. Unlink 'struct musb_qh' from the list except when it's being already "dealt with", typically by musb_giveback(), as indicated by 'is_ready' flag being 0. Since 'struct musb_qh' with an empty USB list is now supposed to be freed, do that after unlinking it. And as there should be no such endpoints in the schedule lists anymore, remove now useless check from musb_advance_schedule() (this check prevented kernel oops in musb_giveback() before)... Signed-off-by: Sergei Shtylyov <sshtylyov@xxxxxxxxxxxxx> --- This patch, with the description and comments somwewhat changed, is intended to replace usb/usb-musb_host-fix-urb_dequeue-method.patch in Greg's series... drivers/usb/musb/musb_host.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) Index: linux-2.6/drivers/usb/musb/musb_host.c =================================================================== --- linux-2.6.orig/drivers/usb/musb/musb_host.c +++ linux-2.6/drivers/usb/musb/musb_host.c @@ -432,7 +432,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)); @@ -2078,7 +2078,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, we need to recycle this qh. + * Though if something else, like musb_giveback(), is already + * using it, we'd better leave it alone for now -- it will be + * recycled a bit later... + */ + 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