Commit 4f88b00d authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: usbtest checks for in-order completions

This makes "test 10" verify that completions are returned in-order,
resolving a FIXME.  OHCI and EHCI do, but UHCI doesn't. (*)  That
simplified a cleanup of the queue fault tests to make it easier
to handle optional faults (with one or more failure modes).

It also returns a "lost subcase" that accidentally was not getting
run.  And in a case of pure paranoia, the unlink tests handle the
EBUSY return from an async urb unlink ... if that ever shows up I'd
expect it to be on an SMP box.


(*) I'd suspected as much given the first round of tests with UHCI;
     the diagnostics from "usbtest" made no sense otherwise.  This
     is just repeatable confirmation of the earlier bug report.  This
     could cause trouble in the usb_sg_*() I/O calls.

     In this case, "testusb -at10 -g4" reported that subcase 1 completed
     out of order (before subcase 0) ... without looking at details, I'd
     guess a list_add() vs list_add_tail() issue.

     Then after trying the queue cleanup code, I got diagnostics from
     uhci_destroy_urb_priv; then a kmalloc poisoning oops in uhci_irq,
     or "uhci_remove_pending_qhs+0x7c/0x1b0" in more detail.  Those
     looks to be the same "can't unlink from completions" errors that
     was also reported before in that code.

     Note that "testusb -at10" (like "testusb -at9") can be made to
     work with any USB device, using "usbtest" module options.
