From: Vinod Koul <vkoul@kernel.org>
To: Seraj Alijan <seraj.alijan@sondrel.com>
Cc: dmaengine@vger.kernel.org, dan.j.williams@intel.com,
james.hartley@sondrel.com, sifan.naeem@sondrel.com,
ed.blake@sondrel.com
Subject: [V3,1/5] dmaengine: dmatest: Add support for multi channel testing
Date: Wed, 5 Dec 2018 22:53:13 +0530 [thread overview]
Message-ID: <20181205172313.GS2847@vkoul-mobl> (raw)
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
next reply other threads:[~2018-12-05 17:23 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-05 17:23 Vinod Koul [this message]
-- strict thread matches above, loose matches on Subject: below --
2018-09-19 19:52 [V3,1/5] dmaengine: dmatest: Add support for multi channel testing Seraj Alijan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181205172313.GS2847@vkoul-mobl \
--to=vkoul@kernel.org \
--cc=dan.j.williams@intel.com \
--cc=dmaengine@vger.kernel.org \
--cc=ed.blake@sondrel.com \
--cc=james.hartley@sondrel.com \
--cc=seraj.alijan@sondrel.com \
--cc=sifan.naeem@sondrel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox