|
@@ -17,6 +17,7 @@
|
|
|
static int override_alt = -1;
|
|
|
module_param_named(alt, override_alt, int, 0644);
|
|
|
MODULE_PARM_DESC(alt, ">= 0 to override altsetting selection");
|
|
|
+static void complicated_callback(struct urb *urb);
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
@@ -239,7 +240,8 @@ static struct urb *usbtest_alloc_urb(
|
|
|
unsigned long bytes,
|
|
|
unsigned transfer_flags,
|
|
|
unsigned offset,
|
|
|
- u8 bInterval)
|
|
|
+ u8 bInterval,
|
|
|
+ usb_complete_t complete_fn)
|
|
|
{
|
|
|
struct urb *urb;
|
|
|
|
|
@@ -248,10 +250,10 @@ static struct urb *usbtest_alloc_urb(
|
|
|
return urb;
|
|
|
|
|
|
if (bInterval)
|
|
|
- usb_fill_int_urb(urb, udev, pipe, NULL, bytes, simple_callback,
|
|
|
+ usb_fill_int_urb(urb, udev, pipe, NULL, bytes, complete_fn,
|
|
|
NULL, bInterval);
|
|
|
else
|
|
|
- usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback,
|
|
|
+ usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, complete_fn,
|
|
|
NULL);
|
|
|
|
|
|
urb->interval = (udev->speed == USB_SPEED_HIGH)
|
|
@@ -296,7 +298,17 @@ static struct urb *simple_alloc_urb(
|
|
|
u8 bInterval)
|
|
|
{
|
|
|
return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
|
|
|
- bInterval);
|
|
|
+ bInterval, simple_callback);
|
|
|
+}
|
|
|
+
|
|
|
+static struct urb *complicated_alloc_urb(
|
|
|
+ struct usb_device *udev,
|
|
|
+ int pipe,
|
|
|
+ unsigned long bytes,
|
|
|
+ u8 bInterval)
|
|
|
+{
|
|
|
+ return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
|
|
|
+ bInterval, complicated_callback);
|
|
|
}
|
|
|
|
|
|
static unsigned pattern;
|
|
@@ -1795,12 +1807,12 @@ static int ctrl_out(struct usbtest_dev *dev,
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
-/* ISO tests ... mimics common usage
|
|
|
+/* ISO/BULK tests ... mimics common usage
|
|
|
* - buffer length is split into N packets (mostly maxpacket sized)
|
|
|
* - multi-buffers according to sglen
|
|
|
*/
|
|
|
|
|
|
-struct iso_context {
|
|
|
+struct transfer_context {
|
|
|
unsigned count;
|
|
|
unsigned pending;
|
|
|
spinlock_t lock;
|
|
@@ -1809,11 +1821,12 @@ struct iso_context {
|
|
|
unsigned long errors;
|
|
|
unsigned long packet_count;
|
|
|
struct usbtest_dev *dev;
|
|
|
+ bool is_iso;
|
|
|
};
|
|
|
|
|
|
-static void iso_callback(struct urb *urb)
|
|
|
+static void complicated_callback(struct urb *urb)
|
|
|
{
|
|
|
- struct iso_context *ctx = urb->context;
|
|
|
+ struct transfer_context *ctx = urb->context;
|
|
|
|
|
|
spin_lock(&ctx->lock);
|
|
|
ctx->count--;
|
|
@@ -1822,7 +1835,7 @@ static void iso_callback(struct urb *urb)
|
|
|
if (urb->error_count > 0)
|
|
|
ctx->errors += urb->error_count;
|
|
|
else if (urb->status != 0)
|
|
|
- ctx->errors += urb->number_of_packets;
|
|
|
+ ctx->errors += (ctx->is_iso ? urb->number_of_packets : 1);
|
|
|
else if (urb->actual_length != urb->transfer_buffer_length)
|
|
|
ctx->errors++;
|
|
|
else if (check_guard_bytes(ctx->dev, urb) != 0)
|
|
@@ -1909,7 +1922,7 @@ static struct urb *iso_alloc_urb(
|
|
|
urb->iso_frame_desc[i].offset = maxp * i;
|
|
|
}
|
|
|
|
|
|
- urb->complete = iso_callback;
|
|
|
+ urb->complete = complicated_callback;
|
|
|
/* urb->context = SET BY CALLER */
|
|
|
urb->interval = 1 << (desc->bInterval - 1);
|
|
|
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
|
@@ -1917,10 +1930,10 @@ static struct urb *iso_alloc_urb(
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|
|
+test_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|
|
int pipe, struct usb_endpoint_descriptor *desc, unsigned offset)
|
|
|
{
|
|
|
- struct iso_context context;
|
|
|
+ struct transfer_context context;
|
|
|
struct usb_device *udev;
|
|
|
unsigned i;
|
|
|
unsigned long packets = 0;
|
|
@@ -1930,20 +1943,20 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|
|
memset(&context, 0, sizeof(context));
|
|
|
context.count = param->iterations * param->sglen;
|
|
|
context.dev = dev;
|
|
|
+ context.is_iso = !!desc;
|
|
|
init_completion(&context.done);
|
|
|
spin_lock_init(&context.lock);
|
|
|
|
|
|
udev = testdev_to_usbdev(dev);
|
|
|
- dev_info(&dev->intf->dev,
|
|
|
- "iso period %d %sframes, wMaxPacket %d, transactions: %d\n",
|
|
|
- 1 << (desc->bInterval - 1),
|
|
|
- (udev->speed == USB_SPEED_HIGH) ? "micro" : "",
|
|
|
- usb_endpoint_maxp(desc) & 0x7ff,
|
|
|
- 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11)));
|
|
|
|
|
|
for (i = 0; i < param->sglen; i++) {
|
|
|
- urbs[i] = iso_alloc_urb(udev, pipe, desc,
|
|
|
+ if (context.is_iso)
|
|
|
+ urbs[i] = iso_alloc_urb(udev, pipe, desc,
|
|
|
param->length, offset);
|
|
|
+ else
|
|
|
+ urbs[i] = complicated_alloc_urb(udev, pipe,
|
|
|
+ param->length, 0);
|
|
|
+
|
|
|
if (!urbs[i]) {
|
|
|
status = -ENOMEM;
|
|
|
goto fail;
|
|
@@ -1952,11 +1965,21 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|
|
urbs[i]->context = &context;
|
|
|
}
|
|
|
packets *= param->iterations;
|
|
|
- dev_info(&dev->intf->dev,
|
|
|
- "total %lu msec (%lu packets)\n",
|
|
|
- (packets * (1 << (desc->bInterval - 1)))
|
|
|
- / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
|
|
|
- packets);
|
|
|
+
|
|
|
+ if (context.is_iso) {
|
|
|
+ dev_info(&dev->intf->dev,
|
|
|
+ "iso period %d %sframes, wMaxPacket %d, transactions: %d\n",
|
|
|
+ 1 << (desc->bInterval - 1),
|
|
|
+ (udev->speed == USB_SPEED_HIGH) ? "micro" : "",
|
|
|
+ usb_endpoint_maxp(desc) & 0x7ff,
|
|
|
+ 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11)));
|
|
|
+
|
|
|
+ dev_info(&dev->intf->dev,
|
|
|
+ "total %lu msec (%lu packets)\n",
|
|
|
+ (packets * (1 << (desc->bInterval - 1)))
|
|
|
+ / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
|
|
|
+ packets);
|
|
|
+ }
|
|
|
|
|
|
spin_lock_irq(&context.lock);
|
|
|
for (i = 0; i < param->sglen; i++) {
|
|
@@ -1993,7 +2016,8 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|
|
;
|
|
|
else if (context.submit_error)
|
|
|
status = -EACCES;
|
|
|
- else if (context.errors > context.packet_count / 10)
|
|
|
+ else if (context.errors >
|
|
|
+ (context.is_iso ? context.packet_count / 10 : 0))
|
|
|
status = -EIO;
|
|
|
return status;
|
|
|
|
|
@@ -2014,8 +2038,8 @@ static int test_unaligned_bulk(
|
|
|
const char *label)
|
|
|
{
|
|
|
int retval;
|
|
|
- struct urb *urb = usbtest_alloc_urb(
|
|
|
- testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1, 0);
|
|
|
+ struct urb *urb = usbtest_alloc_urb(testdev_to_usbdev(tdev),
|
|
|
+ pipe, length, transfer_flags, 1, 0, simple_callback);
|
|
|
|
|
|
if (!urb)
|
|
|
return -ENOMEM;
|
|
@@ -2342,7 +2366,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|
|
param->iterations,
|
|
|
param->sglen, param->length);
|
|
|
/* FIRMWARE: iso sink */
|
|
|
- retval = test_iso_queue(dev, param,
|
|
|
+ retval = test_queue(dev, param,
|
|
|
dev->out_iso_pipe, dev->iso_out, 0);
|
|
|
break;
|
|
|
|
|
@@ -2355,7 +2379,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|
|
param->iterations,
|
|
|
param->sglen, param->length);
|
|
|
/* FIRMWARE: iso source */
|
|
|
- retval = test_iso_queue(dev, param,
|
|
|
+ retval = test_queue(dev, param,
|
|
|
dev->in_iso_pipe, dev->iso_in, 0);
|
|
|
break;
|
|
|
|
|
@@ -2436,7 +2460,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|
|
"TEST 22: write %d iso odd, %d entries of %d bytes\n",
|
|
|
param->iterations,
|
|
|
param->sglen, param->length);
|
|
|
- retval = test_iso_queue(dev, param,
|
|
|
+ retval = test_queue(dev, param,
|
|
|
dev->out_iso_pipe, dev->iso_out, 1);
|
|
|
break;
|
|
|
|
|
@@ -2447,7 +2471,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|
|
"TEST 23: read %d iso odd, %d entries of %d bytes\n",
|
|
|
param->iterations,
|
|
|
param->sglen, param->length);
|
|
|
- retval = test_iso_queue(dev, param,
|
|
|
+ retval = test_queue(dev, param,
|
|
|
dev->in_iso_pipe, dev->iso_in, 1);
|
|
|
break;
|
|
|
|
|
@@ -2504,6 +2528,25 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|
|
retval = simple_io(dev, urb, param->iterations, 0, 0, "test26");
|
|
|
simple_free_urb(urb);
|
|
|
break;
|
|
|
+ case 27:
|
|
|
+ /* We do performance test, so ignore data compare */
|
|
|
+ if (dev->out_pipe == 0 || param->sglen == 0 || pattern != 0)
|
|
|
+ break;
|
|
|
+ dev_info(&intf->dev,
|
|
|
+ "TEST 27: bulk write %dMbytes\n", (param->iterations *
|
|
|
+ param->sglen * param->length) / (1024 * 1024));
|
|
|
+ retval = test_queue(dev, param,
|
|
|
+ dev->out_pipe, NULL, 0);
|
|
|
+ break;
|
|
|
+ case 28:
|
|
|
+ if (dev->in_pipe == 0 || param->sglen == 0 || pattern != 0)
|
|
|
+ break;
|
|
|
+ dev_info(&intf->dev,
|
|
|
+ "TEST 28: bulk read %dMbytes\n", (param->iterations *
|
|
|
+ param->sglen * param->length) / (1024 * 1024));
|
|
|
+ retval = test_queue(dev, param,
|
|
|
+ dev->in_pipe, NULL, 0);
|
|
|
+ break;
|
|
|
}
|
|
|
do_gettimeofday(¶m->duration);
|
|
|
param->duration.tv_sec -= start.tv_sec;
|