aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2013-03-04 04:09:33 -0500
committerVinod Koul <vinod.koul@intel.com>2013-04-15 00:21:17 -0400
commit95019c8c5af947f64e4a62e08a4a275bc36148ee (patch)
treecfe4ce39d14083f9bceb177896b1088e367ff9e1
parent74b5c07a515b2986c9bdfe649213b8e358d32ad2 (diff)
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>
-rw-r--r--Documentation/dmatest.txt19
-rw-r--r--drivers/dma/dmatest.c234
2 files changed, 223 insertions, 30 deletions
diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt
index 3e17b55a8ba3..d05782b26a2e 100644
--- a/Documentation/dmatest.txt
+++ b/Documentation/dmatest.txt
@@ -58,3 +58,22 @@ the above section "Part 2 - When dmatest is built as a module..."
58In both cases the module parameters are used as initial values for the test case. 58In both cases the module parameters are used as initial values for the test case.
59You always could check them at run-time by running 59You always could check them at run-time by running
60 % grep -H . /sys/module/dmatest/parameters/* 60 % grep -H . /sys/module/dmatest/parameters/*
61
62 Part 4 - Gathering the test results
63
64The module provides a storage for the test results in the memory. The gathered
65data could be used after test is done.
66
67The special file 'results' in the debugfs represents gathered data of the in
68progress test. The messages collected are printed to the kernel log as well.
69
70Example 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
74The message format is unified across the different types of errors. A number in
75the parens represents additional information, e.g. error code, error counter,
76or status.
77
78Note that the buffer comparison is done in the old way, i.e. data is not
79collected and just printed out.
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 4225a292d371..3697bd49ed4c 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -86,6 +86,39 @@ MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
86#define PATTERN_OVERWRITE 0x20 86#define PATTERN_OVERWRITE 0x20
87#define PATTERN_COUNT_MASK 0x1f 87#define PATTERN_COUNT_MASK 0x1f
88 88
89enum 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
101struct 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
116struct dmatest_result {
117 struct list_head node;
118 char *name;
119 struct list_head results;
120};
121
89struct dmatest_info; 122struct dmatest_info;
90 123
91struct dmatest_thread { 124struct dmatest_thread {
@@ -146,6 +179,10 @@ struct dmatest_info {
146 /* debugfs related stuff */ 179 /* debugfs related stuff */
147 struct dentry *root; 180 struct dentry *root;
148 struct dmatest_params dbgfs_params; 181 struct dmatest_params dbgfs_params;
182
183 /* Test results */
184 struct list_head results;
185 struct mutex results_lock;
149}; 186};
150 187
151static struct dmatest_info test_info; 188static struct dmatest_info test_info;
@@ -303,6 +340,98 @@ static unsigned int min_odd(unsigned int x, unsigned int y)
303 return val % 2 ? val : val - 1; 340 return val % 2 ? val : val - 1;
304} 341}
305 342
343static 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
369static 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
395static 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
419static 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
306/* 435/*
307 * This function repeatedly tests DMA transfers of various lengths and 436 * This function repeatedly tests DMA transfers of various lengths and
308 * offsets for a given operation type until it is told to exit by 437 * offsets for a given operation type until it is told to exit by
@@ -339,6 +468,7 @@ static int dmatest_func(void *data)
339 int src_cnt; 468 int src_cnt;
340 int dst_cnt; 469 int dst_cnt;
341 int i; 470 int i;
471 struct dmatest_result *result;
342 472
343 thread_name = current->comm; 473 thread_name = current->comm;
344 set_freezable(); 474 set_freezable();
@@ -370,6 +500,10 @@ static int dmatest_func(void *data)
370 } else 500 } else
371 goto err_thread_type; 501 goto err_thread_type;
372 502
503 result = result_init(info, thread_name);
504 if (!result)
505 goto err_srcs;
506
373 thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL); 507 thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL);
374 if (!thread->srcs) 508 if (!thread->srcs)
375 goto err_srcs; 509 goto err_srcs;
@@ -443,10 +577,10 @@ static int dmatest_func(void *data)
443 ret = dma_mapping_error(dev->dev, dma_srcs[i]); 577 ret = dma_mapping_error(dev->dev, dma_srcs[i]);
444 if (ret) { 578 if (ret) {
445 unmap_src(dev->dev, dma_srcs, len, i); 579 unmap_src(dev->dev, dma_srcs, len, i);
446 pr_warn("%s: #%u: mapping error %d with " 580 thread_result_add(info, result,
447 "src_off=0x%x len=0x%x\n", 581 DMATEST_ET_MAP_SRC,
448 thread_name, total_tests - 1, ret, 582 total_tests, src_off, dst_off,
449 src_off, len); 583 len, ret);
450 failed_tests++; 584 failed_tests++;
451 continue; 585 continue;
452 } 586 }
@@ -461,10 +595,10 @@ static int dmatest_func(void *data)
461 unmap_src(dev->dev, dma_srcs, len, src_cnt); 595 unmap_src(dev->dev, dma_srcs, len, src_cnt);
462 unmap_dst(dev->dev, dma_dsts, params->buf_size, 596 unmap_dst(dev->dev, dma_dsts, params->buf_size,
463 i); 597 i);
464 pr_warn("%s: #%u: mapping error %d with " 598 thread_result_add(info, result,
465 "dst_off=0x%x len=0x%x\n", 599 DMATEST_ET_MAP_DST,
466 thread_name, total_tests - 1, ret, 600 total_tests, src_off, dst_off,
467 dst_off, params->buf_size); 601 len, ret);
468 failed_tests++; 602 failed_tests++;
469 continue; 603 continue;
470 } 604 }
@@ -494,10 +628,9 @@ static int dmatest_func(void *data)
494 unmap_src(dev->dev, dma_srcs, len, src_cnt); 628 unmap_src(dev->dev, dma_srcs, len, src_cnt);
495 unmap_dst(dev->dev, dma_dsts, params->buf_size, 629 unmap_dst(dev->dev, dma_dsts, params->buf_size,
496 dst_cnt); 630 dst_cnt);
497 pr_warning("%s: #%u: prep error with src_off=0x%x " 631 thread_result_add(info, result, DMATEST_ET_PREP,
498 "dst_off=0x%x len=0x%x\n", 632 total_tests, src_off, dst_off,
499 thread_name, total_tests - 1, 633 len, 0);
500 src_off, dst_off, len);
501 msleep(100); 634 msleep(100);
502 failed_tests++; 635 failed_tests++;
503 continue; 636 continue;
@@ -509,10 +642,9 @@ static int dmatest_func(void *data)
509 cookie = tx->tx_submit(tx); 642 cookie = tx->tx_submit(tx);
510 643
511 if (dma_submit_error(cookie)) { 644 if (dma_submit_error(cookie)) {
512 pr_warning("%s: #%u: submit error %d with src_off=0x%x " 645 thread_result_add(info, result, DMATEST_ET_SUBMIT,
513 "dst_off=0x%x len=0x%x\n", 646 total_tests, src_off, dst_off,
514 thread_name, total_tests - 1, cookie, 647 len, cookie);
515 src_off, dst_off, len);
516 msleep(100); 648 msleep(100);
517 failed_tests++; 649 failed_tests++;
518 continue; 650 continue;
@@ -534,15 +666,17 @@ static int dmatest_func(void *data)
534 * free it this time?" dancing. For now, just 666 * free it this time?" dancing. For now, just
535 * leave it dangling. 667 * leave it dangling.
536 */ 668 */
537 pr_warning("%s: #%u: test timed out\n", 669 thread_result_add(info, result, DMATEST_ET_TIMEOUT,
538 thread_name, total_tests - 1); 670 total_tests, src_off, dst_off,
671 len, 0);
539 failed_tests++; 672 failed_tests++;
540 continue; 673 continue;
541 } else if (status != DMA_SUCCESS) { 674 } else if (status != DMA_SUCCESS) {
542 pr_warning("%s: #%u: got completion callback," 675 enum dmatest_error_type type = (status == DMA_ERROR) ?
543 " but status is \'%s\'\n", 676 DMATEST_ET_DMA_ERROR : DMATEST_ET_DMA_IN_PROGRESS;
544 thread_name, total_tests - 1, 677 thread_result_add(info, result, type,
545 status == DMA_ERROR ? "error" : "in progress"); 678 total_tests, src_off, dst_off,
679 len, status);
546 failed_tests++; 680 failed_tests++;
547 continue; 681 continue;
548 } 682 }
@@ -574,16 +708,14 @@ static int dmatest_func(void *data)
574 PATTERN_DST, false); 708 PATTERN_DST, false);
575 709
576 if (error_count) { 710 if (error_count) {
577 pr_warning("%s: #%u: %u errors with " 711 thread_result_add(info, result, DMATEST_ET_VERIFY,
578 "src_off=0x%x dst_off=0x%x len=0x%x\n", 712 total_tests, src_off, dst_off,
579 thread_name, total_tests - 1, error_count, 713 len, error_count);
580 src_off, dst_off, len);
581 failed_tests++; 714 failed_tests++;
582 } else { 715 } else {
583 pr_debug("%s: #%u: No errors with " 716 thread_result_add(info, result, DMATEST_ET_OK,
584 "src_off=0x%x dst_off=0x%x len=0x%x\n", 717 total_tests, src_off, dst_off,
585 thread_name, total_tests - 1, 718 len, 0);
586 src_off, dst_off, len);
587 } 719 }
588 } 720 }
589 721
@@ -807,6 +939,9 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run)
807 if (run == false) 939 if (run == false)
808 return 0; 940 return 0;
809 941
942 /* Clear results from previous run */
943 result_free(info, NULL);
944
810 /* Copy test parameters */ 945 /* Copy test parameters */
811 memcpy(params, &info->dbgfs_params, sizeof(*params)); 946 memcpy(params, &info->dbgfs_params, sizeof(*params));
812 947
@@ -945,6 +1080,35 @@ static const struct file_operations dtf_run_fops = {
945 .llseek = default_llseek, 1080 .llseek = default_llseek,
946}; 1081};
947 1082
1083static 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
1100static int dtf_results_open(struct inode *inode, struct file *file)
1101{
1102 return single_open(file, dtf_results_show, inode->i_private);
1103}
1104
1105static 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
948static int dmatest_register_dbgfs(struct dmatest_info *info) 1112static int dmatest_register_dbgfs(struct dmatest_info *info)
949{ 1113{
950 struct dentry *d; 1114 struct dentry *d;
@@ -1015,6 +1179,12 @@ static int dmatest_register_dbgfs(struct dmatest_info *info)
1015 if (IS_ERR_OR_NULL(d)) 1179 if (IS_ERR_OR_NULL(d))
1016 goto err_node; 1180 goto err_node;
1017 1181
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
1018 return 0; 1188 return 0;
1019 1189
1020err_node: 1190err_node:
@@ -1035,6 +1205,9 @@ static int __init dmatest_init(void)
1035 mutex_init(&info->lock); 1205 mutex_init(&info->lock);
1036 INIT_LIST_HEAD(&info->channels); 1206 INIT_LIST_HEAD(&info->channels);
1037 1207
1208 mutex_init(&info->results_lock);
1209 INIT_LIST_HEAD(&info->results);
1210
1038 /* Set default parameters */ 1211 /* Set default parameters */
1039 params->buf_size = test_buf_size; 1212 params->buf_size = test_buf_size;
1040 strlcpy(params->channel, test_channel, sizeof(params->channel)); 1213 strlcpy(params->channel, test_channel, sizeof(params->channel));
@@ -1065,6 +1238,7 @@ static void __exit dmatest_exit(void)
1065 1238
1066 debugfs_remove_recursive(info->root); 1239 debugfs_remove_recursive(info->root);
1067 stop_threaded_test(info); 1240 stop_threaded_test(info);
1241 result_free(info, NULL);
1068} 1242}
1069module_exit(dmatest_exit); 1243module_exit(dmatest_exit);
1070 1244