[PATCH] usb: usbtest: update wait routine to set a timeout

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

 



Currently, in usb_sg_wait routine there isn't a timeout on waiting for
completion signal. When using TEST 5 -> 8 at usbtest module to verify
a new device controller with gadget zero, it might be hang on this
phase and this routine waits forever. And it's better to report a
error even though it fails.

So it should use a test_sg_wait instead of usb_sg_wait to add a
timeout about 10s to export a TIMEOUT error to return in usbtest
driver.

Reference: http://marc.info/?l=linux-usb&m=140137751813423&w=2

Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Cc: <stable@xxxxxxxxxxxxxxx>
Signed-off-by: Huang Rui <ray.huang@xxxxxxx>
---
 drivers/usb/misc/usbtest.c |   93 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 89 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 51a6da2..b075c64 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -10,7 +10,7 @@
 
 #include <linux/usb.h>
 
-#define SIMPLE_IO_TIMEOUT	10000	/* in milliseconds */
+#define IO_TIMEOUT	10000	/* in milliseconds */
 
 /*-------------------------------------------------------------------------*/
 
@@ -380,7 +380,7 @@ static int simple_io(
 		if (retval != 0)
 			break;
 
-		expire = msecs_to_jiffies(SIMPLE_IO_TIMEOUT);
+		expire = msecs_to_jiffies(IO_TIMEOUT);
 		if (!wait_for_completion_timeout(&completion, expire)) {
 			usb_kill_urb(urb);
 			retval = (urb->status == -ENOENT ?
@@ -435,6 +435,90 @@ static void free_sglist(struct scatterlist *sg, int nents)
 	kfree(sg);
 }
 
+/*
+ * Some codes are borrowed from usb_sg_wait and sg_clean routines
+ */
+static void test_sg_clean(struct usb_sg_request *io)
+{
+	if (io->urbs) {
+		while (io->entries--)
+			usb_free_urb(io->urbs[io->entries]);
+		kfree(io->urbs);
+		io->urbs = NULL;
+	}
+	io->dev = NULL;
+}
+
+static int test_sg_wait(struct usb_sg_request *io, unsigned long timeout)
+{
+	int i;
+	int entries = io->entries;
+	long timeleft;
+
+	/* queue the urbs.  */
+	spin_lock_irq(&io->lock);
+	i = 0;
+	while (i < entries && !io->status) {
+		int retval;
+
+		io->urbs[i]->dev = io->dev;
+		retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
+
+		/* after we submit, let completions or cancelations fire;
+		 * we handshake using io->status.
+		 */
+		spin_unlock_irq(&io->lock);
+		switch (retval) {
+			/* maybe we retrying will recover */
+		case -ENXIO:	/* hc didn't queue this one */
+		case -EAGAIN:
+		case -ENOMEM:
+			retval = 0;
+			yield();
+			break;
+
+			/* no error? continue immediately.
+			 *
+			 * NOTE: to work better with UHCI (4K I/O buffer may
+			 * need 3K of TDs) it may be good to limit how many
+			 * URBs are queued at once; N milliseconds?
+			 */
+		case 0:
+			++i;
+			cpu_relax();
+			break;
+
+			/* fail any uncompleted urbs */
+		default:
+			io->urbs[i]->status = retval;
+			dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
+				__func__, retval);
+			usb_sg_cancel(io);
+		}
+		spin_lock_irq(&io->lock);
+		if (retval && (io->status == 0 || io->status == -ECONNRESET))
+			io->status = retval;
+	}
+	io->count -= entries - i;
+	if (io->count == 0)
+		complete(&io->complete);
+	spin_unlock_irq(&io->lock);
+
+	/* OK, yes, this could be packaged as non-blocking.
+	 * So could the submit loop above ... but it's easier to
+	 * solve neither problem than to solve both!
+	 */
+	timeleft = wait_for_completion_timeout(&io->complete, timeout);
+	if (timeleft <= 0) {
+		usb_sg_cancel(io);
+		if (timeleft == 0)
+			io->status = -ETIMEDOUT;
+	}
+
+	test_sg_clean(io);
+	return io->status;
+}
+
 static struct scatterlist *
 alloc_sglist(int nents, int max, int vary)
 {
@@ -505,8 +589,9 @@ static int perform_sglist(
 
 		if (retval)
 			break;
-		usb_sg_wait(req);
-		retval = req->status;
+
+		retval = test_sg_wait(req,
+				msecs_to_jiffies(IO_TIMEOUT));
 
 		/* FIXME check resulting data pattern */
 
-- 
1.7.9.5

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




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]