Commit 2d88ce76 authored by Dan Williams's avatar Dan Williams

dmatest: add a 'wait' parameter

Allows for scripting test runs by module load / unload.  Prevent module
load from returning until 'iterations' (finite) tests have completed, or
cause reads of the 'wait' parameter in sysfs to pause until the tests
are done.

Also killed the local waitqueue since we can just let the thread exit
naturally as long as we hold a reference.

Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 86727443
...@@ -39,17 +39,24 @@ stops. ...@@ -39,17 +39,24 @@ stops.
Note that running a new test will not stop any in progress test. Note that running a new test will not stop any in progress test.
The following command should return actual state of the test. The following command returns the state of the test.
% cat /sys/kernel/debug/dmatest/run % cat /sys/module/dmatest/parameters/run
To wait for test done the user may perform a busy loop that checks the state. To wait for test completion userpace can poll 'run' until it is false, or use
the wait parameter. Specifying 'wait=1' when loading the module causes module
initialization to pause until a test run has completed, while reading
/sys/module/dmatest/parameters/wait waits for any running test to complete
before returning. For example, the following scripts wait for 42 tests
to complete before exiting. Note that if 'iterations' is set to 'infinite' then
waiting is disabled.
% while [ $(cat /sys/module/dmatest/parameters/run) = "Y" ] Example:
> do % modprobe dmatest run=1 iterations=42 wait=1
> echo -n "." % modprobe -r dmatest
> sleep 1 ...or:
> done % modprobe dmatest run=1 iterations=42
> echo % cat /sys/module/dmatest/parameters/wait
% modprobe -r dmatest
Part 3 - When built-in in the kernel... Part 3 - When built-in in the kernel...
...@@ -79,7 +86,7 @@ number of tests executed, number that failed, and a result code. ...@@ -79,7 +86,7 @@ number of tests executed, number that failed, and a result code.
Example: Example:
% dmesg | tail -n 1 % dmesg | tail -n 1
dmatest: dma3chan0-copy0: summary 400000 tests, 0 failures iops: 61524 KB/s 246098 (0) dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0)
The details of a data miscompare error are also emitted, but do not follow the The details of a data miscompare error are also emitted, but do not follow the
above format. above format.
...@@ -161,6 +161,43 @@ struct dmatest_chan { ...@@ -161,6 +161,43 @@ struct dmatest_chan {
struct list_head threads; struct list_head threads;
}; };
static DECLARE_WAIT_QUEUE_HEAD(thread_wait);
static bool wait;
static bool is_threaded_test_run(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->done)
return true;
}
}
return false;
}
static int dmatest_wait_get(char *val, const struct kernel_param *kp)
{
struct dmatest_info *info = &test_info;
struct dmatest_params *params = &info->params;
if (params->iterations)
wait_event(thread_wait, !is_threaded_test_run(info));
wait = true;
return param_get_bool(val, kp);
}
static struct kernel_param_ops wait_ops = {
.get = dmatest_wait_get,
.set = param_set_bool,
};
module_param_cb(wait, &wait_ops, &wait, S_IRUGO);
MODULE_PARM_DESC(wait, "Wait for tests to complete (default: false)");
static bool dmatest_match_channel(struct dmatest_params *params, static bool dmatest_match_channel(struct dmatest_params *params,
struct dma_chan *chan) struct dma_chan *chan)
{ {
...@@ -660,12 +697,7 @@ static int dmatest_func(void *data) ...@@ -660,12 +697,7 @@ static int dmatest_func(void *data)
dmaengine_terminate_all(chan); dmaengine_terminate_all(chan);
thread->done = true; thread->done = true;
wake_up(&thread_wait);
if (params->iterations > 0)
while (!kthread_should_stop()) {
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit);
interruptible_sleep_on(&wait_dmatest_exit);
}
return ret; return ret;
} }
...@@ -681,6 +713,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) ...@@ -681,6 +713,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc)
pr_debug("thread %s exited with status %d\n", pr_debug("thread %s exited with status %d\n",
thread->task->comm, ret); thread->task->comm, ret);
list_del(&thread->node); list_del(&thread->node);
put_task_struct(thread->task);
kfree(thread); kfree(thread);
} }
...@@ -719,18 +752,19 @@ static int dmatest_add_threads(struct dmatest_info *info, ...@@ -719,18 +752,19 @@ static int dmatest_add_threads(struct dmatest_info *info,
thread->chan = dtc->chan; thread->chan = dtc->chan;
thread->type = type; thread->type = type;
smp_wmb(); smp_wmb();
thread->task = kthread_run(dmatest_func, thread, "%s-%s%u", thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
dma_chan_name(chan), op, i); dma_chan_name(chan), op, i);
if (IS_ERR(thread->task)) { if (IS_ERR(thread->task)) {
pr_warn("Failed to run thread %s-%s%u\n", pr_warn("Failed to create thread %s-%s%u\n",
dma_chan_name(chan), op, i); dma_chan_name(chan), op, i);
kfree(thread); kfree(thread);
break; break;
} }
/* srcbuf and dstbuf are allocated by the thread itself */ /* srcbuf and dstbuf are allocated by the thread itself */
get_task_struct(thread->task);
list_add_tail(&thread->node, &dtc->threads); list_add_tail(&thread->node, &dtc->threads);
wake_up_process(thread->task);
} }
return i; return i;
...@@ -863,22 +897,6 @@ static void restart_threaded_test(struct dmatest_info *info, bool run) ...@@ -863,22 +897,6 @@ static void restart_threaded_test(struct dmatest_info *info, bool run)
run_threaded_test(info); run_threaded_test(info);
} }
static bool is_threaded_test_run(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->done)
return true;
}
}
return false;
}
static int dmatest_run_get(char *val, const struct kernel_param *kp) static int dmatest_run_get(char *val, const struct kernel_param *kp)
{ {
struct dmatest_info *info = &test_info; struct dmatest_info *info = &test_info;
...@@ -920,6 +938,7 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp) ...@@ -920,6 +938,7 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp)
static int __init dmatest_init(void) static int __init dmatest_init(void)
{ {
struct dmatest_info *info = &test_info; struct dmatest_info *info = &test_info;
struct dmatest_params *params = &info->params;
if (dmatest_run) { if (dmatest_run) {
mutex_lock(&info->lock); mutex_lock(&info->lock);
...@@ -927,6 +946,9 @@ static int __init dmatest_init(void) ...@@ -927,6 +946,9 @@ static int __init dmatest_init(void)
mutex_unlock(&info->lock); mutex_unlock(&info->lock);
} }
if (params->iterations && wait)
wait_event(thread_wait, !is_threaded_test_run(info));
/* module parameters are stable, inittime tests are started, /* module parameters are stable, inittime tests are started,
* let userspace take over 'run' control * let userspace take over 'run' control
*/ */
......
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