Skip to content

Commit 95019c8

Browse files
andy-shevVinod Koul
authored andcommitted
dmatest: gather test results in the linked list
The patch provides a storage for the test results in the linked list. The gathered data could be used after test is done. The new file 'results' represents gathered data of the in progress test. The messages collected are printed to the kernel log as well. Example of output: % cat /sys/kernel/debug/dmatest/results dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0) The message format is unified across the different types of errors. A number in the parens represents additional information, e.g. error code, error counter, or status. Note that the buffer comparison is done in the old way, i.e. data is not collected and just printed out. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
1 parent 74b5c07 commit 95019c8

File tree

2 files changed

+223
-30
lines changed

2 files changed

+223
-30
lines changed

Documentation/dmatest.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,22 @@ the above section "Part 2 - When dmatest is built as a module..."
5858
In both cases the module parameters are used as initial values for the test case.
5959
You always could check them at run-time by running
6060
% grep -H . /sys/module/dmatest/parameters/*
61+
62+
Part 4 - Gathering the test results
63+
64+
The module provides a storage for the test results in the memory. The gathered
65+
data could be used after test is done.
66+
67+
The special file 'results' in the debugfs represents gathered data of the in
68+
progress test. The messages collected are printed to the kernel log as well.
69+
70+
Example of output:
71+
% cat /sys/kernel/debug/dmatest/results
72+
dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0)
73+
74+
The message format is unified across the different types of errors. A number in
75+
the parens represents additional information, e.g. error code, error counter,
76+
or status.
77+
78+
Note that the buffer comparison is done in the old way, i.e. data is not
79+
collected and just printed out.

drivers/dma/dmatest.c

Lines changed: 204 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,39 @@ MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
8686
#define PATTERN_OVERWRITE 0x20
8787
#define PATTERN_COUNT_MASK 0x1f
8888

89+
enum dmatest_error_type {
90+
DMATEST_ET_OK,
91+
DMATEST_ET_MAP_SRC,
92+
DMATEST_ET_MAP_DST,
93+
DMATEST_ET_PREP,
94+
DMATEST_ET_SUBMIT,
95+
DMATEST_ET_TIMEOUT,
96+
DMATEST_ET_DMA_ERROR,
97+
DMATEST_ET_DMA_IN_PROGRESS,
98+
DMATEST_ET_VERIFY,
99+
};
100+
101+
struct dmatest_thread_result {
102+
struct list_head node;
103+
unsigned int n;
104+
unsigned int src_off;
105+
unsigned int dst_off;
106+
unsigned int len;
107+
enum dmatest_error_type type;
108+
union {
109+
unsigned long data;
110+
dma_cookie_t cookie;
111+
enum dma_status status;
112+
int error;
113+
};
114+
};
115+
116+
struct dmatest_result {
117+
struct list_head node;
118+
char *name;
119+
struct list_head results;
120+
};
121+
89122
struct dmatest_info;
90123

91124
struct dmatest_thread {
@@ -146,6 +179,10 @@ struct dmatest_info {
146179
/* debugfs related stuff */
147180
struct dentry *root;
148181
struct dmatest_params dbgfs_params;
182+
183+
/* Test results */
184+
struct list_head results;
185+
struct mutex results_lock;
149186
};
150187

151188
static struct dmatest_info test_info;
@@ -303,6 +340,98 @@ static unsigned int min_odd(unsigned int x, unsigned int y)
303340
return val % 2 ? val : val - 1;
304341
}
305342

343+
static char *thread_result_get(const char *name,
344+
struct dmatest_thread_result *tr)
345+
{
346+
static const char * const messages[] = {
347+
[DMATEST_ET_OK] = "No errors",
348+
[DMATEST_ET_MAP_SRC] = "src mapping error",
349+
[DMATEST_ET_MAP_DST] = "dst mapping error",
350+
[DMATEST_ET_PREP] = "prep error",
351+
[DMATEST_ET_SUBMIT] = "submit error",
352+
[DMATEST_ET_TIMEOUT] = "test timed out",
353+
[DMATEST_ET_DMA_ERROR] =
354+
"got completion callback (DMA_ERROR)",
355+
[DMATEST_ET_DMA_IN_PROGRESS] =
356+
"got completion callback (DMA_IN_PROGRESS)",
357+
[DMATEST_ET_VERIFY] = "errors",
358+
};
359+
static char buf[512];
360+
361+
snprintf(buf, sizeof(buf) - 1,
362+
"%s: #%u: %s with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)",
363+
name, tr->n, messages[tr->type], tr->src_off, tr->dst_off,
364+
tr->len, tr->data);
365+
366+
return buf;
367+
}
368+
369+
static int thread_result_add(struct dmatest_info *info,
370+
struct dmatest_result *r, enum dmatest_error_type type,
371+
unsigned int n, unsigned int src_off, unsigned int dst_off,
372+
unsigned int len, unsigned long data)
373+
{
374+
struct dmatest_thread_result *tr;
375+
376+
tr = kzalloc(sizeof(*tr), GFP_KERNEL);
377+
if (!tr)
378+
return -ENOMEM;
379+
380+
tr->type = type;
381+
tr->n = n;
382+
tr->src_off = src_off;
383+
tr->dst_off = dst_off;
384+
tr->len = len;
385+
tr->data = data;
386+
387+
mutex_lock(&info->results_lock);
388+
list_add_tail(&tr->node, &r->results);
389+
mutex_unlock(&info->results_lock);
390+
391+
pr_warn("%s\n", thread_result_get(r->name, tr));
392+
return 0;
393+
}
394+
395+
static void result_free(struct dmatest_info *info, const char *name)
396+
{
397+
struct dmatest_result *r, *_r;
398+
399+
mutex_lock(&info->results_lock);
400+
list_for_each_entry_safe(r, _r, &info->results, node) {
401+
struct dmatest_thread_result *tr, *_tr;
402+
403+
if (name && strcmp(r->name, name))
404+
continue;
405+
406+
list_for_each_entry_safe(tr, _tr, &r->results, node) {
407+
list_del(&tr->node);
408+
kfree(tr);
409+
}
410+
411+
kfree(r->name);
412+
list_del(&r->node);
413+
kfree(r);
414+
}
415+
416+
mutex_unlock(&info->results_lock);
417+
}
418+
419+
static struct dmatest_result *result_init(struct dmatest_info *info,
420+
const char *name)
421+
{
422+
struct dmatest_result *r;
423+
424+
r = kzalloc(sizeof(*r), GFP_KERNEL);
425+
if (r) {
426+
r->name = kstrdup(name, GFP_KERNEL);
427+
INIT_LIST_HEAD(&r->results);
428+
mutex_lock(&info->results_lock);
429+
list_add_tail(&r->node, &info->results);
430+
mutex_unlock(&info->results_lock);
431+
}
432+
return r;
433+
}
434+
306435
/*
307436
* This function repeatedly tests DMA transfers of various lengths and
308437
* offsets for a given operation type until it is told to exit by
@@ -339,6 +468,7 @@ static int dmatest_func(void *data)
339468
int src_cnt;
340469
int dst_cnt;
341470
int i;
471+
struct dmatest_result *result;
342472

343473
thread_name = current->comm;
344474
set_freezable();
@@ -370,6 +500,10 @@ static int dmatest_func(void *data)
370500
} else
371501
goto err_thread_type;
372502

503+
result = result_init(info, thread_name);
504+
if (!result)
505+
goto err_srcs;
506+
373507
thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL);
374508
if (!thread->srcs)
375509
goto err_srcs;
@@ -443,10 +577,10 @@ static int dmatest_func(void *data)
443577
ret = dma_mapping_error(dev->dev, dma_srcs[i]);
444578
if (ret) {
445579
unmap_src(dev->dev, dma_srcs, len, i);
446-
pr_warn("%s: #%u: mapping error %d with "
447-
"src_off=0x%x len=0x%x\n",
448-
thread_name, total_tests - 1, ret,
449-
src_off, len);
580+
thread_result_add(info, result,
581+
DMATEST_ET_MAP_SRC,
582+
total_tests, src_off, dst_off,
583+
len, ret);
450584
failed_tests++;
451585
continue;
452586
}
@@ -461,10 +595,10 @@ static int dmatest_func(void *data)
461595
unmap_src(dev->dev, dma_srcs, len, src_cnt);
462596
unmap_dst(dev->dev, dma_dsts, params->buf_size,
463597
i);
464-
pr_warn("%s: #%u: mapping error %d with "
465-
"dst_off=0x%x len=0x%x\n",
466-
thread_name, total_tests - 1, ret,
467-
dst_off, params->buf_size);
598+
thread_result_add(info, result,
599+
DMATEST_ET_MAP_DST,
600+
total_tests, src_off, dst_off,
601+
len, ret);
468602
failed_tests++;
469603
continue;
470604
}
@@ -494,10 +628,9 @@ static int dmatest_func(void *data)
494628
unmap_src(dev->dev, dma_srcs, len, src_cnt);
495629
unmap_dst(dev->dev, dma_dsts, params->buf_size,
496630
dst_cnt);
497-
pr_warning("%s: #%u: prep error with src_off=0x%x "
498-
"dst_off=0x%x len=0x%x\n",
499-
thread_name, total_tests - 1,
500-
src_off, dst_off, len);
631+
thread_result_add(info, result, DMATEST_ET_PREP,
632+
total_tests, src_off, dst_off,
633+
len, 0);
501634
msleep(100);
502635
failed_tests++;
503636
continue;
@@ -509,10 +642,9 @@ static int dmatest_func(void *data)
509642
cookie = tx->tx_submit(tx);
510643

511644
if (dma_submit_error(cookie)) {
512-
pr_warning("%s: #%u: submit error %d with src_off=0x%x "
513-
"dst_off=0x%x len=0x%x\n",
514-
thread_name, total_tests - 1, cookie,
515-
src_off, dst_off, len);
645+
thread_result_add(info, result, DMATEST_ET_SUBMIT,
646+
total_tests, src_off, dst_off,
647+
len, cookie);
516648
msleep(100);
517649
failed_tests++;
518650
continue;
@@ -534,15 +666,17 @@ static int dmatest_func(void *data)
534666
* free it this time?" dancing. For now, just
535667
* leave it dangling.
536668
*/
537-
pr_warning("%s: #%u: test timed out\n",
538-
thread_name, total_tests - 1);
669+
thread_result_add(info, result, DMATEST_ET_TIMEOUT,
670+
total_tests, src_off, dst_off,
671+
len, 0);
539672
failed_tests++;
540673
continue;
541674
} else if (status != DMA_SUCCESS) {
542-
pr_warning("%s: #%u: got completion callback,"
543-
" but status is \'%s\'\n",
544-
thread_name, total_tests - 1,
545-
status == DMA_ERROR ? "error" : "in progress");
675+
enum dmatest_error_type type = (status == DMA_ERROR) ?
676+
DMATEST_ET_DMA_ERROR : DMATEST_ET_DMA_IN_PROGRESS;
677+
thread_result_add(info, result, type,
678+
total_tests, src_off, dst_off,
679+
len, status);
546680
failed_tests++;
547681
continue;
548682
}
@@ -574,16 +708,14 @@ static int dmatest_func(void *data)
574708
PATTERN_DST, false);
575709

