Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d6c3d96 authored by Peter Chen's avatar Peter Chen Committed by Felipe Balbi
Browse files

usb: gadget: f_sourcesink: add queue depth



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: default avatarKrzysztof Opasiak <k.opasiak@samsung.com>
Signed-off-by: default avatarPeter Chen <peter.chen@freescale.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent b0846627
Loading
Loading
Loading
Loading
+109 −33
Original line number Diff line number Diff line
@@ -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,9 +590,8 @@ 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;
	int			i, size, qlen, status = 0;

	for (i = 0; i < 8; i++) {
	if (is_iso) {
		switch (speed) {
		case USB_SPEED_SUPER:
@@ -614,12 +608,15 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
			break;
		}
		ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
			req = ss_alloc_ep_req(ep, size);
		qlen = ss->iso_qlen;
	} else {
		ep = is_in ? ss->in_ep : ss->out_ep;
			req = ss_alloc_ep_req(ep, 0);
		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 @@ static ssize_t f_ss_opts_bulk_buflen_store(struct config_item *item,

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);
+6 −0
Original line number Diff line number Diff line
@@ -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.
+12 −0
Original line number Diff line number Diff line
@@ -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)) {