usb: gadget: f_sourcesink: add queue depth
authorPeter Chen <peter.chen@freescale.com>
Thu, 19 Nov 2015 07:02:16 +0000 (15:02 +0800)
committerFelipe Balbi <balbi@ti.com>
Tue, 15 Dec 2015 15:12:41 +0000 (09:12 -0600)
Add queue depth for both iso and bulk transfer, with more queues, we
can do performance and stress test using sourcesink, and update g_zero
accordingly.

Reviewed-by: Krzysztof Opasiak <k.opasiak@samsung.com>
Signed-off-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/g_zero.h
drivers/usb/gadget/legacy/zero.c

index 9f3ced62d9162c991c03b0db68d10fd0cbe06ea9..9df4aa1ea011dc7b1afe39a045ca0f9349078664 100644 (file)
  * plus two that support control-OUT tests.  If the optional "autoresume"
  * mode is enabled, it provides good functional coverage for the "USBCV"
  * test harness from USB-IF.
- *
- * Note that because this doesn't queue more than one request at a time,
- * some other function must be used to test queueing logic.  The network
- * link (g_ether) is the best overall option for that, since its TX and RX
- * queues are relatively independent, will receive a range of packet sizes,
- * and can often be made to run out completely.  Those issues are important
- * when stress testing peripheral controller drivers.
  */
 struct f_sourcesink {
        struct usb_function     function;
@@ -57,6 +50,8 @@ struct f_sourcesink {
        unsigned isoc_mult;
        unsigned isoc_maxburst;
        unsigned buflen;
+       unsigned bulk_qlen;
+       unsigned iso_qlen;
 };
 
 static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
@@ -595,31 +590,33 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 {
        struct usb_ep           *ep;
        struct usb_request      *req;
-       int                     i, size, status;
-
-       for (i = 0; i < 8; i++) {
-               if (is_iso) {
-                       switch (speed) {
-                       case USB_SPEED_SUPER:
-                               size = ss->isoc_maxpacket *
-                                               (ss->isoc_mult + 1) *
-                                               (ss->isoc_maxburst + 1);
-                               break;
-                       case USB_SPEED_HIGH:
-                               size = ss->isoc_maxpacket * (ss->isoc_mult + 1);
-                               break;
-                       default:
-                               size = ss->isoc_maxpacket > 1023 ?
-                                               1023 : ss->isoc_maxpacket;
-                               break;
-                       }
-                       ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
-                       req = ss_alloc_ep_req(ep, size);
-               } else {
-                       ep = is_in ? ss->in_ep : ss->out_ep;
-                       req = ss_alloc_ep_req(ep, 0);
+       int                     i, size, qlen, status = 0;
+
+       if (is_iso) {
+               switch (speed) {
+               case USB_SPEED_SUPER:
+                       size = ss->isoc_maxpacket *
+                                       (ss->isoc_mult + 1) *
+                                       (ss->isoc_maxburst + 1);
+                       break;
+               case USB_SPEED_HIGH:
+                       size = ss->isoc_maxpacket * (ss->isoc_mult + 1);
+                       break;
+               default:
+                       size = ss->isoc_maxpacket > 1023 ?
+                                       1023 : ss->isoc_maxpacket;
+                       break;
                }
+               ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
+               qlen = ss->iso_qlen;
+       } else {
+               ep = is_in ? ss->in_ep : ss->out_ep;
+               qlen = ss->bulk_qlen;
+               size = 0;
+       }
 
+       for (i = 0; i < qlen; i++) {
+               req = ss_alloc_ep_req(ep, size);
                if (!req)
                        return -ENOMEM;
 
@@ -639,9 +636,6 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
                              ep->name, status);
                        free_ep_req(ep, req);
                }
-
-               if (!is_iso)
-                       break;
        }
 
        return status;
@@ -869,6 +863,8 @@ static struct usb_function *source_sink_alloc_func(
        ss->isoc_mult = ss_opts->isoc_mult;
        ss->isoc_maxburst = ss_opts->isoc_maxburst;
        ss->buflen = ss_opts->bulk_buflen;
+       ss->bulk_qlen = ss_opts->bulk_qlen;
+       ss->iso_qlen = ss_opts->iso_qlen;
 
        ss->function.name = "source/sink";
        ss->function.bind = sourcesink_bind;
@@ -1153,6 +1149,82 @@ end:
 
 CONFIGFS_ATTR(f_ss_opts_, bulk_buflen);
 
+static ssize_t f_ss_opts_bulk_qlen_show(struct config_item *item, char *page)
+{
+       struct f_ss_opts *opts = to_f_ss_opts(item);
+       int result;
+
+       mutex_lock(&opts->lock);
+       result = sprintf(page, "%u\n", opts->bulk_qlen);
+       mutex_unlock(&opts->lock);
+
+       return result;
+}
+
+static ssize_t f_ss_opts_bulk_qlen_store(struct config_item *item,
+                                          const char *page, size_t len)
+{
+       struct f_ss_opts *opts = to_f_ss_opts(item);
+       int ret;
+       u32 num;
+
+       mutex_lock(&opts->lock);
+       if (opts->refcnt) {
+               ret = -EBUSY;
+               goto end;
+       }
+
+       ret = kstrtou32(page, 0, &num);
+       if (ret)
+               goto end;
+
+       opts->bulk_qlen = num;
+       ret = len;
+end:
+       mutex_unlock(&opts->lock);
+       return ret;
+}
+
+CONFIGFS_ATTR(f_ss_opts_, bulk_qlen);
+
+static ssize_t f_ss_opts_iso_qlen_show(struct config_item *item, char *page)
+{
+       struct f_ss_opts *opts = to_f_ss_opts(item);
+       int result;
+
+       mutex_lock(&opts->lock);
+       result = sprintf(page, "%u\n", opts->iso_qlen);
+       mutex_unlock(&opts->lock);
+
+       return result;
+}
+
+static ssize_t f_ss_opts_iso_qlen_store(struct config_item *item,
+                                          const char *page, size_t len)
+{
+       struct f_ss_opts *opts = to_f_ss_opts(item);
+       int ret;
+       u32 num;
+
+       mutex_lock(&opts->lock);
+       if (opts->refcnt) {
+               ret = -EBUSY;
+               goto end;
+       }
+
+       ret = kstrtou32(page, 0, &num);
+       if (ret)
+               goto end;
+
+       opts->iso_qlen = num;
+       ret = len;
+end:
+       mutex_unlock(&opts->lock);
+       return ret;
+}
+
+CONFIGFS_ATTR(f_ss_opts_, iso_qlen);
+
 static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_attr_pattern,
        &f_ss_opts_attr_isoc_interval,
@@ -1160,6 +1232,8 @@ static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_attr_isoc_mult,
        &f_ss_opts_attr_isoc_maxburst,
        &f_ss_opts_attr_bulk_buflen,
+       &f_ss_opts_attr_bulk_qlen,
+       &f_ss_opts_attr_iso_qlen,
        NULL,
 };
 
@@ -1189,6 +1263,8 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
        ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
        ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
        ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
+       ss_opts->bulk_qlen = GZERO_SS_BULK_QLEN;
+       ss_opts->iso_qlen = GZERO_SS_ISO_QLEN;
 
        config_group_init_type_name(&ss_opts->func_inst.group, "",
                                    &ss_func_type);
index 15f180904f8a3980e2845c38bf327e5174b8df30..4f61d95bf1772e3d26c30c383643c75ff77fd1b8 100644 (file)
@@ -10,6 +10,8 @@
 #define GZERO_QLEN             32
 #define GZERO_ISOC_INTERVAL    4
 #define GZERO_ISOC_MAXPACKET   1024
+#define GZERO_SS_BULK_QLEN     1
+#define GZERO_SS_ISO_QLEN      8
 
 struct usb_zero_options {
        unsigned pattern;
@@ -19,6 +21,8 @@ struct usb_zero_options {
        unsigned isoc_maxburst;
        unsigned bulk_buflen;
        unsigned qlen;
+       unsigned ss_bulk_qlen;
+       unsigned ss_iso_qlen;
 };
 
 struct f_ss_opts {
@@ -29,6 +33,8 @@ struct f_ss_opts {
        unsigned isoc_mult;
        unsigned isoc_maxburst;
        unsigned bulk_buflen;
+       unsigned bulk_qlen;
+       unsigned iso_qlen;
 
        /*
         * Read/write access to configfs attributes is handled by configfs.
index 37a410056fed2c8298211fe1491aef7765e283a5..0ccdcd9c64a5959dffbc41894b1b776d1748f6d7 100644 (file)
@@ -68,6 +68,8 @@ static struct usb_zero_options gzero_options = {
        .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
        .bulk_buflen = GZERO_BULK_BUFLEN,
        .qlen = GZERO_QLEN,
+       .ss_bulk_qlen = GZERO_SS_BULK_QLEN,
+       .ss_iso_qlen = GZERO_SS_ISO_QLEN,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -255,6 +257,14 @@ static struct usb_function_instance *func_inst_lb;
 module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(qlen, "depth of loopback queue");
 
+module_param_named(ss_bulk_qlen, gzero_options.ss_bulk_qlen, uint,
+               S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(bulk_qlen, "depth of sourcesink queue for bulk transfer");
+
+module_param_named(ss_iso_qlen, gzero_options.ss_iso_qlen, uint,
+               S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(iso_qlen, "depth of sourcesink queue for iso transfer");
+
 static int zero_bind(struct usb_composite_dev *cdev)
 {
        struct f_ss_opts        *ss_opts;
@@ -285,6 +295,8 @@ static int zero_bind(struct usb_composite_dev *cdev)
        ss_opts->isoc_mult = gzero_options.isoc_mult;
        ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
        ss_opts->bulk_buflen = gzero_options.bulk_buflen;
+       ss_opts->bulk_qlen = gzero_options.ss_bulk_qlen;
+       ss_opts->iso_qlen = gzero_options.ss_iso_qlen;
 
        func_ss = usb_get_function(func_inst_ss);
        if (IS_ERR(func_ss)) {