[PATCH 1/3] usb: gadget: f_sourcesink: add queue depth

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

 



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.

Signed-off-by: Peter Chen <peter.chen@xxxxxxxxxxxxx>
---
 drivers/usb/gadget/function/f_sourcesink.c | 144 ++++++++++++++++++++++-------
 drivers/usb/gadget/function/g_zero.h       |   6 ++
 drivers/usb/gadget/legacy/zero.c           |  12 +++
 3 files changed, 129 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index d7646d3..4ab603e8 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -34,13 +34,6 @@
  * 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;
@@ -1164,6 +1160,84 @@ static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
 			f_ss_opts_bulk_buflen_show,
 			f_ss_opts_bulk_buflen_store);
 
+static ssize_t f_ss_opts_bulk_qlen_show(struct f_ss_opts *opts, char *page)
+{
+	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 f_ss_opts *opts,
+					   const char *page, size_t len)
+{
+	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;
+}
+
+static struct f_ss_opts_attribute f_ss_opts_bulk_qlen =
+	__CONFIGFS_ATTR(bulk_qlen, S_IRUGO | S_IWUSR,
+			f_ss_opts_bulk_qlen_show,
+			f_ss_opts_bulk_qlen_store);
+
+static ssize_t f_ss_opts_iso_qlen_show(struct f_ss_opts *opts, char *page)
+{
+	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 f_ss_opts *opts,
+					   const char *page, size_t len)
+{
+	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;
+}
+
+static struct f_ss_opts_attribute f_ss_opts_iso_qlen =
+	__CONFIGFS_ATTR(iso_qlen, S_IRUGO | S_IWUSR,
+			f_ss_opts_iso_qlen_show,
+			f_ss_opts_iso_qlen_store);
+
 static struct configfs_attribute *ss_attrs[] = {
 	&f_ss_opts_pattern.attr,
 	&f_ss_opts_isoc_interval.attr,
@@ -1171,6 +1245,8 @@ static struct configfs_attribute *ss_attrs[] = {
 	&f_ss_opts_isoc_mult.attr,
 	&f_ss_opts_isoc_maxburst.attr,
 	&f_ss_opts_bulk_buflen.attr,
+	&f_ss_opts_bulk_qlen.attr,
+	&f_ss_opts_iso_qlen.attr,
 	NULL,
 };
 
@@ -1200,6 +1276,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);
diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h
index 15f1809..4f61d95 100644
--- a/drivers/usb/gadget/function/g_zero.h
+++ b/drivers/usb/gadget/function/g_zero.h
@@ -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.
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
index 37a4100..0ccdcd9 100644
--- a/drivers/usb/gadget/legacy/zero.c
+++ b/drivers/usb/gadget/legacy/zero.c
@@ -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)) {
-- 
1.9.1

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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux