Skip to content

Commit 851b7e1

Browse files
andy-shevVinod Koul
authored andcommitted
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>
1 parent 15b8a8e commit 851b7e1

2 files changed

Lines changed: 303 additions & 2 deletions

File tree

Documentation/dmatest.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
DMA Test Guide
2+
==============
3+
4+
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
5+
6+
This small document introduces how to test DMA drivers using dmatest module.
7+
8+
Part 1 - How to build the test module
9+
10+
The menuconfig contains an option that could be found by following path:
11+
Device Drivers -> DMA Engine support -> DMA Test client
12+
13+
In the configuration file the option called CONFIG_DMATEST. The dmatest could
14+
be built as module or inside kernel. Let's consider those cases.
15+
16+
Part 2 - When dmatest is built as a module...
17+
18+
After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest
19+
folder with nodes will be created. They are the same as module parameters with
20+
addition of the 'run' node that controls run and stop phases of the test.
21+
22+
Note that in this case test will not run on load automatically.
23+
24+
Example of usage:
25+
% echo dma0chan0 > /sys/kernel/debug/dmatest/channel
26+
% echo 2000 > /sys/kernel/debug/dmatest/timeout
27+
% echo 1 > /sys/kernel/debug/dmatest/iterations
28+
% echo 1 > /sys/kernel/debug/dmatest/run
29+
30+
Hint: available channel list could be extracted by running the following
31+
command:
32+
% ls -1 /sys/class/dma/
33+
34+
After a while you will start to get messages about current status or error like
35+
in the original code.
36+
37+
Note that running a new test will stop any in progress test.
38+
39+
Part 3 - When built-in in the kernel...
40+
41+
The module parameters that is supplied to the kernel command line will be used
42+
for the first performed test. After user gets a control, the test could be
43+
interrupted or re-run with same or different parameters. For the details see
44+
the above section "Part 2 - When dmatest is built as a module..."
45+
46+
In both cases the module parameters are used as initial values for the test case.
47+
You always could check them at run-time by running
48+
% grep -H . /sys/module/dmatest/parameters/*

drivers/dma/dmatest.c

Lines changed: 255 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* DMA Engine test module
33
*
44
* Copyright (C) 2007 Atmel Corporation
5+
* Copyright (C) 2013 Intel Corporation
56
*
67
* This program is free software; you can redistribute it and/or modify
78
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +19,10 @@
1819
#include <linux/random.h>
1920
#include <linux/slab.h>
2021
#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>
2126

2227
static unsigned int test_buf_size = 16384;
2328
module_param(test_buf_size, uint, S_IRUGO);
@@ -123,6 +128,7 @@ struct dmatest_params {
123128
/**
124129
* struct dmatest_info - test information.
125130
* @params: test parameters
131+
* @lock: access protection to the fields of this structure
126132
*/
127133
struct dmatest_info {
128134
/* Test parameters */
@@ -131,6 +137,11 @@ struct dmatest_info {
131137
/* Internal state */
132138
struct list_head channels;
133139
unsigned int nr_channels;
140+
struct mutex lock;
141+
142+
/* debugfs related stuff */
143+
struct dentry *root;
144+
struct dmatest_params dbgfs_params;
134145
};
135146

136147
static struct dmatest_info test_info;
@@ -718,7 +729,7 @@ static bool filter(struct dma_chan *chan, void *param)
718729
return true;
719730
}
720731

721-
static int run_threaded_test(struct dmatest_info *info)
732+
static int __run_threaded_test(struct dmatest_info *info)
722733
{
723734
dma_cap_mask_t mask;
724735
struct dma_chan *chan;
@@ -744,7 +755,19 @@ static int run_threaded_test(struct dmatest_info *info)
744755
return err;
745756
}
746757

747-
static void stop_threaded_test(struct dmatest_info *info)
758+
#ifndef MODULE
759+
static 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+
770+
static void __stop_threaded_test(struct dmatest_info *info)
748771
{
749772
struct dmatest_chan *dtc, *_dtc;
750773
struct dma_chan *chan;
@@ -760,13 +783,234 @@ static void stop_threaded_test(struct dmatest_info *info)
760783
info->nr_channels = 0;
761784
}
762785

786+
static 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+
793+
static 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+
817+
static 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+
832+
static 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+
841+
static 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+
850+
static 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+
857+
static 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+
866+
static 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+
875+
static 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+
882+
static 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+
899+
static 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+
919+
static 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+
926+
static 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+
998+
err_node:
999+
debugfs_remove_recursive(info->root);
1000+
err_root:
1001+
pr_err("dmatest: Failed to initialize debugfs\n");
1002+
return ret;
1003+
}
1004+
7631005
static int __init dmatest_init(void)
7641006
{
7651007
struct dmatest_info *info = &test_info;
7661008
struct dmatest_params *params = &info->params;
1009+
int ret;
7671010

7681011
memset(info, 0, sizeof(*info));
7691012

1013+
mutex_init(&info->lock);
7701014
INIT_LIST_HEAD(&info->channels);
7711015

7721016
/* Set default parameters */
@@ -780,7 +1024,15 @@ static int __init dmatest_init(void)
7801024
params->pq_sources = pq_sources;
7811025
params->timeout = timeout;
7821026

1027+
ret = dmatest_register_dbgfs(info);
1028+
if (ret)
1029+
return ret;
1030+
1031+
#ifdef MODULE
1032+
return 0;
1033+
#else
7831034
return run_threaded_test(info);
1035+
#endif
7841036
}
7851037
/* when compiled-in wait for drivers to load first */
7861038
late_initcall(dmatest_init);
@@ -789,6 +1041,7 @@ static void __exit dmatest_exit(void)
7891041
{
7901042
struct dmatest_info *info = &test_info;
7911043

1044+
debugfs_remove_recursive(info->root);
7921045
stop_threaded_test(info);
7931046
}
7941047
module_exit(dmatest_exit);

0 commit comments

Comments
 (0)