Message ID | 1537386774-20749-2-git-send-email-seraj.alijan@sondrel.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | dmaengine: dmatest: Add multi chan and new params | expand |
On 19-09-18, 20:52, Seraj Alijan wrote: > Add support for running tests on multiple channels simultaneously as the > driver currently limits to 1 channel per test run. This will add support > for stress testing DMA controllers with multi channel capabilities. > > This is done by adding a callback function to the "channel" parameter > that registers the requested channel prior to the "run" parameter being > set to 1. Each time the "channel" parameter is populated with a new > dma channel, a new test is appended to the thread queue. Once the "run" > parameter is set to 1, the test will kick start all pending threads. > > Signed-off-by: Seraj Alijan <seraj.alijan@sondrel.com> > --- > drivers/dma/dmatest.c | 196 +++++++++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 177 insertions(+), 19 deletions(-) > > diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c > index aa1712b..ea69033 100644 > --- a/drivers/dma/dmatest.c > +++ b/drivers/dma/dmatest.c > @@ -27,11 +27,6 @@ static unsigned int test_buf_size = 16384; > module_param(test_buf_size, uint, S_IRUGO | S_IWUSR); > MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer"); > > -static char test_channel[20]; > -module_param_string(channel, test_channel, sizeof(test_channel), > - S_IRUGO | S_IWUSR); > -MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); > - > static char test_device[32]; > module_param_string(device, test_device, sizeof(test_device), > S_IRUGO | S_IWUSR); > @@ -139,6 +134,28 @@ static bool dmatest_run; > module_param_cb(run, &run_ops, &dmatest_run, S_IRUGO | S_IWUSR); > MODULE_PARM_DESC(run, "Run the test (default: false)"); > > +static int dmatest_chan_set(const char *val, const struct kernel_param *kp); > +static int dmatest_chan_get(char *val, const struct kernel_param *kp); > +static const struct kernel_param_ops multi_chan_ops = { > + .set = dmatest_chan_set, > + .get = dmatest_chan_get, > +}; > + > +static char test_channel[20]; > +static struct kparam_string newchan_kps = { > + .string = test_channel, > + .maxlen = 20, > +}; > +module_param_cb(channel, &multi_chan_ops, &newchan_kps, 0644); > +MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); > + > +static int dmatest_test_list_get(char *val, const struct kernel_param *kp); > +static const struct kernel_param_ops test_list_ops = { > + .get = dmatest_test_list_get, > +}; > +module_param_cb(test_list, &test_list_ops, NULL, 0444); > +MODULE_PARM_DESC(test_list, "Print current test list"); > + > /* Maximum amount of mismatched bytes in buffer to print */ > #define MAX_ERROR_COUNT 32 > > @@ -179,6 +196,7 @@ struct dmatest_thread { > wait_queue_head_t done_wait; > struct dmatest_done test_done; > bool done; > + bool pending; > }; > > struct dmatest_chan { > @@ -206,6 +224,22 @@ static bool is_threaded_test_run(struct dmatest_info *info) > return false; > } > > +static bool is_threaded_test_pending(struct dmatest_info *info) > +{ > + struct dmatest_chan *dtc; > + > + list_for_each_entry(dtc, &info->channels, node) { > + struct dmatest_thread *thread; > + > + list_for_each_entry(thread, &dtc->threads, node) { > + if (thread->pending) > + return true; > + } > + } > + > + return false; > +} > + > static int dmatest_wait_get(char *val, const struct kernel_param *kp) > { > struct dmatest_info *info = &test_info; > @@ -476,6 +510,7 @@ static int dmatest_func(void *data) > ret = -ENOMEM; > > smp_rmb(); > + thread->pending = false; > info = thread->info; > params = &info->params; > chan = thread->chan; > @@ -886,7 +921,7 @@ static int dmatest_add_threads(struct dmatest_info *info, > /* srcbuf and dstbuf are allocated by the thread itself */ > get_task_struct(thread->task); > list_add_tail(&thread->node, &dtc->threads); > - wake_up_process(thread->task); > + thread->pending = true; > } > > return i; > @@ -932,7 +967,7 @@ static int dmatest_add_channel(struct dmatest_info *info, > thread_count += cnt > 0 ? cnt : 0; > } > > - pr_info("Started %u threads using %s\n", > + pr_info("Added %u threads using %s\n", > thread_count, dma_chan_name(chan)); > > list_add_tail(&dtc->node, &info->channels); > @@ -977,7 +1012,7 @@ static void request_channels(struct dmatest_info *info, > } > } > > -static void run_threaded_test(struct dmatest_info *info) > +static void add_threaded_test(struct dmatest_info *info) > { > struct dmatest_params *params = &info->params; > > @@ -1000,6 +1035,24 @@ static void run_threaded_test(struct dmatest_info *info) > request_channels(info, DMA_PQ); > } > > +static void run_pending_tests(struct dmatest_info *info) > +{ > + struct dmatest_chan *dtc; > + unsigned int thread_count = 0; > + > + list_for_each_entry(dtc, &info->channels, node) { > + struct dmatest_thread *thread; > + > + thread_count = 0; > + list_for_each_entry(thread, &dtc->threads, node) { > + wake_up_process(thread->task); > + thread_count++; > + } > + pr_info("Started %u threads using %s\n", > + thread_count, dma_chan_name(dtc->chan)); > + } > +} > + > static void stop_threaded_test(struct dmatest_info *info) > { > struct dmatest_chan *dtc, *_dtc; > @@ -1016,7 +1069,7 @@ static void stop_threaded_test(struct dmatest_info *info) > info->nr_channels = 0; > } > > -static void restart_threaded_test(struct dmatest_info *info, bool run) > +static void start_threaded_tests(struct dmatest_info *info) > { > /* we might be called early to set run=, defer running until all > * parameters have been evaluated > @@ -1024,11 +1077,7 @@ static void restart_threaded_test(struct dmatest_info *info, bool run) > if (!info->did_init) > return; > > - /* Stop any running test first */ > - stop_threaded_test(info); > - > - /* Run test with new parameters */ > - run_threaded_test(info); > + run_pending_tests(info); > } > > static int dmatest_run_get(char *val, const struct kernel_param *kp) > @@ -1039,7 +1088,8 @@ static int dmatest_run_get(char *val, const struct kernel_param *kp) > if (is_threaded_test_run(info)) { > dmatest_run = true; > } else { > - stop_threaded_test(info); > + if (!is_threaded_test_pending(info)) > + stop_threaded_test(info); > dmatest_run = false; > } > mutex_unlock(&info->lock); > @@ -1057,18 +1107,125 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp) > if (ret) { > mutex_unlock(&info->lock); > return ret; > + } else if (dmatest_run) { > + if (is_threaded_test_pending(info)) > + start_threaded_tests(info); > + else > + pr_info("Could not start test, no channels configured\n"); > + } else { > + stop_threaded_test(info); > + } > + > + mutex_unlock(&info->lock); > + > + return ret; > +} > + > +static int dmatest_chan_set(const char *val, const struct kernel_param *kp) > +{ > + struct dmatest_info *info = &test_info; > + struct dmatest_chan *dtc; > + char chan_reset_val[20]; > + int ret = 0; > + > + mutex_lock(&info->lock); > + ret = param_set_copystring(val, kp); > + if (ret) { > + mutex_unlock(&info->lock); > + return ret; > + } > + /*Clear any previously run threads */ > + if (!is_threaded_test_run(info) && !is_threaded_test_pending(info)) > + stop_threaded_test(info); > + /* Reject channels that are already registered */ > + if (is_threaded_test_pending(info)) { > + list_for_each_entry(dtc, &info->channels, node) { > + if (strcmp(dma_chan_name(dtc->chan), > + strim(test_channel)) == 0) { > + dtc = list_last_entry(&info->channels, > + struct dmatest_chan, > + node); > + strlcpy(chan_reset_val, > + dma_chan_name(dtc->chan), > + sizeof(chan_reset_val)); > + ret = -EBUSY; > + goto add_chan_err; > + } > + } > } > > - if (is_threaded_test_run(info)) > + add_threaded_test(info); > + > + /* Check if channel was added successfully */ > + dtc = list_last_entry(&info->channels, struct dmatest_chan, node); > + > + if (dtc->chan) { > + /* > + * if new channel was not successfully added, revert the the ^^^^^^^^^^ duplicate the > + * "test_channel" string to the name of the last successfully > + * added channel. exception for when users issues empty string > + * to channel parameter. > + */ > + if ((strcmp(dma_chan_name(dtc->chan), strim(test_channel)) != 0) > + && (strcmp("", strim(test_channel)) != 0)) { > + ret = -EINVAL; > + strlcpy(chan_reset_val, dma_chan_name(dtc->chan), > + sizeof(chan_reset_val)); > + goto add_chan_err; > + } > + > + } else { > + /* Clear test_channel if no channels were added successfully */ > + strlcpy(chan_reset_val, "", sizeof(chan_reset_val)); > ret = -EBUSY; > - else if (dmatest_run) > - restart_threaded_test(info, dmatest_run); > + goto add_chan_err; > + } > + > + mutex_unlock(&info->lock); > + > + return ret; > > +add_chan_err: > + param_set_copystring(chan_reset_val, kp); > mutex_unlock(&info->lock); > > return ret; > } > > +static int dmatest_chan_get(char *val, const struct kernel_param *kp) > +{ > + struct dmatest_info *info = &test_info; > + > + mutex_lock(&info->lock); > + if (!is_threaded_test_run(info) && !is_threaded_test_pending(info)) { > + stop_threaded_test(info); > + strlcpy(test_channel, "", sizeof(test_channel)); > + } > + mutex_unlock(&info->lock); > + > + return param_get_string(val, kp); > +} > + > +static int dmatest_test_list_get(char *val, const struct kernel_param *kp) > +{ > + struct dmatest_info *info = &test_info; > + struct dmatest_chan *dtc; > + unsigned int thread_count = 0; > + > + list_for_each_entry(dtc, &info->channels, node) { > + struct dmatest_thread *thread; > + > + thread_count = 0; > + list_for_each_entry(thread, &dtc->threads, node) { > + thread_count++; > + } > + pr_info("%u threads using %s\n", > + thread_count, dma_chan_name(dtc->chan)); > + } > + > + return 0; > +} > + > static int __init dmatest_init(void) > { > struct dmatest_info *info = &test_info; > @@ -1076,7 +1233,8 @@ static int __init dmatest_init(void) > > if (dmatest_run) { > mutex_lock(&info->lock); > - run_threaded_test(info); > + add_threaded_test(info); > + run_pending_tests(info); > mutex_unlock(&info->lock); > } > > -- > 2.7.4
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index aa1712b..ea69033 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -27,11 +27,6 @@ static unsigned int test_buf_size = 16384; module_param(test_buf_size, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer"); -static char test_channel[20]; -module_param_string(channel, test_channel, sizeof(test_channel), - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); - static char test_device[32]; module_param_string(device, test_device, sizeof(test_device), S_IRUGO | S_IWUSR); @@ -139,6 +134,28 @@ static bool dmatest_run; module_param_cb(run, &run_ops, &dmatest_run, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(run, "Run the test (default: false)"); +static int dmatest_chan_set(const char *val, const struct kernel_param *kp); +static int dmatest_chan_get(char *val, const struct kernel_param *kp); +static const struct kernel_param_ops multi_chan_ops = { + .set = dmatest_chan_set, + .get = dmatest_chan_get, +}; + +static char test_channel[20]; +static struct kparam_string newchan_kps = { + .string = test_channel, + .maxlen = 20, +}; +module_param_cb(channel, &multi_chan_ops, &newchan_kps, 0644); +MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); + +static int dmatest_test_list_get(char *val, const struct kernel_param *kp); +static const struct kernel_param_ops test_list_ops = { + .get = dmatest_test_list_get, +}; +module_param_cb(test_list, &test_list_ops, NULL, 0444); +MODULE_PARM_DESC(test_list, "Print current test list"); + /* Maximum amount of mismatched bytes in buffer to print */ #define MAX_ERROR_COUNT 32 @@ -179,6 +196,7 @@ struct dmatest_thread { wait_queue_head_t done_wait; struct dmatest_done test_done; bool done; + bool pending; }; struct dmatest_chan { @@ -206,6 +224,22 @@ static bool is_threaded_test_run(struct dmatest_info *info) return false; } +static bool is_threaded_test_pending(struct dmatest_info *info) +{ + struct dmatest_chan *dtc; + + list_for_each_entry(dtc, &info->channels, node) { + struct dmatest_thread *thread; + + list_for_each_entry(thread, &dtc->threads, node) { + if (thread->pending) + return true; + } + } + + return false; +} + static int dmatest_wait_get(char *val, const struct kernel_param *kp) { struct dmatest_info *info = &test_info; @@ -476,6 +510,7 @@ static int dmatest_func(void *data) ret = -ENOMEM; smp_rmb(); + thread->pending = false; info = thread->info; params = &info->params; chan = thread->chan; @@ -886,7 +921,7 @@ static int dmatest_add_threads(struct dmatest_info *info, /* srcbuf and dstbuf are allocated by the thread itself */ get_task_struct(thread->task); list_add_tail(&thread->node, &dtc->threads); - wake_up_process(thread->task); + thread->pending = true; } return i; @@ -932,7 +967,7 @@ static int dmatest_add_channel(struct dmatest_info *info, thread_count += cnt > 0 ? cnt : 0; } - pr_info("Started %u threads using %s\n", + pr_info("Added %u threads using %s\n", thread_count, dma_chan_name(chan)); list_add_tail(&dtc->node, &info->channels); @@ -977,7 +1012,7 @@ static void request_channels(struct dmatest_info *info, } } -static void run_threaded_test(struct dmatest_info *info) +static void add_threaded_test(struct dmatest_info *info) { struct dmatest_params *params = &info->params; @@ -1000,6 +1035,24 @@ static void run_threaded_test(struct dmatest_info *info) request_channels(info, DMA_PQ); } +static void run_pending_tests(struct dmatest_info *info) +{ + struct dmatest_chan *dtc; + unsigned int thread_count = 0; + + list_for_each_entry(dtc, &info->channels, node) { + struct dmatest_thread *thread; + + thread_count = 0; + list_for_each_entry(thread, &dtc->threads, node) { + wake_up_process(thread->task); + thread_count++; + } + pr_info("Started %u threads using %s\n", + thread_count, dma_chan_name(dtc->chan)); + } +} + static void stop_threaded_test(struct dmatest_info *info) { struct dmatest_chan *dtc, *_dtc; @@ -1016,7 +1069,7 @@ static void stop_threaded_test(struct dmatest_info *info) info->nr_channels = 0; } -static void restart_threaded_test(struct dmatest_info *info, bool run) +static void start_threaded_tests(struct dmatest_info *info) { /* we might be called early to set run=, defer running until all * parameters have been evaluated @@ -1024,11 +1077,7 @@ static void restart_threaded_test(struct dmatest_info *info, bool run) if (!info->did_init) return; - /* Stop any running test first */ - stop_threaded_test(info); - - /* Run test with new parameters */ - run_threaded_test(info); + run_pending_tests(info); } static int dmatest_run_get(char *val, const struct kernel_param *kp) @@ -1039,7 +1088,8 @@ static int dmatest_run_get(char *val, const struct kernel_param *kp) if (is_threaded_test_run(info)) { dmatest_run = true; } else { - stop_threaded_test(info); + if (!is_threaded_test_pending(info)) + stop_threaded_test(info); dmatest_run = false; } mutex_unlock(&info->lock); @@ -1057,18 +1107,125 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp) if (ret) { mutex_unlock(&info->lock); return ret; + } else if (dmatest_run) { + if (is_threaded_test_pending(info)) + start_threaded_tests(info); + else + pr_info("Could not start test, no channels configured\n"); + } else { + stop_threaded_test(info); + } + + mutex_unlock(&info->lock); + + return ret; +} + +static int dmatest_chan_set(const char *val, const struct kernel_param *kp) +{ + struct dmatest_info *info = &test_info; + struct dmatest_chan *dtc; + char chan_reset_val[20]; + int ret = 0; + + mutex_lock(&info->lock); + ret = param_set_copystring(val, kp); + if (ret) { + mutex_unlock(&info->lock); + return ret; + } + /*Clear any previously run threads */ + if (!is_threaded_test_run(info) && !is_threaded_test_pending(info)) + stop_threaded_test(info); + /* Reject channels that are already registered */ + if (is_threaded_test_pending(info)) { + list_for_each_entry(dtc, &info->channels, node) { + if (strcmp(dma_chan_name(dtc->chan), + strim(test_channel)) == 0) { + dtc = list_last_entry(&info->channels, + struct dmatest_chan, + node); + strlcpy(chan_reset_val, + dma_chan_name(dtc->chan), + sizeof(chan_reset_val)); + ret = -EBUSY; + goto add_chan_err; + } + } } - if (is_threaded_test_run(info)) + add_threaded_test(info); + + /* Check if channel was added successfully */ + dtc = list_last_entry(&info->channels, struct dmatest_chan, node); + + if (dtc->chan) { + /* + * if new channel was not successfully added, revert the the + * "test_channel" string to the name of the last successfully + * added channel. exception for when users issues empty string + * to channel parameter. + */ + if ((strcmp(dma_chan_name(dtc->chan), strim(test_channel)) != 0) + && (strcmp("", strim(test_channel)) != 0)) { + ret = -EINVAL; + strlcpy(chan_reset_val, dma_chan_name(dtc->chan), + sizeof(chan_reset_val)); + goto add_chan_err; + } + + } else { + /* Clear test_channel if no channels were added successfully */ + strlcpy(chan_reset_val, "", sizeof(chan_reset_val)); ret = -EBUSY; - else if (dmatest_run) - restart_threaded_test(info, dmatest_run); + goto add_chan_err; + } + + mutex_unlock(&info->lock); + + return ret; +add_chan_err: + param_set_copystring(chan_reset_val, kp); mutex_unlock(&info->lock); return ret; } +static int dmatest_chan_get(char *val, const struct kernel_param *kp) +{ + struct dmatest_info *info = &test_info; + + mutex_lock(&info->lock); + if (!is_threaded_test_run(info) && !is_threaded_test_pending(info)) { + stop_threaded_test(info); + strlcpy(test_channel, "", sizeof(test_channel)); + } + mutex_unlock(&info->lock); + + return param_get_string(val, kp); +} + +static int dmatest_test_list_get(char *val, const struct kernel_param *kp) +{ + struct dmatest_info *info = &test_info; + struct dmatest_chan *dtc; + unsigned int thread_count = 0; + + list_for_each_entry(dtc, &info->channels, node) { + struct dmatest_thread *thread; + + thread_count = 0; + list_for_each_entry(thread, &dtc->threads, node) { + thread_count++; + } + pr_info("%u threads using %s\n", + thread_count, dma_chan_name(dtc->chan)); + } + + return 0; +} + static int __init dmatest_init(void) { struct dmatest_info *info = &test_info; @@ -1076,7 +1233,8 @@ static int __init dmatest_init(void) if (dmatest_run) { mutex_lock(&info->lock); - run_threaded_test(info); + add_threaded_test(info); + run_pending_tests(info); mutex_unlock(&info->lock); }
Add support for running tests on multiple channels simultaneously as the driver currently limits to 1 channel per test run. This will add support for stress testing DMA controllers with multi channel capabilities. This is done by adding a callback function to the "channel" parameter that registers the requested channel prior to the "run" parameter being set to 1. Each time the "channel" parameter is populated with a new dma channel, a new test is appended to the thread queue. Once the "run" parameter is set to 1, the test will kick start all pending threads. Signed-off-by: Seraj Alijan <seraj.alijan@sondrel.com> --- drivers/dma/dmatest.c | 196 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 177 insertions(+), 19 deletions(-)