aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2013-03-04 04:09:30 -0500
committerVinod Koul <vinod.koul@intel.com>2013-04-15 00:21:17 -0400
commit851b7e16a07dfda6178d4e35fea9a9e3eb8954ae (patch)
tree7970966aa65fd72062a8944591c81993b1b7b932 /drivers/dma
parent15b8a8ea1a87313f1b46ea878c65942fd52147ed (diff)
dmatest: run test via debugfs
Instead of doing modprobe dmatest ... modprobe -r dmatest we allow user to run tests interactively. The dmatest could be built as module or inside kernel. Let's consider those cases. 1. When dmatest is built as a module... After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest folder with nodes will be created. They are the same as module parameters with addition of the 'run' node that controls run and stop phases of the test. Note that in this case test will not run on load automatically. Example of usage: % echo dma0chan0 > /sys/kernel/debug/dmatest/channel % echo 2000 > /sys/kernel/debug/dmatest/timeout % echo 1 > /sys/kernel/debug/dmatest/iterations % echo 1 > /sys/kernel/debug/dmatest/run After a while you will start to get messages about current status or error like in the original code. Note that running a new test will stop any in progress test. 2. When built-in in the kernel... The module parameters that is supplied to the kernel command line will be used for the first performed test. After user gets a control, the test could be interrupted or re-run with same or different parameters. For the details see the above section "1. When dmatest is built as a module..." In both cases the module parameters are used as initial values for the test case. You always could check them at run-time by running % grep -H . /sys/module/dmatest/parameters/* Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/dmatest.c257
1 files changed, 255 insertions, 2 deletions
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index c6e5d8331c66..fc31542e7200 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -2,6 +2,7 @@
2 * DMA Engine test module 2 * DMA Engine test module
3 * 3 *
4 * Copyright (C) 2007 Atmel Corporation 4 * Copyright (C) 2007 Atmel Corporation
5 * Copyright (C) 2013 Intel Corporation
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +19,10 @@
18#include <linux/random.h> 19#include <linux/random.h>
19#include <linux/slab.h> 20#include <linux/slab.h>
20#include <linux/wait.h> 21#include <linux/wait.h>
22#include <linux/ctype.h>
23#include <linux/debugfs.h>
24#include <linux/uaccess.h>
25#include <linux/seq_file.h>
21 26
22static unsigned int test_buf_size = 16384; 27static unsigned int test_buf_size = 16384;
23module_param(test_buf_size, uint, S_IRUGO); 28module_param(test_buf_size, uint, S_IRUGO);
@@ -123,6 +128,7 @@ struct dmatest_params {
123/** 128/**
124 * struct dmatest_info - test information. 129 * struct dmatest_info - test information.
125 * @params: test parameters 130 * @params: test parameters
131 * @lock: access protection to the fields of this structure
126 */ 132 */
127struct dmatest_info { 133struct dmatest_info {
128 /* Test parameters */ 134 /* Test parameters */
@@ -131,6 +137,11 @@ struct dmatest_info {
131 /* Internal state */ 137 /* Internal state */
132 struct list_head channels; 138 struct list_head channels;
133 unsigned int nr_channels; 139 unsigned int nr_channels;
140 struct mutex lock;
141
142 /* debugfs related stuff */
143 struct dentry *root;
144 struct dmatest_params dbgfs_params;
134}; 145};
135 146
136static struct dmatest_info test_info; 147static struct dmatest_info test_info;
@@ -718,7 +729,7 @@ static bool filter(struct dma_chan *chan, void *param)
718 return true; 729 return true;
719} 730}
720 731
721static int run_threaded_test(struct dmatest_info *info) 732static int __run_threaded_test(struct dmatest_info *info)
722{ 733{
723 dma_cap_mask_t mask; 734 dma_cap_mask_t mask;
724 struct dma_chan *chan; 735 struct dma_chan *chan;
@@ -744,7 +755,19 @@ static int run_threaded_test(struct dmatest_info *info)
744 return err; 755 return err;
745} 756}
746 757
747static void stop_threaded_test(struct dmatest_info *info) 758#ifndef MODULE
759static int run_threaded_test(struct dmatest_info *info)
760{
761 int ret;
762
763 mutex_lock(&info->lock);
764 ret = __run_threaded_test(info);
765 mutex_unlock(&info->lock);
766 return ret;
767}
768#endif
769
770static void __stop_threaded_test(struct dmatest_info *info)
748{ 771{
749 struct dmatest_chan *dtc, *_dtc; 772 struct dmatest_chan *dtc, *_dtc;
750 struct dma_chan *chan; 773 struct dma_chan *chan;
@@ -760,13 +783,234 @@ static void stop_threaded_test(struct dmatest_info *info)
760 info->nr_channels = 0; 783 info->nr_channels = 0;
761} 784}
762 785
786static void stop_threaded_test(struct dmatest_info *info)
787{
788 mutex_lock(&info->lock);
789 __stop_threaded_test(info);
790 mutex_unlock(&info->lock);
791}
792
793static int __restart_threaded_test(struct dmatest_info *info, bool run)
794{
795 struct dmatest_params *params = &info->params;
796 int ret;
797
798 /* Stop any running test first */
799 __stop_threaded_test(info);
800
801 if (run == false)
802 return 0;
803
804 /* Copy test parameters */
805 memcpy(params, &info->dbgfs_params, sizeof(*params));
806
807 /* Run test with new parameters */
808 ret = __run_threaded_test(info);
809 if (ret) {
810 __stop_threaded_test(info);
811 pr_err("dmatest: Can't run test\n");
812 }
813
814 return ret;
815}
816
817static ssize_t dtf_write_string(void *to, size_t available, loff_t *ppos,
818 const void __user *from, size_t count)
819{
820 char tmp[20];
821 ssize_t len;
822
823 len = simple_write_to_buffer(tmp, sizeof(tmp) - 1, ppos, from, count);
824 if (len >= 0) {
825 tmp[len] = '\0';
826 strlcpy(to, strim(tmp), available);
827 }
828
829 return len;
830}
831
832static ssize_t dtf_read_channel(struct file *file, char __user *buf,
833 size_t count, loff_t *ppos)
834{
835 struct dmatest_info *info = file->private_data;
836 return simple_read_from_buffer(buf, count, ppos,
837 info->dbgfs_params.channel,
838 strlen(info->dbgfs_params.channel));
839}
840
841static ssize_t dtf_write_channel(struct file *file, const char __user *buf,
842 size_t size, loff_t *ppos)
843{
844 struct dmatest_info *info = file->private_data;
845 return dtf_write_string(info->dbgfs_params.channel,
846 sizeof(info->dbgfs_params.channel),
847 ppos, buf, size);
848}
849
850static const struct file_operations dtf_channel_fops = {
851 .read = dtf_read_channel,
852 .write = dtf_write_channel,
853 .open = simple_open,
854 .llseek = default_llseek,
855};
856
857static ssize_t dtf_read_device(struct file *file, char __user *buf,
858 size_t count, loff_t *ppos)
859{
860 struct dmatest_info *info = file->private_data;
861 return simple_read_from_buffer(buf, count, ppos,
862 info->dbgfs_params.device,
863 strlen(info->dbgfs_params.device));
864}
865
866static ssize_t dtf_write_device(struct file *file, const char __user *buf,
867 size_t size, loff_t *ppos)
868{
869 struct dmatest_info *info = file->private_data;
870 return dtf_write_string(info->dbgfs_params.device,
871 sizeof(info->dbgfs_params.device),
872 ppos, buf, size);
873}
874
875static const struct file_operations dtf_device_fops = {
876 .read = dtf_read_device,
877 .write = dtf_write_device,
878 .open = simple_open,
879 .llseek = default_llseek,
880};
881
882static ssize_t dtf_read_run(struct file *file, char __user *user_buf,
883 size_t count, loff_t *ppos)
884{
885 struct dmatest_info *info = file->private_data;
886 char buf[3];
887
888 mutex_lock(&info->lock);
889 if (info->nr_channels)
890 buf[0] = 'Y';
891 else
892 buf[0] = 'N';
893 mutex_unlock(&info->lock);
894 buf[1] = '\n';
895 buf[2] = 0x00;
896 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
897}
898
899static ssize_t dtf_write_run(struct file *file, const char __user *user_buf,
900 size_t count, loff_t *ppos)
901{
902 struct dmatest_info *info = file->private_data;
903 char buf[16];
904 bool bv;
905 int ret = 0;
906
907 if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1))))
908 return -EFAULT;
909
910 if (strtobool(buf, &bv) == 0) {
911 mutex_lock(&info->lock);
912 ret = __restart_threaded_test(info, bv);
913 mutex_unlock(&info->lock);
914 }
915
916 return ret ? ret : count;
917}
918
919static const struct file_operations dtf_run_fops = {
920 .read = dtf_read_run,
921 .write = dtf_write_run,
922 .open = simple_open,
923 .llseek = default_llseek,
924};
925
926static int dmatest_register_dbgfs(struct dmatest_info *info)
927{
928 struct dentry *d;
929 struct dmatest_params *params = &info->dbgfs_params;
930 int ret = -ENOMEM;
931
932 d = debugfs_create_dir("dmatest", NULL);
933 if (IS_ERR(d))
934 return PTR_ERR(d);
935 if (!d)
936 goto err_root;
937
938 info->root = d;
939
940 /* Copy initial values */
941 memcpy(params, &info->params, sizeof(*params));
942
943 /* Test parameters */
944
945 d = debugfs_create_u32("test_buf_size", S_IWUSR | S_IRUGO, info->root,
946 (u32 *)&params->buf_size);
947 if (IS_ERR_OR_NULL(d))
948 goto err_node;
949
950 d = debugfs_create_file("channel", S_IRUGO | S_IWUSR, info->root,
951 info, &dtf_channel_fops);
952 if (IS_ERR_OR_NULL(d))
953 goto err_node;
954
955 d = debugfs_create_file("device", S_IRUGO | S_IWUSR, info->root,
956 info, &dtf_device_fops);
957 if (IS_ERR_OR_NULL(d))
958 goto err_node;
959
960 d = debugfs_create_u32("threads_per_chan", S_IWUSR | S_IRUGO, info->root,
961 (u32 *)&params->threads_per_chan);
962 if (IS_ERR_OR_NULL(d))
963 goto err_node;
964
965 d = debugfs_create_u32("max_channels", S_IWUSR | S_IRUGO, info->root,
966 (u32 *)&params->max_channels);
967 if (IS_ERR_OR_NULL(d))
968 goto err_node;
969
970 d = debugfs_create_u32("iterations", S_IWUSR | S_IRUGO, info->root,
971 (u32 *)&params->iterations);
972 if (IS_ERR_OR_NULL(d))
973 goto err_node;
974
975 d = debugfs_create_u32("xor_sources", S_IWUSR | S_IRUGO, info->root,
976 (u32 *)&params->xor_sources);
977 if (IS_ERR_OR_NULL(d))
978 goto err_node;
979
980 d = debugfs_create_u32("pq_sources", S_IWUSR | S_IRUGO, info->root,
981 (u32 *)&params->pq_sources);
982 if (IS_ERR_OR_NULL(d))
983 goto err_node;
984
985 d = debugfs_create_u32("timeout", S_IWUSR | S_IRUGO, info->root,
986 (u32 *)&params->timeout);
987 if (IS_ERR_OR_NULL(d))
988 goto err_node;
989
990 /* Run or stop threaded test */
991 d = debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root,
992 info, &dtf_run_fops);
993 if (IS_ERR_OR_NULL(d))
994 goto err_node;
995
996 return 0;
997
998err_node:
999 debugfs_remove_recursive(info->root);
1000err_root:
1001 pr_err("dmatest: Failed to initialize debugfs\n");
1002 return ret;
1003}
1004
763static int __init dmatest_init(void) 1005static int __init dmatest_init(void)
764{ 1006{
765 struct dmatest_info *info = &test_info; 1007 struct dmatest_info *info = &test_info;
766 struct dmatest_params *params = &info->params; 1008 struct dmatest_params *params = &info->params;
1009 int ret;
767 1010
768 memset(info, 0, sizeof(*info)); 1011 memset(info, 0, sizeof(*info));
769 1012
1013 mutex_init(&info->lock);
770 INIT_LIST_HEAD(&info->channels); 1014 INIT_LIST_HEAD(&info->channels);
771 1015
772 /* Set default parameters */ 1016 /* Set default parameters */
@@ -780,7 +1024,15 @@ static int __init dmatest_init(void)
780 params->pq_sources = pq_sources; 1024 params->pq_sources = pq_sources;
781 params->timeout = timeout; 1025 params->timeout = timeout;
782 1026
1027 ret = dmatest_register_dbgfs(info);
1028 if (ret)
1029 return ret;
1030
1031#ifdef MODULE
1032 return 0;
1033#else
783 return run_threaded_test(info); 1034 return run_threaded_test(info);
1035#endif
784} 1036}
785/* when compiled-in wait for drivers to load first */ 1037/* when compiled-in wait for drivers to load first */
786late_initcall(dmatest_init); 1038late_initcall(dmatest_init);
@@ -789,6 +1041,7 @@ static void __exit dmatest_exit(void)
789{ 1041{
790 struct dmatest_info *info = &test_info; 1042 struct dmatest_info *info = &test_info;
791 1043
1044 debugfs_remove_recursive(info->root);
792 stop_threaded_test(info); 1045 stop_threaded_test(info);
793} 1046}
794module_exit(dmatest_exit); 1047module_exit(dmatest_exit);