mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-21 11:44:01 +08:00
usb: misc: usbtest: add bulk queue test
The bulk queue tests are used to show 'best performance' for bulk transfer, we are often asked this question by users. The implementation is the same with iso test, that is queue request at interrupt completion, so we reuse the iso structures, and rename them as common one. It's result should be very close to IC simulation, in order to get that, the device side should also need to prepare enough queue. We have got the 'best performance' (IN: 41MB, OUT: 39MB) at i.mx platform (USB2, ARM Cortex A9, stream mode need to enable) with below command: Host side: modprobe usbtest ./testusb -a -t 27 -g 64 -s 16384 ./testusb -a -t 28 -g 64 -s 16384 Gadget side: modprobe g_zero loopdefault=1 qlen=64 buflen=16384 Signed-off-by: Peter Chen <peter.chen@freescale.com> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
44e4a60dac
commit
145f48c518
@ -17,6 +17,7 @@
|
|||||||
static int override_alt = -1;
|
static int override_alt = -1;
|
||||||
module_param_named(alt, override_alt, int, 0644);
|
module_param_named(alt, override_alt, int, 0644);
|
||||||
MODULE_PARM_DESC(alt, ">= 0 to override altsetting selection");
|
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 long bytes,
|
||||||
unsigned transfer_flags,
|
unsigned transfer_flags,
|
||||||
unsigned offset,
|
unsigned offset,
|
||||||
u8 bInterval)
|
u8 bInterval,
|
||||||
|
usb_complete_t complete_fn)
|
||||||
{
|
{
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
|
|
||||||
@ -248,10 +250,10 @@ static struct urb *usbtest_alloc_urb(
|
|||||||
return urb;
|
return urb;
|
||||||
|
|
||||||
if (bInterval)
|
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);
|
NULL, bInterval);
|
||||||
else
|
else
|
||||||
usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback,
|
usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, complete_fn,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
urb->interval = (udev->speed == USB_SPEED_HIGH)
|
urb->interval = (udev->speed == USB_SPEED_HIGH)
|
||||||
@ -296,7 +298,17 @@ static struct urb *simple_alloc_urb(
|
|||||||
u8 bInterval)
|
u8 bInterval)
|
||||||
{
|
{
|
||||||
return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
|
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;
|
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)
|
* - buffer length is split into N packets (mostly maxpacket sized)
|
||||||
* - multi-buffers according to sglen
|
* - multi-buffers according to sglen
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct iso_context {
|
struct transfer_context {
|
||||||
unsigned count;
|
unsigned count;
|
||||||
unsigned pending;
|
unsigned pending;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
@ -1809,11 +1821,12 @@ struct iso_context {
|
|||||||
unsigned long errors;
|
unsigned long errors;
|
||||||
unsigned long packet_count;
|
unsigned long packet_count;
|
||||||
struct usbtest_dev *dev;
|
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);
|
spin_lock(&ctx->lock);
|
||||||
ctx->count--;
|
ctx->count--;
|
||||||
@ -1822,7 +1835,7 @@ static void iso_callback(struct urb *urb)
|
|||||||
if (urb->error_count > 0)
|
if (urb->error_count > 0)
|
||||||
ctx->errors += urb->error_count;
|
ctx->errors += urb->error_count;
|
||||||
else if (urb->status != 0)
|
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)
|
else if (urb->actual_length != urb->transfer_buffer_length)
|
||||||
ctx->errors++;
|
ctx->errors++;
|
||||||
else if (check_guard_bytes(ctx->dev, urb) != 0)
|
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->iso_frame_desc[i].offset = maxp * i;
|
||||||
}
|
}
|
||||||
|
|
||||||
urb->complete = iso_callback;
|
urb->complete = complicated_callback;
|
||||||
/* urb->context = SET BY CALLER */
|
/* urb->context = SET BY CALLER */
|
||||||
urb->interval = 1 << (desc->bInterval - 1);
|
urb->interval = 1 << (desc->bInterval - 1);
|
||||||
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
||||||
@ -1917,10 +1930,10 @@ static struct urb *iso_alloc_urb(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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)
|
int pipe, struct usb_endpoint_descriptor *desc, unsigned offset)
|
||||||
{
|
{
|
||||||
struct iso_context context;
|
struct transfer_context context;
|
||||||
struct usb_device *udev;
|
struct usb_device *udev;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned long packets = 0;
|
unsigned long packets = 0;
|
||||||
@ -1930,20 +1943,20 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|||||||
memset(&context, 0, sizeof(context));
|
memset(&context, 0, sizeof(context));
|
||||||
context.count = param->iterations * param->sglen;
|
context.count = param->iterations * param->sglen;
|
||||||
context.dev = dev;
|
context.dev = dev;
|
||||||
|
context.is_iso = !!desc;
|
||||||
init_completion(&context.done);
|
init_completion(&context.done);
|
||||||
spin_lock_init(&context.lock);
|
spin_lock_init(&context.lock);
|
||||||
|
|
||||||
udev = testdev_to_usbdev(dev);
|
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++) {
|
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);
|
param->length, offset);
|
||||||
|
else
|
||||||
|
urbs[i] = complicated_alloc_urb(udev, pipe,
|
||||||
|
param->length, 0);
|
||||||
|
|
||||||
if (!urbs[i]) {
|
if (!urbs[i]) {
|
||||||
status = -ENOMEM;
|
status = -ENOMEM;
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1952,11 +1965,21 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|||||||
urbs[i]->context = &context;
|
urbs[i]->context = &context;
|
||||||
}
|
}
|
||||||
packets *= param->iterations;
|
packets *= param->iterations;
|
||||||
dev_info(&dev->intf->dev,
|
|
||||||
"total %lu msec (%lu packets)\n",
|
if (context.is_iso) {
|
||||||
(packets * (1 << (desc->bInterval - 1)))
|
dev_info(&dev->intf->dev,
|
||||||
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
|
"iso period %d %sframes, wMaxPacket %d, transactions: %d\n",
|
||||||
packets);
|
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);
|
spin_lock_irq(&context.lock);
|
||||||
for (i = 0; i < param->sglen; i++) {
|
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)
|
else if (context.submit_error)
|
||||||
status = -EACCES;
|
status = -EACCES;
|
||||||
else if (context.errors > context.packet_count / 10)
|
else if (context.errors >
|
||||||
|
(context.is_iso ? context.packet_count / 10 : 0))
|
||||||
status = -EIO;
|
status = -EIO;
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@ -2014,8 +2038,8 @@ static int test_unaligned_bulk(
|
|||||||
const char *label)
|
const char *label)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct urb *urb = usbtest_alloc_urb(
|
struct urb *urb = usbtest_alloc_urb(testdev_to_usbdev(tdev),
|
||||||
testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1, 0);
|
pipe, length, transfer_flags, 1, 0, simple_callback);
|
||||||
|
|
||||||
if (!urb)
|
if (!urb)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -2342,7 +2366,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||||||
param->iterations,
|
param->iterations,
|
||||||
param->sglen, param->length);
|
param->sglen, param->length);
|
||||||
/* FIRMWARE: iso sink */
|
/* FIRMWARE: iso sink */
|
||||||
retval = test_iso_queue(dev, param,
|
retval = test_queue(dev, param,
|
||||||
dev->out_iso_pipe, dev->iso_out, 0);
|
dev->out_iso_pipe, dev->iso_out, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2355,7 +2379,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||||||
param->iterations,
|
param->iterations,
|
||||||
param->sglen, param->length);
|
param->sglen, param->length);
|
||||||
/* FIRMWARE: iso source */
|
/* FIRMWARE: iso source */
|
||||||
retval = test_iso_queue(dev, param,
|
retval = test_queue(dev, param,
|
||||||
dev->in_iso_pipe, dev->iso_in, 0);
|
dev->in_iso_pipe, dev->iso_in, 0);
|
||||||
break;
|
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",
|
"TEST 22: write %d iso odd, %d entries of %d bytes\n",
|
||||||
param->iterations,
|
param->iterations,
|
||||||
param->sglen, param->length);
|
param->sglen, param->length);
|
||||||
retval = test_iso_queue(dev, param,
|
retval = test_queue(dev, param,
|
||||||
dev->out_iso_pipe, dev->iso_out, 1);
|
dev->out_iso_pipe, dev->iso_out, 1);
|
||||||
break;
|
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",
|
"TEST 23: read %d iso odd, %d entries of %d bytes\n",
|
||||||
param->iterations,
|
param->iterations,
|
||||||
param->sglen, param->length);
|
param->sglen, param->length);
|
||||||
retval = test_iso_queue(dev, param,
|
retval = test_queue(dev, param,
|
||||||
dev->in_iso_pipe, dev->iso_in, 1);
|
dev->in_iso_pipe, dev->iso_in, 1);
|
||||||
break;
|
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");
|
retval = simple_io(dev, urb, param->iterations, 0, 0, "test26");
|
||||||
simple_free_urb(urb);
|
simple_free_urb(urb);
|
||||||
break;
|
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);
|
do_gettimeofday(¶m->duration);
|
||||||
param->duration.tv_sec -= start.tv_sec;
|
param->duration.tv_sec -= start.tv_sec;
|
||||||
|
Loading…
Reference in New Issue
Block a user