diff options
Diffstat (limited to 'drivers/dma/dmatest.c')
-rw-r--r-- | drivers/dma/dmatest.c | 72 |
1 files changed, 47 insertions, 25 deletions
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 26b502069638..dd4d84d556d5 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c | |||
@@ -161,6 +161,43 @@ struct dmatest_chan { | |||
161 | struct list_head threads; | 161 | struct list_head threads; |
162 | }; | 162 | }; |
163 | 163 | ||
164 | static DECLARE_WAIT_QUEUE_HEAD(thread_wait); | ||
165 | static bool wait; | ||
166 | |||
167 | static bool is_threaded_test_run(struct dmatest_info *info) | ||
168 | { | ||
169 | struct dmatest_chan *dtc; | ||
170 | |||
171 | list_for_each_entry(dtc, &info->channels, node) { | ||
172 | struct dmatest_thread *thread; | ||
173 | |||
174 | list_for_each_entry(thread, &dtc->threads, node) { | ||
175 | if (!thread->done) | ||
176 | return true; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | return false; | ||
181 | } | ||
182 | |||
183 | static int dmatest_wait_get(char *val, const struct kernel_param *kp) | ||
184 | { | ||
185 | struct dmatest_info *info = &test_info; | ||
186 | struct dmatest_params *params = &info->params; | ||
187 | |||
188 | if (params->iterations) | ||
189 | wait_event(thread_wait, !is_threaded_test_run(info)); | ||
190 | wait = true; | ||
191 | return param_get_bool(val, kp); | ||
192 | } | ||
193 | |||
194 | static struct kernel_param_ops wait_ops = { | ||
195 | .get = dmatest_wait_get, | ||
196 | .set = param_set_bool, | ||
197 | }; | ||
198 | module_param_cb(wait, &wait_ops, &wait, S_IRUGO); | ||
199 | MODULE_PARM_DESC(wait, "Wait for tests to complete (default: false)"); | ||
200 | |||
164 | static bool dmatest_match_channel(struct dmatest_params *params, | 201 | static bool dmatest_match_channel(struct dmatest_params *params, |
165 | struct dma_chan *chan) | 202 | struct dma_chan *chan) |
166 | { | 203 | { |
@@ -660,12 +697,7 @@ err_thread_type: | |||
660 | dmaengine_terminate_all(chan); | 697 | dmaengine_terminate_all(chan); |
661 | 698 | ||
662 | thread->done = true; | 699 | thread->done = true; |
663 | 700 | wake_up(&thread_wait); | |
664 | if (params->iterations > 0) | ||
665 | while (!kthread_should_stop()) { | ||
666 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); | ||
667 | interruptible_sleep_on(&wait_dmatest_exit); | ||
668 | } | ||
669 | 701 | ||
670 | return ret; | 702 | return ret; |
671 | } | 703 | } |
@@ -681,6 +713,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) | |||
681 | pr_debug("thread %s exited with status %d\n", | 713 | pr_debug("thread %s exited with status %d\n", |
682 | thread->task->comm, ret); | 714 | thread->task->comm, ret); |
683 | list_del(&thread->node); | 715 | list_del(&thread->node); |
716 | put_task_struct(thread->task); | ||
684 | kfree(thread); | 717 | kfree(thread); |
685 | } | 718 | } |
686 | 719 | ||
@@ -719,18 +752,19 @@ static int dmatest_add_threads(struct dmatest_info *info, | |||
719 | thread->chan = dtc->chan; | 752 | thread->chan = dtc->chan; |
720 | thread->type = type; | 753 | thread->type = type; |
721 | smp_wmb(); | 754 | smp_wmb(); |
722 | thread->task = kthread_run(dmatest_func, thread, "%s-%s%u", | 755 | thread->task = kthread_create(dmatest_func, thread, "%s-%s%u", |
723 | dma_chan_name(chan), op, i); | 756 | dma_chan_name(chan), op, i); |
724 | if (IS_ERR(thread->task)) { | 757 | if (IS_ERR(thread->task)) { |
725 | pr_warn("Failed to run thread %s-%s%u\n", | 758 | pr_warn("Failed to create thread %s-%s%u\n", |
726 | dma_chan_name(chan), op, i); | 759 | dma_chan_name(chan), op, i); |
727 | kfree(thread); | 760 | kfree(thread); |
728 | break; | 761 | break; |
729 | } | 762 | } |
730 | 763 | ||
731 | /* srcbuf and dstbuf are allocated by the thread itself */ | 764 | /* srcbuf and dstbuf are allocated by the thread itself */ |
732 | 765 | get_task_struct(thread->task); | |
733 | list_add_tail(&thread->node, &dtc->threads); | 766 | list_add_tail(&thread->node, &dtc->threads); |
767 | wake_up_process(thread->task); | ||
734 | } | 768 | } |
735 | 769 | ||
736 | return i; | 770 | return i; |
@@ -863,22 +897,6 @@ static void restart_threaded_test(struct dmatest_info *info, bool run) | |||
863 | run_threaded_test(info); | 897 | run_threaded_test(info); |
864 | } | 898 | } |
865 | 899 | ||
866 | static bool is_threaded_test_run(struct dmatest_info *info) | ||
867 | { | ||
868 | struct dmatest_chan *dtc; | ||
869 | |||
870 | list_for_each_entry(dtc, &info->channels, node) { | ||
871 | struct dmatest_thread *thread; | ||
872 | |||
873 | list_for_each_entry(thread, &dtc->threads, node) { | ||
874 | if (!thread->done) | ||
875 | return true; | ||
876 | } | ||
877 | } | ||
878 | |||
879 | return false; | ||
880 | } | ||
881 | |||
882 | static int dmatest_run_get(char *val, const struct kernel_param *kp) | 900 | static int dmatest_run_get(char *val, const struct kernel_param *kp) |
883 | { | 901 | { |
884 | struct dmatest_info *info = &test_info; | 902 | struct dmatest_info *info = &test_info; |
@@ -920,6 +938,7 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp) | |||
920 | static int __init dmatest_init(void) | 938 | static int __init dmatest_init(void) |
921 | { | 939 | { |
922 | struct dmatest_info *info = &test_info; | 940 | struct dmatest_info *info = &test_info; |
941 | struct dmatest_params *params = &info->params; | ||
923 | 942 | ||
924 | if (dmatest_run) { | 943 | if (dmatest_run) { |
925 | mutex_lock(&info->lock); | 944 | mutex_lock(&info->lock); |
@@ -927,6 +946,9 @@ static int __init dmatest_init(void) | |||
927 | mutex_unlock(&info->lock); | 946 | mutex_unlock(&info->lock); |
928 | } | 947 | } |
929 | 948 | ||
949 | if (params->iterations && wait) | ||
950 | wait_event(thread_wait, !is_threaded_test_run(info)); | ||
951 | |||
930 | /* module parameters are stable, inittime tests are started, | 952 | /* module parameters are stable, inittime tests are started, |
931 | * let userspace take over 'run' control | 953 | * let userspace take over 'run' control |
932 | */ | 954 | */ |