parent 135c5b70
...@@ -552,6 +552,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -552,6 +552,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* (b) protocol stalls (control-only) will autorecover. * (b) protocol stalls (control-only) will autorecover.
* it's quite not like bulk/intr; no halt clearing. * it's quite not like bulk/intr; no halt clearing.
* (c) short control reads are reported and handled. * (c) short control reads are reported and handled.
* (d) queues are always processed in-order
*/ */
struct ctrl_ctx { struct ctrl_ctx {
...@@ -563,66 +564,68 @@ struct ctrl_ctx { ...@@ -563,66 +564,68 @@ struct ctrl_ctx {
int status; int status;
struct urb **urb; struct urb **urb;
struct usbtest_param *param; struct usbtest_param *param;
int last;
};
#define NUM_SUBCASES 13 /* how many test subcases here? */
struct subcase {
struct usb_ctrlrequest setup;
int number;
int expected;
}; };
static void ctrl_complete (struct urb *urb, struct pt_regs *regs) static void ctrl_complete (struct urb *urb, struct pt_regs *regs)
{ {
struct ctrl_ctx *ctx = urb->context; struct ctrl_ctx *ctx = urb->context;
struct usb_ctrlrequest *reqp; struct usb_ctrlrequest *reqp;
struct subcase *subcase;
int status = urb->status; int status = urb->status;
reqp = (struct usb_ctrlrequest *)urb->setup_packet; reqp = (struct usb_ctrlrequest *)urb->setup_packet;
subcase = container_of (reqp, struct subcase, setup);
spin_lock (&ctx->lock); spin_lock (&ctx->lock);
ctx->count--; ctx->count--;
ctx->pending--; ctx->pending--;
/* FIXME verify that the completions are in the right sequence. /* queue must transfer and complete in fifo order, unless
* we could store the test number with the setup packet, that * usb_unlink_urb() is used to unlink something not at the
* buffer has extra space. * physical queue head (not tested).
*/ */
if (subcase->number > 0) {
switch (status) { if ((subcase->number - ctx->last) != 1) {
case 0: /* success */ dbg ("subcase %d completed out of order, last %d",
case -EREMOTEIO: /* short read */ subcase->number, ctx->last);
if (reqp->bRequestType == (USB_DIR_IN|USB_RECIP_DEVICE) status = -EDOM;
&& reqp->bRequest == USB_REQ_GET_DESCRIPTOR goto error;
&& ((le16_to_cpu (reqp->wValue) >> 8)
== USB_DT_DEVICE)) {
if (reqp->wLength > USB_DT_DEVICE_SIZE
&& status == -EREMOTEIO)
status = 0;
else if (reqp->wLength == USB_DT_DEVICE_SIZE
&& status != 0)
status = -EIO;
if (status)
goto error;
} }
break; }
case -ECONNRESET: /* async unlink */ ctx->last = subcase->number;
break;
case -EPIPE: /* (protocol) stall */ /* succeed or fault in only one way? */
if (reqp->bRequestType == (USB_DIR_IN|USB_RECIP_INTERFACE) if (status == subcase->expected)
&& reqp->bRequest == USB_REQ_GET_INTERFACE) status = 0;
/* async unlink for cleanup? */
else if (status != -ECONNRESET) {
/* some faults are allowed, not required */
if (subcase->expected > 0 && (
((urb->status == -subcase->expected /* happened */
|| urb->status == 0)))) /* didn't */
status = 0; status = 0;
else if (reqp->bRequestType == (USB_DIR_IN|USB_RECIP_DEVICE) /* sometimes more than one fault is allowed */
&& reqp->bRequest == USB_REQ_GET_DESCRIPTOR) { else if (subcase->number == 12 && status == -EPIPE)
switch (le16_to_cpu (reqp->wValue) >> 8) {
case USB_DT_DEVICE_QUALIFIER:
case USB_DT_OTHER_SPEED_CONFIG:
case USB_DT_INTERFACE:
case USB_DT_ENDPOINT:
status = 0;
}
} else if (reqp->bRequestType == USB_RECIP_ENDPOINT
&& reqp->bRequest == USB_REQ_CLEAR_FEATURE)
status = 0; status = 0;
/* some stalls we plan on; others would be errors */ else
if (status == 0) dbg ("subtest %d error, status %d",
break; subcase->number, status);
/* else FALLTHROUGH */ }
/* unexpected status codes mean errors; ideally, in hardware */
if (status) {
error: error:
default: /* this fault's an error */
if (ctx->status == 0) { if (ctx->status == 0) {
int i; int i;
...@@ -631,10 +634,8 @@ static void ctrl_complete (struct urb *urb, struct pt_regs *regs) ...@@ -631,10 +634,8 @@ static void ctrl_complete (struct urb *urb, struct pt_regs *regs)
reqp->bRequestType, reqp->bRequest, reqp->bRequestType, reqp->bRequest,
status, ctx->count); status, ctx->count);
/* FIXME use this "unlink everything" exit route /* FIXME this "unlink everything" exit route should
* in all cases, not just for fault cleanup. * be a separate test case.
* it'll be another test mode, but one that makes
* testing be more consistent.
*/ */
/* unlink whatever's still pending */ /* unlink whatever's still pending */
...@@ -688,6 +689,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -688,6 +689,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
context.pending = 0; context.pending = 0;
context.status = -ENOMEM; context.status = -ENOMEM;
context.param = param; context.param = param;
context.last = -1;
/* allocate and init the urbs we'll queue. /* allocate and init the urbs we'll queue.
* as with bulk/intr sglists, sglen is the queue depth; it also * as with bulk/intr sglists, sglen is the queue depth; it also
...@@ -701,7 +703,9 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -701,7 +703,9 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
int pipe = usb_rcvctrlpipe (udev, 0); int pipe = usb_rcvctrlpipe (udev, 0);
unsigned len; unsigned len;
struct urb *u; struct urb *u;
struct usb_ctrlrequest req, *reqp; struct usb_ctrlrequest req;
struct subcase *reqp;
int expected = 0;
/* requests here are mostly expected to succeed on any /* requests here are mostly expected to succeed on any
* device, but some are chosen to trigger protocol stalls * device, but some are chosen to trigger protocol stalls
...@@ -711,7 +715,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -711,7 +715,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.bRequest = USB_REQ_GET_DESCRIPTOR; req.bRequest = USB_REQ_GET_DESCRIPTOR;
req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE; req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE;
switch (i % 12 /* number of subtest cases here */) { switch (i % NUM_SUBCASES) {
case 0: // get device descriptor case 0: // get device descriptor
req.wValue = cpu_to_le16 (USB_DT_DEVICE << 8); req.wValue = cpu_to_le16 (USB_DT_DEVICE << 8);
len = sizeof (struct usb_device_descriptor); len = sizeof (struct usb_device_descriptor);
...@@ -725,6 +729,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -725,6 +729,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE; req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE;
// index = 0 means first interface // index = 0 means first interface
len = 1; len = 1;
expected = EPIPE;
break; break;
case 3: // get interface status case 3: // get interface status
req.bRequest = USB_REQ_GET_STATUS; req.bRequest = USB_REQ_GET_STATUS;
...@@ -740,6 +745,8 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -740,6 +745,8 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
case 5: // get device qualifier (MAY STALL) case 5: // get device qualifier (MAY STALL)
req.wValue = cpu_to_le16 (USB_DT_DEVICE_QUALIFIER << 8); req.wValue = cpu_to_le16 (USB_DT_DEVICE_QUALIFIER << 8);
len = sizeof (struct usb_qualifier_descriptor); len = sizeof (struct usb_qualifier_descriptor);
if (udev->speed != USB_SPEED_HIGH)
expected = EPIPE;
break; break;
case 6: // get first config descriptor, plus interface case 6: // get first config descriptor, plus interface
req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0); req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);
...@@ -750,6 +757,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -750,6 +757,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8); req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
// interface == 0 // interface == 0
len = sizeof (struct usb_interface_descriptor); len = sizeof (struct usb_interface_descriptor);
expected = -EPIPE;
break; break;
// NOTE: two consecutive stalls in the queue here. // NOTE: two consecutive stalls in the queue here.
// that tests fault recovery a bit more aggressively. // that tests fault recovery a bit more aggressively.
...@@ -760,6 +768,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -760,6 +768,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
// wIndex 0 == ep0 (shouldn't halt!) // wIndex 0 == ep0 (shouldn't halt!)
len = 0; len = 0;
pipe = usb_sndctrlpipe (udev, 0); pipe = usb_sndctrlpipe (udev, 0);
expected = EPIPE;
break; break;
case 9: // get endpoint status case 9: // get endpoint status
req.bRequest = USB_REQ_GET_STATUS; req.bRequest = USB_REQ_GET_STATUS;
...@@ -770,18 +779,21 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -770,18 +779,21 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
case 10: // trigger short read (EREMOTEIO) case 10: // trigger short read (EREMOTEIO)
req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0); req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);
len = 1024; len = 1024;
expected = -EREMOTEIO;
break; break;
// NOTE: two consecutive _different_ faults in the queue. // NOTE: two consecutive _different_ faults in the queue.
case 11: // get endpoint descriptor (ALWAYS STALLS) case 11: // get endpoint descriptor (ALWAYS STALLS)
req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8); req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8);
// endpoint == 0 // endpoint == 0
len = sizeof (struct usb_interface_descriptor); len = sizeof (struct usb_interface_descriptor);
expected = -EPIPE;
break; break;
// NOTE: sometimes even a third fault in the queue! // NOTE: sometimes even a third fault in the queue!
case 12: // get string 0 descriptor (MAY STALL) case 12: // get string 0 descriptor (MAY STALL)
req.wValue = cpu_to_le16 (USB_DT_STRING << 8); req.wValue = cpu_to_le16 (USB_DT_STRING << 8);
// string == 0, for language IDs // string == 0, for language IDs
len = sizeof (struct usb_interface_descriptor); len = sizeof (struct usb_interface_descriptor);
expected = EREMOTEIO; // or EPIPE, if no strings
break; break;
default: default:
err ("bogus number of ctrl queue testcases!"); err ("bogus number of ctrl queue testcases!");
...@@ -793,12 +805,14 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -793,12 +805,14 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
if (!u) if (!u)
goto cleanup; goto cleanup;
reqp = usb_buffer_alloc (udev, sizeof req, SLAB_KERNEL, reqp = usb_buffer_alloc (udev, sizeof *reqp, SLAB_KERNEL,
&u->setup_dma); &u->setup_dma);
if (!reqp) if (!reqp)
goto cleanup; goto cleanup;
*reqp = req; reqp->setup = req;
u->setup_packet = (char *) reqp; reqp->number = i % NUM_SUBCASES;
reqp->expected = expected;
u->setup_packet = (char *) &reqp->setup;
u->context = &context; u->context = &context;
u->complete = ctrl_complete; u->complete = ctrl_complete;
...@@ -839,6 +853,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -839,6 +853,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
kfree (urb); kfree (urb);
return context.status; return context.status;
} }
#undef NUM_SUBCASES
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -886,7 +901,16 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) ...@@ -886,7 +901,16 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
* hcd states and code paths, even with little other system load. * hcd states and code paths, even with little other system load.
*/ */
wait_ms (jiffies % (2 * INTERRUPT_RATE)); wait_ms (jiffies % (2 * INTERRUPT_RATE));
retry:
retval = usb_unlink_urb (urb); retval = usb_unlink_urb (urb);
if (retval == -EBUSY) {
/* we can't unlink urbs while they're completing.
* "normal" drivers would prevent resubmission, but
* since we're testing unlink paths, we can't.
*/
dbg ("unlink retry");
goto retry;
}
if (!(retval == 0 || retval == -EINPROGRESS)) { if (!(retval == 0 || retval == -EINPROGRESS)) {
dbg ("submit/unlink fail %d", retval); dbg ("submit/unlink fail %d", retval);
return retval; return retval;
...@@ -1309,7 +1333,13 @@ static struct usbtest_info ez2_info = { ...@@ -1309,7 +1333,13 @@ static struct usbtest_info ez2_info = {
.alt = 1, .alt = 1,
}; };
/* ezusb family device with dedicated usb test firmware*/ /* ezusb family device with dedicated usb test firmware,
* or a peripheral running Linux and 'zero.c' test firmware.
*
* FIXME usbtest should read the descriptors, since compatible
* test firmware might run on hardware (pxa250 for one) that
* can't configure an ep2in-bulk.
*/
static struct usbtest_info fw_info = { static struct usbtest_info fw_info = {
.name = "usb test device", .name = "usb test device",
.ep_in = 2, .ep_in = 2,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment