aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/dmatest.txt27
-rw-r--r--drivers/dma/dmatest.c240
2 files changed, 46 insertions, 221 deletions
diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt
index 8b7a5c879df9..45b8c95f1a21 100644
--- a/Documentation/dmatest.txt
+++ b/Documentation/dmatest.txt
@@ -16,9 +16,8 @@ be built as module or inside kernel. Let's consider those cases.
16 Part 2 - When dmatest is built as a module... 16 Part 2 - When dmatest is built as a module...
17 17
18After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest 18After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest
19folder with nodes will be created. There are two important files located. First 19folder with a file named 'run' nodes will be created. 'run' controls run and
20is the 'run' node that controls run and stop phases of the test, and the second 20stop phases of the test.
21one, 'results', is used to get the test case results.
22 21
23Note that in this case test will not run on load automatically. 22Note that in this case test will not run on load automatically.
24 23
@@ -32,8 +31,9 @@ Hint: available channel list could be extracted by running the following
32command: 31command:
33 % ls -1 /sys/class/dma/ 32 % ls -1 /sys/class/dma/
34 33
35After a while you will start to get messages about current status or error like 34Once started a message like "dmatest: Started 1 threads using dma0chan0" is
36in the original code. 35emitted. After that only test failure messages are reported until the test
36stops.
37 37
38Note that running a new test will not stop any in progress test. 38Note that running a new test will not stop any in progress test.
39 39
@@ -62,19 +62,18 @@ case. You always could check them at run-time by running
62 62
63 Part 4 - Gathering the test results 63 Part 4 - Gathering the test results
64 64
65The module provides a storage for the test results in the memory. The gathered 65Test results are printed to the kernel log buffer with the format:
66data could be used after test is done.
67 66
68The special file 'results' in the debugfs represents gathered data of the in 67"dmatest: result <channel>: <test id>: '<error msg>' with src_off=<val> dst_off=<val> len=<val> (<err code>)"
69progress test. The messages collected are printed to the kernel log as well.
70 68
71Example of output: 69Example of output:
72 % cat /sys/kernel/debug/dmatest/results 70 % dmesg | tail -n 1
73 dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0) 71 dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0)
74 72
75The message format is unified across the different types of errors. A number in 73The message format is unified across the different types of errors. A number in
76the parens represents additional information, e.g. error code, error counter, 74the parens represents additional information, e.g. error code, error counter,
77or status. 75or status. A test thread also emits a summary line at completion listing the
76number of tests executed, number that failed, and a result code.
78 77
79Note that the buffer comparison is done in the old way, i.e. data is not 78The details of a data miscompare error are also emitted, but do not follow the
80collected and just printed out. 79above format.
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index dcb38d86550e..58b195f9d03c 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -8,6 +8,8 @@
8 * 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
9 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
10 */ 10 */
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
11#include <linux/delay.h> 13#include <linux/delay.h>
12#include <linux/dma-mapping.h> 14#include <linux/dma-mapping.h>
13#include <linux/dmaengine.h> 15#include <linux/dmaengine.h>
@@ -88,39 +90,6 @@ MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
88#define PATTERN_OVERWRITE 0x20 90#define PATTERN_OVERWRITE 0x20
89#define PATTERN_COUNT_MASK 0x1f 91#define PATTERN_COUNT_MASK 0x1f
90 92
91enum dmatest_error_type {
92 DMATEST_ET_OK,
93 DMATEST_ET_MAP_SRC,
94 DMATEST_ET_MAP_DST,
95 DMATEST_ET_PREP,
96 DMATEST_ET_SUBMIT,
97 DMATEST_ET_TIMEOUT,
98 DMATEST_ET_DMA_ERROR,
99 DMATEST_ET_DMA_IN_PROGRESS,
100 DMATEST_ET_VERIFY,
101};
102
103struct dmatest_thread_result {
104 struct list_head node;
105 unsigned int n;
106 unsigned int src_off;
107 unsigned int dst_off;
108 unsigned int len;
109 enum dmatest_error_type type;
110 union {
111 unsigned long data;
112 dma_cookie_t cookie;
113 enum dma_status status;
114 int error;
115 };
116};
117
118struct dmatest_result {
119 struct list_head node;
120 char *name;
121 struct list_head results;
122};
123
124struct dmatest_info; 93struct dmatest_info;
125 94
126struct dmatest_thread { 95struct dmatest_thread {
@@ -180,10 +149,6 @@ struct dmatest_info {
180 149
181 /* debugfs related stuff */ 150 /* debugfs related stuff */
182 struct dentry *root; 151 struct dentry *root;
183
184 /* Test results */
185 struct list_head results;
186 struct mutex results_lock;
187}; 152};
188 153
189static struct dmatest_info test_info; 154static struct dmatest_info test_info;
@@ -337,100 +302,19 @@ static unsigned int min_odd(unsigned int x, unsigned int y)
337 return val % 2 ? val : val - 1; 302 return val % 2 ? val : val - 1;
338} 303}
339 304
340static char *thread_result_get(const char *name, 305static void result(const char *err, unsigned int n, unsigned int src_off,
341 struct dmatest_thread_result *tr) 306 unsigned int dst_off, unsigned int len, unsigned long data)
342{ 307{
343 static const char * const messages[] = { 308 pr_info("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)",
344 [DMATEST_ET_OK] = "No errors", 309 current->comm, n, err, src_off, dst_off, len, data);
345 [DMATEST_ET_MAP_SRC] = "src mapping error",
346 [DMATEST_ET_MAP_DST] = "dst mapping error",
347 [DMATEST_ET_PREP] = "prep error",
348 [DMATEST_ET_SUBMIT] = "submit error",
349 [DMATEST_ET_TIMEOUT] = "test timed out",
350 [DMATEST_ET_DMA_ERROR] =
351 "got completion callback (DMA_ERROR)",
352 [DMATEST_ET_DMA_IN_PROGRESS] =
353 "got completion callback (DMA_IN_PROGRESS)",
354 [DMATEST_ET_VERIFY] = "errors",
355 };
356 static char buf[512];
357
358 snprintf(buf, sizeof(buf) - 1,
359 "%s: #%u: %s with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)",
360 name, tr->n, messages[tr->type], tr->src_off, tr->dst_off,
361 tr->len, tr->data);
362
363 return buf;
364} 310}
365 311
366static int thread_result_add(struct dmatest_info *info, 312static void dbg_result(const char *err, unsigned int n, unsigned int src_off,
367 struct dmatest_result *r, enum dmatest_error_type type, 313 unsigned int dst_off, unsigned int len,
368 unsigned int n, unsigned int src_off, unsigned int dst_off, 314 unsigned long data)
369 unsigned int len, unsigned long data)
370{ 315{
371 struct dmatest_thread_result *tr; 316 pr_debug("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)",
372 317 current->comm, n, err, src_off, dst_off, len, data);
373 tr = kzalloc(sizeof(*tr), GFP_KERNEL);
374 if (!tr)
375 return -ENOMEM;
376
377 tr->type = type;
378 tr->n = n;
379 tr->src_off = src_off;
380 tr->dst_off = dst_off;
381 tr->len = len;
382 tr->data = data;
383
384 mutex_lock(&info->results_lock);
385 list_add_tail(&tr->node, &r->results);
386 mutex_unlock(&info->results_lock);
387
388 if (tr->type == DMATEST_ET_OK)
389 pr_debug("%s\n", thread_result_get(r->name, tr));
390 else
391 pr_warn("%s\n", thread_result_get(r->name, tr));
392
393 return 0;
394}
395
396static void result_free(struct dmatest_info *info, const char *name)
397{
398 struct dmatest_result *r, *_r;
399
400 mutex_lock(&info->results_lock);
401 list_for_each_entry_safe(r, _r, &info->results, node) {
402 struct dmatest_thread_result *tr, *_tr;
403
404 if (name && strcmp(r->name, name))
405 continue;
406
407 list_for_each_entry_safe(tr, _tr, &r->results, node) {
408 list_del(&tr->node);
409 kfree(tr);
410 }
411
412 kfree(r->name);
413 list_del(&r->node);
414 kfree(r);
415 }
416
417 mutex_unlock(&info->results_lock);
418}
419
420static struct dmatest_result *result_init(struct dmatest_info *info,
421 const char *name)
422{
423 struct dmatest_result *r;
424
425 r = kzalloc(sizeof(*r), GFP_KERNEL);
426 if (r) {
427 r->name = kstrdup(name, GFP_KERNEL);
428 INIT_LIST_HEAD(&r->results);
429 mutex_lock(&info->results_lock);
430 list_add_tail(&r->node, &info->results);
431 mutex_unlock(&info->results_lock);
432 }
433 return r;
434} 318}
435 319
436/* 320/*
@@ -456,7 +340,6 @@ static int dmatest_func(void *data)
456 struct dmatest_params *params; 340 struct dmatest_params *params;
457 struct dma_chan *chan; 341 struct dma_chan *chan;
458 struct dma_device *dev; 342 struct dma_device *dev;
459 const char *thread_name;
460 unsigned int src_off, dst_off, len; 343 unsigned int src_off, dst_off, len;
461 unsigned int error_count; 344 unsigned int error_count;
462 unsigned int failed_tests = 0; 345 unsigned int failed_tests = 0;
@@ -469,9 +352,7 @@ static int dmatest_func(void *data)
469 int src_cnt; 352 int src_cnt;
470 int dst_cnt; 353 int dst_cnt;
471 int i; 354 int i;
472 struct dmatest_result *result;
473 355
474 thread_name = current->comm;
475 set_freezable(); 356 set_freezable();
476 357
477 ret = -ENOMEM; 358 ret = -ENOMEM;
@@ -501,10 +382,6 @@ static int dmatest_func(void *data)
501 } else 382 } else
502 goto err_thread_type; 383 goto err_thread_type;
503 384
504 result = result_init(info, thread_name);
505 if (!result)
506 goto err_srcs;
507
508 thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL); 385 thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL);
509 if (!thread->srcs) 386 if (!thread->srcs)
510 goto err_srcs; 387 goto err_srcs;
@@ -576,10 +453,8 @@ static int dmatest_func(void *data)
576 ret = dma_mapping_error(dev->dev, dma_srcs[i]); 453 ret = dma_mapping_error(dev->dev, dma_srcs[i]);
577 if (ret) { 454 if (ret) {
578 unmap_src(dev->dev, dma_srcs, len, i); 455 unmap_src(dev->dev, dma_srcs, len, i);
579 thread_result_add(info, result, 456 result("src mapping error", total_tests,
580 DMATEST_ET_MAP_SRC, 457 src_off, dst_off, len, ret);
581 total_tests, src_off, dst_off,
582 len, ret);
583 failed_tests++; 458 failed_tests++;
584 continue; 459 continue;
585 } 460 }
@@ -594,10 +469,8 @@ static int dmatest_func(void *data)
594 unmap_src(dev->dev, dma_srcs, len, src_cnt); 469 unmap_src(dev->dev, dma_srcs, len, src_cnt);
595 unmap_dst(dev->dev, dma_dsts, params->buf_size, 470 unmap_dst(dev->dev, dma_dsts, params->buf_size,
596 i); 471 i);
597 thread_result_add(info, result, 472 result("dst mapping error", total_tests,
598 DMATEST_ET_MAP_DST, 473 src_off, dst_off, len, ret);
599 total_tests, src_off, dst_off,
600 len, ret);
601 failed_tests++; 474 failed_tests++;
602 continue; 475 continue;
603 } 476 }
@@ -627,9 +500,8 @@ static int dmatest_func(void *data)
627 unmap_src(dev->dev, dma_srcs, len, src_cnt); 500 unmap_src(dev->dev, dma_srcs, len, src_cnt);
628 unmap_dst(dev->dev, dma_dsts, params->buf_size, 501 unmap_dst(dev->dev, dma_dsts, params->buf_size,
629 dst_cnt); 502 dst_cnt);
630 thread_result_add(info, result, DMATEST_ET_PREP, 503 result("prep error", total_tests, src_off,
631 total_tests, src_off, dst_off, 504 dst_off, len, ret);
632 len, 0);
633 msleep(100); 505 msleep(100);
634 failed_tests++; 506 failed_tests++;
635 continue; 507 continue;
@@ -641,9 +513,8 @@ static int dmatest_func(void *data)
641 cookie = tx->tx_submit(tx); 513 cookie = tx->tx_submit(tx);
642 514
643 if (dma_submit_error(cookie)) { 515 if (dma_submit_error(cookie)) {
644 thread_result_add(info, result, DMATEST_ET_SUBMIT, 516 result("submit error", total_tests, src_off,
645 total_tests, src_off, dst_off, 517 dst_off, len, ret);
646 len, cookie);
647 msleep(100); 518 msleep(100);
648 failed_tests++; 519 failed_tests++;
649 continue; 520 continue;
@@ -664,17 +535,15 @@ static int dmatest_func(void *data)
664 * free it this time?" dancing. For now, just 535 * free it this time?" dancing. For now, just
665 * leave it dangling. 536 * leave it dangling.
666 */ 537 */
667 thread_result_add(info, result, DMATEST_ET_TIMEOUT, 538 result("test timed out", total_tests, src_off, dst_off,
668 total_tests, src_off, dst_off, 539 len, 0);
669 len, 0);
670 failed_tests++; 540 failed_tests++;
671 continue; 541 continue;
672 } else if (status != DMA_SUCCESS) { 542 } else if (status != DMA_SUCCESS) {
673 enum dmatest_error_type type = (status == DMA_ERROR) ? 543 result(status == DMA_ERROR ?
674 DMATEST_ET_DMA_ERROR : DMATEST_ET_DMA_IN_PROGRESS; 544 "completion error status" :
675 thread_result_add(info, result, type, 545 "completion busy status", total_tests, src_off,
676 total_tests, src_off, dst_off, 546 dst_off, len, ret);
677 len, status);
678 failed_tests++; 547 failed_tests++;
679 continue; 548 continue;
680 } 549 }
@@ -685,7 +554,7 @@ static int dmatest_func(void *data)
685 554
686 error_count = 0; 555 error_count = 0;
687 556
688 pr_debug("%s: verifying source buffer...\n", thread_name); 557 pr_debug("%s: verifying source buffer...\n", current->comm);
689 error_count += dmatest_verify(thread->srcs, 0, src_off, 558 error_count += dmatest_verify(thread->srcs, 0, src_off,
690 0, PATTERN_SRC, true); 559 0, PATTERN_SRC, true);
691 error_count += dmatest_verify(thread->srcs, src_off, 560 error_count += dmatest_verify(thread->srcs, src_off,
@@ -695,8 +564,7 @@ static int dmatest_func(void *data)
695 params->buf_size, src_off + len, 564 params->buf_size, src_off + len,
696 PATTERN_SRC, true); 565 PATTERN_SRC, true);
697 566
698 pr_debug("%s: verifying dest buffer...\n", 567 pr_debug("%s: verifying dest buffer...\n", current->comm);
699 thread->task->comm);
700 error_count += dmatest_verify(thread->dsts, 0, dst_off, 568 error_count += dmatest_verify(thread->dsts, 0, dst_off,
701 0, PATTERN_DST, false); 569 0, PATTERN_DST, false);
702 error_count += dmatest_verify(thread->dsts, dst_off, 570 error_count += dmatest_verify(thread->dsts, dst_off,
@@ -707,14 +575,12 @@ static int dmatest_func(void *data)
707 PATTERN_DST, false); 575 PATTERN_DST, false);
708 576
709 if (error_count) { 577 if (error_count) {
710 thread_result_add(info, result, DMATEST_ET_VERIFY, 578 result("data error", total_tests, src_off, dst_off,
711 total_tests, src_off, dst_off, 579 len, error_count);
712 len, error_count);
713 failed_tests++; 580 failed_tests++;
714 } else { 581 } else {
715 thread_result_add(info, result, DMATEST_ET_OK, 582 dbg_result("test passed", total_tests, src_off, dst_off,
716 total_tests, src_off, dst_off, 583 len, 0);
717 len, 0);
718 } 584 }
719 } 585 }
720 586
@@ -731,8 +597,8 @@ err_srcbuf:
731err_srcs: 597err_srcs:
732 kfree(pq_coefs); 598 kfree(pq_coefs);
733err_thread_type: 599err_thread_type:
734 pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", 600 pr_info("%s: terminating after %u tests, %u failures (status %d)\n",
735 thread_name, total_tests, failed_tests, ret); 601 current->comm, total_tests, failed_tests, ret);
736 602
737 /* terminate all transfers on specified channels */ 603 /* terminate all transfers on specified channels */
738 if (ret) 604 if (ret)
@@ -937,9 +803,6 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run)
937 if (run == false) 803 if (run == false)
938 return 0; 804 return 0;
939 805
940 /* Clear results from previous run */
941 result_free(info, NULL);
942
943 /* Copy test parameters */ 806 /* Copy test parameters */
944 params->buf_size = test_buf_size; 807 params->buf_size = test_buf_size;
945 strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); 808 strlcpy(params->channel, strim(test_channel), sizeof(params->channel));
@@ -1024,35 +887,6 @@ static const struct file_operations dtf_run_fops = {
1024 .llseek = default_llseek, 887 .llseek = default_llseek,
1025}; 888};
1026 889
1027static int dtf_results_show(struct seq_file *sf, void *data)
1028{
1029 struct dmatest_info *info = sf->private;
1030 struct dmatest_result *result;
1031 struct dmatest_thread_result *tr;
1032
1033 mutex_lock(&info->results_lock);
1034 list_for_each_entry(result, &info->results, node) {
1035 list_for_each_entry(tr, &result->results, node)
1036 seq_printf(sf, "%s\n",
1037 thread_result_get(result->name, tr));
1038 }
1039
1040 mutex_unlock(&info->results_lock);
1041 return 0;
1042}
1043
1044static int dtf_results_open(struct inode *inode, struct file *file)
1045{
1046 return single_open(file, dtf_results_show, inode->i_private);
1047}
1048
1049static const struct file_operations dtf_results_fops = {
1050 .open = dtf_results_open,
1051 .read = seq_read,
1052 .llseek = seq_lseek,
1053 .release = single_release,
1054};
1055
1056static int dmatest_register_dbgfs(struct dmatest_info *info) 890static int dmatest_register_dbgfs(struct dmatest_info *info)
1057{ 891{
1058 struct dentry *d; 892 struct dentry *d;
@@ -1069,10 +903,6 @@ static int dmatest_register_dbgfs(struct dmatest_info *info)
1069 debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info, 903 debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info,
1070 &dtf_run_fops); 904 &dtf_run_fops);
1071 905
1072 /* Results of test in progress */
1073 debugfs_create_file("results", S_IRUGO, info->root, info,
1074 &dtf_results_fops);
1075
1076 return 0; 906 return 0;
1077 907
1078err_root: 908err_root:
@@ -1090,9 +920,6 @@ static int __init dmatest_init(void)
1090 mutex_init(&info->lock); 920 mutex_init(&info->lock);
1091 INIT_LIST_HEAD(&info->channels); 921 INIT_LIST_HEAD(&info->channels);
1092 922
1093 mutex_init(&info->results_lock);
1094 INIT_LIST_HEAD(&info->results);
1095
1096 ret = dmatest_register_dbgfs(info); 923 ret = dmatest_register_dbgfs(info);
1097 if (ret) 924 if (ret)
1098 return ret; 925 return ret;
@@ -1112,7 +939,6 @@ static void __exit dmatest_exit(void)
1112 939
1113 debugfs_remove_recursive(info->root); 940 debugfs_remove_recursive(info->root);
1114 stop_threaded_test(info); 941 stop_threaded_test(info);
1115 result_free(info, NULL);
1116} 942}
1117module_exit(dmatest_exit); 943module_exit(dmatest_exit);
1118 944