summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBin Liu <b-liu@ti.com>2016-05-31 17:05:04 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-06-01 23:58:59 +0200
commitdbac5d07d13e330e6706813c9fde477140fb5d80 (patch)
tree0a01a5d981d58b645c87ea29fcba781be628b823
parentusb: musb: host: clear rxcsr error bit if set (diff)
downloadlinux-dbac5d07d13e330e6706813c9fde477140fb5d80.tar.xz
linux-dbac5d07d13e330e6706813c9fde477140fb5d80.zip
usb: musb: host: don't start next rx urb if current one failed
urb->status is set when endpoint csr RXSTALL, H_ERROR, DATAERROR or INCOMPRX bit is set. Those bits mean a broken pipe, so don't start next urb when any of these bits is set by checking urb->status. To minimize the risk of regression, only do so for RX, until we have a test case to understand the behavior of TX. The patch fixes system freeze issue caused by repeatedly invoking RX ISR while removing a usb uart device connected to a hub, in which case the hub has no chance to report the disconnect event due to the kernel is busy in processing the RX interrupt flooding. Fix checkpatch complaint (qh != NULL) as while. Reported-by: Max Uvarov <muvarov@gmail.com> Tested-by: Yegor Yefremov <yegorslists@googlemail.com> Signed-off-by: Bin Liu <b-liu@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/musb/musb_host.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 931381c51ad7..dd1ebde02786 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -434,7 +434,13 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
}
}
- if (qh != NULL && qh->is_ready) {
+ /*
+ * The pipe must be broken if current urb->status is set, so don't
+ * start next urb.
+ * TODO: to minimize the risk of regression, only check urb->status
+ * for RX, until we have a test case to understand the behavior of TX.
+ */
+ if ((!status || !is_in) && qh && qh->is_ready) {
dev_dbg(musb->controller, "... next ep%d %cX urb %p\n",
hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
musb_start_urb(musb, is_in, qh);