diff options
author | Dan Williams <dan.j.williams@intel.com> | 2013-11-06 19:30:01 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2013-11-14 14:04:39 -0500 |
commit | a310d037b8d06755c62bb4878c00d19490af5550 (patch) | |
tree | 7546e7c90f51bb2491558ce4772740ad9e903540 | |
parent | 0adff800662f52d0ffc3e420db231769cb3fff13 (diff) |
dmatest: restore ability to start test at module load and init
1/ move 'run' control to a module parameter so we can do:
modprobe dmatest run=1. With this moved the rest of the debugfs
boilerplate can go.
2/ Fix parameter initialization. Previously the test was being started
without taking the parameters into account in the built-in case.
Also killed off the '__' version of some routines. The new rule is just
hold the lock when calling a *threaded_test() routine.
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | Documentation/dmatest.txt | 18 | ||||
-rw-r--r-- | drivers/dma/dmatest.c | 265 |
2 files changed, 116 insertions, 167 deletions
diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt index 45b8c95f1a21..e6e16a7f3706 100644 --- a/Documentation/dmatest.txt +++ b/Documentation/dmatest.txt | |||
@@ -15,17 +15,19 @@ be built as module or inside kernel. Let's consider those cases. | |||
15 | 15 | ||
16 | Part 2 - When dmatest is built as a module... | 16 | Part 2 - When dmatest is built as a module... |
17 | 17 | ||
18 | After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest | ||
19 | folder with a file named 'run' nodes will be created. 'run' controls run and | ||
20 | stop phases of the test. | ||
21 | |||
22 | Note that in this case test will not run on load automatically. | ||
23 | |||
24 | Example of usage: | 18 | Example of usage: |
19 | % modprobe dmatest channel=dma0chan0 timeout=2000 iterations=1 run=1 | ||
20 | |||
21 | ...or: | ||
22 | % modprobe dmatest | ||
25 | % echo dma0chan0 > /sys/module/dmatest/parameters/channel | 23 | % echo dma0chan0 > /sys/module/dmatest/parameters/channel |
26 | % echo 2000 > /sys/module/dmatest/parameters/timeout | 24 | % echo 2000 > /sys/module/dmatest/parameters/timeout |
27 | % echo 1 > /sys/module/dmatest/parameters/iterations | 25 | % echo 1 > /sys/module/dmatest/parameters/iterations |
28 | % echo 1 > /sys/kernel/debug/dmatest/run | 26 | % echo 1 > /sys/module/dmatest/parameters/run |
27 | |||
28 | ...or on the kernel command line: | ||
29 | |||
30 | dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1 | ||
29 | 31 | ||
30 | Hint: available channel list could be extracted by running the following | 32 | Hint: available channel list could be extracted by running the following |
31 | command: | 33 | command: |
@@ -42,7 +44,7 @@ The following command should return actual state of the test. | |||
42 | 44 | ||
43 | To wait for test done the user may perform a busy loop that checks the state. | 45 | To wait for test done the user may perform a busy loop that checks the state. |
44 | 46 | ||
45 | % while [ $(cat /sys/kernel/debug/dmatest/run) = "Y" ] | 47 | % while [ $(cat /sys/module/dmatest/parameters/run) = "Y" ] |
46 | > do | 48 | > do |
47 | > echo -n "." | 49 | > echo -n "." |
48 | > sleep 1 | 50 | > sleep 1 |
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 15199edcc366..c5048671daf7 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c | |||
@@ -21,10 +21,6 @@ | |||
21 | #include <linux/random.h> | 21 | #include <linux/random.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
24 | #include <linux/ctype.h> | ||
25 | #include <linux/debugfs.h> | ||
26 | #include <linux/uaccess.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | 24 | ||
29 | static unsigned int test_buf_size = 16384; | 25 | static unsigned int test_buf_size = 16384; |
30 | module_param(test_buf_size, uint, S_IRUGO | S_IWUSR); | 26 | module_param(test_buf_size, uint, S_IRUGO | S_IWUSR); |
@@ -70,45 +66,6 @@ module_param(timeout, uint, S_IRUGO | S_IWUSR); | |||
70 | MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " | 66 | MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " |
71 | "Pass -1 for infinite timeout"); | 67 | "Pass -1 for infinite timeout"); |
72 | 68 | ||
73 | /* Maximum amount of mismatched bytes in buffer to print */ | ||
74 | #define MAX_ERROR_COUNT 32 | ||
75 | |||
76 | /* | ||
77 | * Initialization patterns. All bytes in the source buffer has bit 7 | ||
78 | * set, all bytes in the destination buffer has bit 7 cleared. | ||
79 | * | ||
80 | * Bit 6 is set for all bytes which are to be copied by the DMA | ||
81 | * engine. Bit 5 is set for all bytes which are to be overwritten by | ||
82 | * the DMA engine. | ||
83 | * | ||
84 | * The remaining bits are the inverse of a counter which increments by | ||
85 | * one for each byte address. | ||
86 | */ | ||
87 | #define PATTERN_SRC 0x80 | ||
88 | #define PATTERN_DST 0x00 | ||
89 | #define PATTERN_COPY 0x40 | ||
90 | #define PATTERN_OVERWRITE 0x20 | ||
91 | #define PATTERN_COUNT_MASK 0x1f | ||
92 | |||
93 | struct dmatest_info; | ||
94 | |||
95 | struct dmatest_thread { | ||
96 | struct list_head node; | ||
97 | struct dmatest_info *info; | ||
98 | struct task_struct *task; | ||
99 | struct dma_chan *chan; | ||
100 | u8 **srcs; | ||
101 | u8 **dsts; | ||
102 | enum dma_transaction_type type; | ||
103 | bool done; | ||
104 | }; | ||
105 | |||
106 | struct dmatest_chan { | ||
107 | struct list_head node; | ||
108 | struct dma_chan *chan; | ||
109 | struct list_head threads; | ||
110 | }; | ||
111 | |||
112 | /** | 69 | /** |
113 | * struct dmatest_params - test parameters. | 70 | * struct dmatest_params - test parameters. |
114 | * @buf_size: size of the memcpy test buffer | 71 | * @buf_size: size of the memcpy test buffer |
@@ -138,7 +95,7 @@ struct dmatest_params { | |||
138 | * @params: test parameters | 95 | * @params: test parameters |
139 | * @lock: access protection to the fields of this structure | 96 | * @lock: access protection to the fields of this structure |
140 | */ | 97 | */ |
141 | struct dmatest_info { | 98 | static struct dmatest_info { |
142 | /* Test parameters */ | 99 | /* Test parameters */ |
143 | struct dmatest_params params; | 100 | struct dmatest_params params; |
144 | 101 | ||
@@ -146,12 +103,58 @@ struct dmatest_info { | |||
146 | struct list_head channels; | 103 | struct list_head channels; |
147 | unsigned int nr_channels; | 104 | unsigned int nr_channels; |
148 | struct mutex lock; | 105 | struct mutex lock; |
106 | bool did_init; | ||
107 | } test_info = { | ||
108 | .channels = LIST_HEAD_INIT(test_info.channels), | ||
109 | .lock = __MUTEX_INITIALIZER(test_info.lock), | ||
110 | }; | ||
149 | 111 | ||
150 | /* debugfs related stuff */ | 112 | static int dmatest_run_set(const char *val, const struct kernel_param *kp); |
151 | struct dentry *root; | 113 | static int dmatest_run_get(char *val, const struct kernel_param *kp); |
114 | static struct kernel_param_ops run_ops = { | ||
115 | .set = dmatest_run_set, | ||
116 | .get = dmatest_run_get, | ||
152 | }; | 117 | }; |
118 | static bool dmatest_run; | ||
119 | module_param_cb(run, &run_ops, &dmatest_run, S_IRUGO | S_IWUSR); | ||
120 | MODULE_PARM_DESC(run, "Run the test (default: false)"); | ||
153 | 121 | ||
154 | static struct dmatest_info test_info; | 122 | /* Maximum amount of mismatched bytes in buffer to print */ |
123 | #define MAX_ERROR_COUNT 32 | ||
124 | |||
125 | /* | ||
126 | * Initialization patterns. All bytes in the source buffer has bit 7 | ||
127 | * set, all bytes in the destination buffer has bit 7 cleared. | ||
128 | * | ||
129 | * Bit 6 is set for all bytes which are to be copied by the DMA | ||
130 | * engine. Bit 5 is set for all bytes which are to be overwritten by | ||
131 | * the DMA engine. | ||
132 | * | ||
133 | * The remaining bits are the inverse of a counter which increments by | ||
134 | * one for each byte address. | ||
135 | */ | ||
136 | #define PATTERN_SRC 0x80 | ||
137 | #define PATTERN_DST 0x00 | ||
138 | #define PATTERN_COPY 0x40 | ||
139 | #define PATTERN_OVERWRITE 0x20 | ||
140 | #define PATTERN_COUNT_MASK 0x1f | ||
141 | |||
142 | struct dmatest_thread { | ||
143 | struct list_head node; | ||
144 | struct dmatest_info *info; | ||
145 | struct task_struct *task; | ||
146 | struct dma_chan *chan; | ||
147 | u8 **srcs; | ||
148 | u8 **dsts; | ||
149 | enum dma_transaction_type type; | ||
150 | bool done; | ||
151 | }; | ||
152 | |||
153 | struct dmatest_chan { | ||
154 | struct list_head node; | ||
155 | struct dma_chan *chan; | ||
156 | struct list_head threads; | ||
157 | }; | ||
155 | 158 | ||
156 | static bool dmatest_match_channel(struct dmatest_params *params, | 159 | static bool dmatest_match_channel(struct dmatest_params *params, |
157 | struct dma_chan *chan) | 160 | struct dma_chan *chan) |
@@ -731,13 +734,24 @@ static bool filter(struct dma_chan *chan, void *param) | |||
731 | return true; | 734 | return true; |
732 | } | 735 | } |
733 | 736 | ||
734 | static int __run_threaded_test(struct dmatest_info *info) | 737 | static int run_threaded_test(struct dmatest_info *info) |
735 | { | 738 | { |
736 | dma_cap_mask_t mask; | 739 | dma_cap_mask_t mask; |
737 | struct dma_chan *chan; | 740 | struct dma_chan *chan; |
738 | struct dmatest_params *params = &info->params; | 741 | struct dmatest_params *params = &info->params; |
739 | int err = 0; | 742 | int err = 0; |
740 | 743 | ||
744 | /* Copy test parameters */ | ||
745 | params->buf_size = test_buf_size; | ||
746 | strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); | ||
747 | strlcpy(params->device, strim(test_device), sizeof(params->device)); | ||
748 | params->threads_per_chan = threads_per_chan; | ||
749 | params->max_channels = max_channels; | ||
750 | params->iterations = iterations; | ||
751 | params->xor_sources = xor_sources; | ||
752 | params->pq_sources = pq_sources; | ||
753 | params->timeout = timeout; | ||
754 | |||
741 | dma_cap_zero(mask); | 755 | dma_cap_zero(mask); |
742 | dma_cap_set(DMA_MEMCPY, mask); | 756 | dma_cap_set(DMA_MEMCPY, mask); |
743 | for (;;) { | 757 | for (;;) { |
@@ -757,19 +771,8 @@ static int __run_threaded_test(struct dmatest_info *info) | |||
757 | return err; | 771 | return err; |
758 | } | 772 | } |
759 | 773 | ||
760 | #ifndef MODULE | ||
761 | static int run_threaded_test(struct dmatest_info *info) | ||
762 | { | ||
763 | int ret; | ||
764 | |||
765 | mutex_lock(&info->lock); | ||
766 | ret = __run_threaded_test(info); | ||
767 | mutex_unlock(&info->lock); | ||
768 | return ret; | ||
769 | } | ||
770 | #endif | ||
771 | 774 | ||
772 | static void __stop_threaded_test(struct dmatest_info *info) | 775 | static void stop_threaded_test(struct dmatest_info *info) |
773 | { | 776 | { |
774 | struct dmatest_chan *dtc, *_dtc; | 777 | struct dmatest_chan *dtc, *_dtc; |
775 | struct dma_chan *chan; | 778 | struct dma_chan *chan; |
@@ -785,39 +788,22 @@ static void __stop_threaded_test(struct dmatest_info *info) | |||
785 | info->nr_channels = 0; | 788 | info->nr_channels = 0; |
786 | } | 789 | } |
787 | 790 | ||
788 | static void stop_threaded_test(struct dmatest_info *info) | 791 | static int restart_threaded_test(struct dmatest_info *info, bool run) |
789 | { | ||
790 | mutex_lock(&info->lock); | ||
791 | __stop_threaded_test(info); | ||
792 | mutex_unlock(&info->lock); | ||
793 | } | ||
794 | |||
795 | static int __restart_threaded_test(struct dmatest_info *info, bool run) | ||
796 | { | 792 | { |
797 | struct dmatest_params *params = &info->params; | 793 | /* we might be called early to set run=, defer running until all |
798 | 794 | * parameters have been evaluated | |
799 | /* Stop any running test first */ | 795 | */ |
800 | __stop_threaded_test(info); | 796 | if (!info->did_init) |
801 | |||
802 | if (run == false) | ||
803 | return 0; | 797 | return 0; |
804 | 798 | ||
805 | /* Copy test parameters */ | 799 | /* Stop any running test first */ |
806 | params->buf_size = test_buf_size; | 800 | stop_threaded_test(info); |
807 | strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); | ||
808 | strlcpy(params->device, strim(test_device), sizeof(params->device)); | ||
809 | params->threads_per_chan = threads_per_chan; | ||
810 | params->max_channels = max_channels; | ||
811 | params->iterations = iterations; | ||
812 | params->xor_sources = xor_sources; | ||
813 | params->pq_sources = pq_sources; | ||
814 | params->timeout = timeout; | ||
815 | 801 | ||
816 | /* Run test with new parameters */ | 802 | /* Run test with new parameters */ |
817 | return __run_threaded_test(info); | 803 | return run_threaded_test(info); |
818 | } | 804 | } |
819 | 805 | ||
820 | static bool __is_threaded_test_run(struct dmatest_info *info) | 806 | static bool is_threaded_test_run(struct dmatest_info *info) |
821 | { | 807 | { |
822 | struct dmatest_chan *dtc; | 808 | struct dmatest_chan *dtc; |
823 | 809 | ||
@@ -833,101 +819,61 @@ static bool __is_threaded_test_run(struct dmatest_info *info) | |||
833 | return false; | 819 | return false; |
834 | } | 820 | } |
835 | 821 | ||
836 | static ssize_t dtf_read_run(struct file *file, char __user *user_buf, | 822 | static int dmatest_run_get(char *val, const struct kernel_param *kp) |
837 | size_t count, loff_t *ppos) | ||
838 | { | 823 | { |
839 | struct dmatest_info *info = file->private_data; | 824 | struct dmatest_info *info = &test_info; |
840 | char buf[3]; | ||
841 | 825 | ||
842 | mutex_lock(&info->lock); | 826 | mutex_lock(&info->lock); |
843 | 827 | if (is_threaded_test_run(info)) { | |
844 | if (__is_threaded_test_run(info)) { | 828 | dmatest_run = true; |
845 | buf[0] = 'Y'; | ||
846 | } else { | 829 | } else { |
847 | __stop_threaded_test(info); | 830 | stop_threaded_test(info); |
848 | buf[0] = 'N'; | 831 | dmatest_run = false; |
849 | } | 832 | } |
850 | |||
851 | mutex_unlock(&info->lock); | 833 | mutex_unlock(&info->lock); |
852 | buf[1] = '\n'; | 834 | |
853 | buf[2] = 0x00; | 835 | return param_get_bool(val, kp); |
854 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | ||
855 | } | 836 | } |
856 | 837 | ||
857 | static ssize_t dtf_write_run(struct file *file, const char __user *user_buf, | 838 | static int dmatest_run_set(const char *val, const struct kernel_param *kp) |
858 | size_t count, loff_t *ppos) | ||
859 | { | 839 | { |
860 | struct dmatest_info *info = file->private_data; | 840 | struct dmatest_info *info = &test_info; |
861 | char buf[16]; | 841 | int ret; |
862 | bool bv; | ||
863 | int ret = 0; | ||
864 | |||
865 | if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) | ||
866 | return -EFAULT; | ||
867 | |||
868 | if (strtobool(buf, &bv) == 0) { | ||
869 | mutex_lock(&info->lock); | ||
870 | |||
871 | if (__is_threaded_test_run(info)) | ||
872 | ret = -EBUSY; | ||
873 | else | ||
874 | ret = __restart_threaded_test(info, bv); | ||
875 | 842 | ||
843 | mutex_lock(&info->lock); | ||
844 | ret = param_set_bool(val, kp); | ||
845 | if (ret) { | ||
876 | mutex_unlock(&info->lock); | 846 | mutex_unlock(&info->lock); |
847 | return ret; | ||
877 | } | 848 | } |
878 | 849 | ||
879 | return ret ? ret : count; | 850 | if (is_threaded_test_run(info)) |
880 | } | 851 | ret = -EBUSY; |
881 | 852 | else if (dmatest_run) | |
882 | static const struct file_operations dtf_run_fops = { | 853 | ret = restart_threaded_test(info, dmatest_run); |
883 | .read = dtf_read_run, | ||
884 | .write = dtf_write_run, | ||
885 | .open = simple_open, | ||
886 | .llseek = default_llseek, | ||
887 | }; | ||
888 | |||
889 | static int dmatest_register_dbgfs(struct dmatest_info *info) | ||
890 | { | ||
891 | struct dentry *d; | ||
892 | |||
893 | d = debugfs_create_dir("dmatest", NULL); | ||
894 | if (IS_ERR(d)) | ||
895 | return PTR_ERR(d); | ||
896 | if (!d) | ||
897 | goto err_root; | ||
898 | 854 | ||
899 | info->root = d; | 855 | mutex_unlock(&info->lock); |
900 | |||
901 | /* Run or stop threaded test */ | ||
902 | debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info, | ||
903 | &dtf_run_fops); | ||
904 | |||
905 | return 0; | ||
906 | 856 | ||
907 | err_root: | 857 | return ret; |
908 | pr_err("Failed to initialize debugfs\n"); | ||
909 | return -ENOMEM; | ||
910 | } | 858 | } |
911 | 859 | ||
912 | static int __init dmatest_init(void) | 860 | static int __init dmatest_init(void) |
913 | { | 861 | { |
914 | struct dmatest_info *info = &test_info; | 862 | struct dmatest_info *info = &test_info; |
915 | int ret; | 863 | int ret = 0; |
916 | |||
917 | memset(info, 0, sizeof(*info)); | ||
918 | 864 | ||
919 | mutex_init(&info->lock); | 865 | if (dmatest_run) { |
920 | INIT_LIST_HEAD(&info->channels); | 866 | mutex_lock(&info->lock); |
867 | ret = run_threaded_test(info); | ||
868 | mutex_unlock(&info->lock); | ||
869 | } | ||
921 | 870 | ||
922 | ret = dmatest_register_dbgfs(info); | 871 | /* module parameters are stable, inittime tests are started, |
923 | if (ret) | 872 | * let userspace take over 'run' control |
924 | return ret; | 873 | */ |
874 | info->did_init = true; | ||
925 | 875 | ||
926 | #ifdef MODULE | 876 | return ret; |
927 | return 0; | ||
928 | #else | ||
929 | return run_threaded_test(info); | ||
930 | #endif | ||
931 | } | 877 | } |
932 | /* when compiled-in wait for drivers to load first */ | 878 | /* when compiled-in wait for drivers to load first */ |
933 | late_initcall(dmatest_init); | 879 | late_initcall(dmatest_init); |
@@ -936,8 +882,9 @@ static void __exit dmatest_exit(void) | |||
936 | { | 882 | { |
937 | struct dmatest_info *info = &test_info; | 883 | struct dmatest_info *info = &test_info; |
938 | 884 | ||
939 | debugfs_remove_recursive(info->root); | 885 | mutex_lock(&info->lock); |
940 | stop_threaded_test(info); | 886 | stop_threaded_test(info); |
887 | mutex_unlock(&info->lock); | ||
941 | } | 888 | } |
942 | module_exit(dmatest_exit); | 889 | module_exit(dmatest_exit); |
943 | 890 | ||