576710
if (error_count) {
577-
pr_warning("%s: #%u: %u errors with "
578-
"src_off=0x%x dst_off=0x%x len=0x%x\n",
579-
thread_name, total_tests - 1, error_count,
580-
src_off, dst_off, len);
711+
thread_result_add(info, result, DMATEST_ET_VERIFY,
712+
total_tests, src_off, dst_off,
713+
len, error_count);
581714
failed_tests++;
582715
} else {
583-
pr_debug("%s: #%u: No errors with "
584-
"src_off=0x%x dst_off=0x%x len=0x%x\n",
585-
thread_name, total_tests - 1,
586-
src_off, dst_off, len);
716+
thread_result_add(info, result, DMATEST_ET_OK,
717+
total_tests, src_off, dst_off,
718+
len, 0);
587719
}
588720
}
589721

@@ -807,6 +939,9 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run)
807939
if (run == false)
808940
return 0;
809941

942+
/* Clear results from previous run */
943+
result_free(info, NULL);
944+
810945
/* Copy test parameters */
811946
memcpy(params, &info->dbgfs_params, sizeof(*params));
812947

@@ -945,6 +1080,35 @@ static const struct file_operations dtf_run_fops = {
9451080
.llseek = default_llseek,
9461081
};
9471082

1083+
static int dtf_results_show(struct seq_file *sf, void *data)
1084+
{
1085+
struct dmatest_info *info = sf->private;
1086+
struct dmatest_result *result;
1087+
struct dmatest_thread_result *tr;
1088+
1089+
mutex_lock(&info->results_lock);
1090+
list_for_each_entry(result, &info->results, node) {
1091+
list_for_each_entry(tr, &result->results, node)
1092+
seq_printf(sf, "%s\n",
1093+
thread_result_get(result->name, tr));
1094+
}
1095+
1096+
mutex_unlock(&info->results_lock);
1097+
return 0;
1098+
}
1099+
1100+
static int dtf_results_open(struct inode *inode, struct file *file)
1101+
{
1102+
return single_open(file, dtf_results_show, inode->i_private);
1103+
}
1104+
1105+
static const struct file_operations dtf_results_fops = {
1106+
.open = dtf_results_open,
1107+
.read = seq_read,
1108+
.llseek = seq_lseek,
1109+
.release = single_release,
1110+
};
1111+
9481112
static int dmatest_register_dbgfs(struct dmatest_info *info)
9491113
{
9501114
struct dentry *d;
@@ -1015,6 +1179,12 @@ static int dmatest_register_dbgfs(struct dmatest_info *info)
10151179
if (IS_ERR_OR_NULL(d))
10161180
goto err_node;
10171181

1182+
/* Results of test in progress */
1183+
d = debugfs_create_file("results", S_IRUGO, info->root, info,
1184+
&dtf_results_fops);
1185+
if (IS_ERR_OR_NULL(d))
1186+
goto err_node;
1187+
10181188
return 0;
10191189

10201190
err_node:
@@ -1035,6 +1205,9 @@ static int __init dmatest_init(void)
10351205
mutex_init(&info->lock);
10361206
INIT_LIST_HEAD(&info->channels);
10371207

1208+
mutex_init(&info->results_lock);
1209+
INIT_LIST_HEAD(&info->results);
1210+
10381211
/* Set default parameters */
10391212
params->buf_size = test_buf_size;
10401213
strlcpy(params->channel, test_channel, sizeof(params->channel));
@@ -1065,6 +1238,7 @@ static void __exit dmatest_exit(void)
10651238

10661239
debugfs_remove_recursive(info->root);
10671240
stop_threaded_test(info);
1241+
result_free(info, NULL);
10681242
}
10691243
module_exit(dmatest_exit);
10701244

0 commit comments

Comments
 (0)