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

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
...@@ -34,13 +34,6 @@ ...@@ -34,13 +34,6 @@
* plus two that support control-OUT tests. If the optional "autoresume" * plus two that support control-OUT tests. If the optional "autoresume"
* mode is enabled, it provides good functional coverage for the "USBCV" * mode is enabled, it provides good functional coverage for the "USBCV"
* test harness from USB-IF. * 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 f_sourcesink {
struct usb_function function; struct usb_function function;
...@@ -57,6 +50,8 @@ struct f_sourcesink { ...@@ -57,6 +50,8 @@ struct f_sourcesink {
unsigned isoc_mult; unsigned isoc_mult;
unsigned isoc_maxburst; unsigned isoc_maxburst;
unsigned buflen; unsigned buflen;
unsigned bulk_qlen;
unsigned iso_qlen;
}; };
static inline struct f_sourcesink *func_to_ss(struct usb_function *f) 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, ...@@ -595,9 +590,8 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
{ {
struct usb_ep *ep; struct usb_ep *ep;
struct usb_request *req; struct usb_request *req;
int i, size, status; int i, size, qlen, status = 0;
for (i = 0; i < 8; i++) {
if (is_iso) { if (is_iso) {
switch (speed) { switch (speed) {
case USB_SPEED_SUPER: case USB_SPEED_SUPER:
...@@ -614,12 +608,15 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, ...@@ -614,12 +608,15 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
break; break;
} }
ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
req = ss_alloc_ep_req(ep, size); qlen = ss->iso_qlen;
} else { } else {
ep = is_in ? ss->in_ep : ss->out_ep; 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) if (!req)
return -ENOMEM; return -ENOMEM;
...@@ -639,9 +636,6 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, ...@@ -639,9 +636,6 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
ep->name, status); ep->name, status);
free_ep_req(ep, req); free_ep_req(ep, req);
} }
if (!is_iso)
break;
} }
return status; return status;
...@@ -869,6 +863,8 @@ static struct usb_function *source_sink_alloc_func( ...@@ -869,6 +863,8 @@ static struct usb_function *source_sink_alloc_func(
ss->isoc_mult = ss_opts->isoc_mult; ss->isoc_mult = ss_opts->isoc_mult;
ss->isoc_maxburst = ss_opts->isoc_maxburst; ss->isoc_maxburst = ss_opts->isoc_maxburst;
ss->buflen = ss_opts->bulk_buflen; 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.name = "source/sink";
ss->function.bind = sourcesink_bind; ss->function.bind = sourcesink_bind;
...@@ -1153,6 +1149,82 @@ static ssize_t f_ss_opts_bulk_buflen_store(struct config_item *item, ...@@ -1153,6 +1149,82 @@ static ssize_t f_ss_opts_bulk_buflen_store(struct config_item *item,
CONFIGFS_ATTR(f_ss_opts_, bulk_buflen); 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[] = { static struct configfs_attribute *ss_attrs[] = {
&f_ss_opts_attr_pattern, &f_ss_opts_attr_pattern,
&f_ss_opts_attr_isoc_interval, &f_ss_opts_attr_isoc_interval,
...@@ -1160,6 +1232,8 @@ static struct configfs_attribute *ss_attrs[] = { ...@@ -1160,6 +1232,8 @@ static struct configfs_attribute *ss_attrs[] = {
&f_ss_opts_attr_isoc_mult, &f_ss_opts_attr_isoc_mult,
&f_ss_opts_attr_isoc_maxburst, &f_ss_opts_attr_isoc_maxburst,
&f_ss_opts_attr_bulk_buflen, &f_ss_opts_attr_bulk_buflen,
&f_ss_opts_attr_bulk_qlen,
&f_ss_opts_attr_iso_qlen,
NULL, NULL,
}; };
...@@ -1189,6 +1263,8 @@ static struct usb_function_instance *source_sink_alloc_inst(void) ...@@ -1189,6 +1263,8 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
ss_opts->isoc_interval = GZERO_ISOC_INTERVAL; ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET; ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
ss_opts->bulk_buflen = GZERO_BULK_BUFLEN; 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, "", config_group_init_type_name(&ss_opts->func_inst.group, "",
&ss_func_type); &ss_func_type);
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#define GZERO_QLEN 32 #define GZERO_QLEN 32
#define GZERO_ISOC_INTERVAL 4 #define GZERO_ISOC_INTERVAL 4
#define GZERO_ISOC_MAXPACKET 1024 #define GZERO_ISOC_MAXPACKET 1024
#define GZERO_SS_BULK_QLEN 1
#define GZERO_SS_ISO_QLEN 8
struct usb_zero_options { struct usb_zero_options {
unsigned pattern; unsigned pattern;
...@@ -19,6 +21,8 @@ struct usb_zero_options { ...@@ -19,6 +21,8 @@ struct usb_zero_options {
unsigned isoc_maxburst; unsigned isoc_maxburst;
unsigned bulk_buflen; unsigned bulk_buflen;
unsigned qlen; unsigned qlen;
unsigned ss_bulk_qlen;
unsigned ss_iso_qlen;
}; };
struct f_ss_opts { struct f_ss_opts {
...@@ -29,6 +33,8 @@ struct f_ss_opts { ...@@ -29,6 +33,8 @@ struct f_ss_opts {
unsigned isoc_mult; unsigned isoc_mult;
unsigned isoc_maxburst; unsigned isoc_maxburst;
unsigned bulk_buflen; unsigned bulk_buflen;
unsigned bulk_qlen;
unsigned iso_qlen;
/* /*
* Read/write access to configfs attributes is handled by configfs. * Read/write access to configfs attributes is handled by configfs.
......
...@@ -68,6 +68,8 @@ static struct usb_zero_options gzero_options = { ...@@ -68,6 +68,8 @@ static struct usb_zero_options gzero_options = {
.isoc_maxpacket = GZERO_ISOC_MAXPACKET, .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
.bulk_buflen = GZERO_BULK_BUFLEN, .bulk_buflen = GZERO_BULK_BUFLEN,
.qlen = GZERO_QLEN, .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; ...@@ -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_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(qlen, "depth of loopback queue"); 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) static int zero_bind(struct usb_composite_dev *cdev)
{ {
struct f_ss_opts *ss_opts; struct f_ss_opts *ss_opts;
...@@ -285,6 +295,8 @@ static int zero_bind(struct usb_composite_dev *cdev) ...@@ -285,6 +295,8 @@ static int zero_bind(struct usb_composite_dev *cdev)
ss_opts->isoc_mult = gzero_options.isoc_mult; ss_opts->isoc_mult = gzero_options.isoc_mult;
ss_opts->isoc_maxburst = gzero_options.isoc_maxburst; ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
ss_opts->bulk_buflen = gzero_options.bulk_buflen; 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); func_ss = usb_get_function(func_inst_ss);
if (IS_ERR(func_ss)) { if (IS_ERR(func_ss)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment