diff options
author | Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 2013-03-04 04:09:34 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2013-04-15 00:21:18 -0400 |
commit | d86b2f298e6de124984f5d5817ed1e6e759b3ada (patch) | |
tree | 8e8ec1c9b6d99e7bd3920709d2166e76ac80dd07 | |
parent | 95019c8c5af947f64e4a62e08a4a275bc36148ee (diff) |
dmatest: append verify result to results
Comparison between buffers is stored to the dedicated structure.
Note that the verify result is now accessible only via file 'results' in the
debugfs.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r-- | Documentation/dmatest.txt | 6 | ||||
-rw-r--r-- | drivers/dma/dmatest.c | 182 |
2 files changed, 132 insertions, 56 deletions
diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt index d05782b26a2e..279ac0a8c5b1 100644 --- a/Documentation/dmatest.txt +++ b/Documentation/dmatest.txt | |||
@@ -75,5 +75,7 @@ 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, | 75 | the parens represents additional information, e.g. error code, error counter, |
76 | or status. | 76 | or status. |
77 | 77 | ||
78 | Note that the buffer comparison is done in the old way, i.e. data is not | 78 | Comparison between buffers is stored to the dedicated structure. |
79 | collected and just printed out. | 79 | |
80 | Note that the verify result is now accessible only via file 'results' in the | ||
81 | debugfs. | ||
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 3697bd49ed4c..d8ce4ecfef18 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c | |||
@@ -96,6 +96,20 @@ enum dmatest_error_type { | |||
96 | DMATEST_ET_DMA_ERROR, | 96 | DMATEST_ET_DMA_ERROR, |
97 | DMATEST_ET_DMA_IN_PROGRESS, | 97 | DMATEST_ET_DMA_IN_PROGRESS, |
98 | DMATEST_ET_VERIFY, | 98 | DMATEST_ET_VERIFY, |
99 | DMATEST_ET_VERIFY_BUF, | ||
100 | }; | ||
101 | |||
102 | struct dmatest_verify_buffer { | ||
103 | unsigned int index; | ||
104 | u8 expected; | ||
105 | u8 actual; | ||
106 | }; | ||
107 | |||
108 | struct dmatest_verify_result { | ||
109 | unsigned int error_count; | ||
110 | struct dmatest_verify_buffer data[MAX_ERROR_COUNT]; | ||
111 | u8 pattern; | ||
112 | bool is_srcbuf; | ||
99 | }; | 113 | }; |
100 | 114 | ||
101 | struct dmatest_thread_result { | 115 | struct dmatest_thread_result { |
@@ -106,10 +120,11 @@ struct dmatest_thread_result { | |||
106 | unsigned int len; | 120 | unsigned int len; |
107 | enum dmatest_error_type type; | 121 | enum dmatest_error_type type; |
108 | union { | 122 | union { |
109 | unsigned long data; | 123 | unsigned long data; |
110 | dma_cookie_t cookie; | 124 | dma_cookie_t cookie; |
111 | enum dma_status status; | 125 | enum dma_status status; |
112 | int error; | 126 | int error; |
127 | struct dmatest_verify_result *vr; | ||
113 | }; | 128 | }; |
114 | }; | 129 | }; |
115 | 130 | ||
@@ -246,35 +261,9 @@ static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len, | |||
246 | } | 261 | } |
247 | } | 262 | } |
248 | 263 | ||
249 | static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index, | 264 | static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, |
250 | unsigned int counter, bool is_srcbuf) | 265 | unsigned int start, unsigned int end, unsigned int counter, |
251 | { | 266 | u8 pattern, bool is_srcbuf) |
252 | u8 diff = actual ^ pattern; | ||
253 | u8 expected = pattern | (~counter & PATTERN_COUNT_MASK); | ||
254 | const char *thread_name = current->comm; | ||
255 | |||
256 | if (is_srcbuf) | ||
257 | pr_warning("%s: srcbuf[0x%x] overwritten!" | ||
258 | " Expected %02x, got %02x\n", | ||
259 | thread_name, index, expected, actual); | ||
260 | else if ((pattern & PATTERN_COPY) | ||
261 | && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) | ||
262 | pr_warning("%s: dstbuf[0x%x] not copied!" | ||
263 | " Expected %02x, got %02x\n", | ||
264 | thread_name, index, expected, actual); | ||
265 | else if (diff & PATTERN_SRC) | ||
266 | pr_warning("%s: dstbuf[0x%x] was copied!" | ||
267 | " Expected %02x, got %02x\n", | ||
268 | thread_name, index, expected, actual); | ||
269 | else | ||
270 | pr_warning("%s: dstbuf[0x%x] mismatch!" | ||
271 | " Expected %02x, got %02x\n", | ||
272 | thread_name, index, expected, actual); | ||
273 | } | ||
274 | |||
275 | static unsigned int dmatest_verify(u8 **bufs, unsigned int start, | ||
276 | unsigned int end, unsigned int counter, u8 pattern, | ||
277 | bool is_srcbuf) | ||
278 | { | 267 | { |
279 | unsigned int i; | 268 | unsigned int i; |
280 | unsigned int error_count = 0; | 269 | unsigned int error_count = 0; |
@@ -282,6 +271,7 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start, | |||
282 | u8 expected; | 271 | u8 expected; |
283 | u8 *buf; | 272 | u8 *buf; |
284 | unsigned int counter_orig = counter; | 273 | unsigned int counter_orig = counter; |
274 | struct dmatest_verify_buffer *vb; | ||
285 | 275 | ||
286 | for (; (buf = *bufs); bufs++) { | 276 | for (; (buf = *bufs); bufs++) { |
287 | counter = counter_orig; | 277 | counter = counter_orig; |
@@ -289,9 +279,12 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start, | |||
289 | actual = buf[i]; | 279 | actual = buf[i]; |
290 | expected = pattern | (~counter & PATTERN_COUNT_MASK); | 280 | expected = pattern | (~counter & PATTERN_COUNT_MASK); |
291 | if (actual != expected) { | 281 | if (actual != expected) { |
292 | if (error_count < MAX_ERROR_COUNT) | 282 | if (error_count < MAX_ERROR_COUNT && vr) { |
293 | dmatest_mismatch(actual, pattern, i, | 283 | vb = &vr->data[error_count]; |
294 | counter, is_srcbuf); | 284 | vb->index = i; |
285 | vb->expected = expected; | ||
286 | vb->actual = actual; | ||
287 | } | ||
295 | error_count++; | 288 | error_count++; |
296 | } | 289 | } |
297 | counter++; | 290 | counter++; |
@@ -340,6 +333,30 @@ static unsigned int min_odd(unsigned int x, unsigned int y) | |||
340 | return val % 2 ? val : val - 1; | 333 | return val % 2 ? val : val - 1; |
341 | } | 334 | } |
342 | 335 | ||
336 | static char *verify_result_get_one(struct dmatest_verify_result *vr, | ||
337 | unsigned int i) | ||
338 | { | ||
339 | struct dmatest_verify_buffer *vb = &vr->data[i]; | ||
340 | u8 diff = vb->actual ^ vr->pattern; | ||
341 | static char buf[512]; | ||
342 | char *msg; | ||
343 | |||
344 | if (vr->is_srcbuf) | ||
345 | msg = "srcbuf overwritten!"; | ||
346 | else if ((vr->pattern & PATTERN_COPY) | ||
347 | && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) | ||
348 | msg = "dstbuf not copied!"; | ||
349 | else if (diff & PATTERN_SRC) | ||
350 | msg = "dstbuf was copied!"; | ||
351 | else | ||
352 | msg = "dstbuf mismatch!"; | ||
353 | |||
354 | snprintf(buf, sizeof(buf) - 1, "%s [0x%x] Expected %02x, got %02x", msg, | ||
355 | vb->index, vb->expected, vb->actual); | ||
356 | |||
357 | return buf; | ||
358 | } | ||
359 | |||
343 | static char *thread_result_get(const char *name, | 360 | static char *thread_result_get(const char *name, |
344 | struct dmatest_thread_result *tr) | 361 | struct dmatest_thread_result *tr) |
345 | { | 362 | { |
@@ -355,6 +372,7 @@ static char *thread_result_get(const char *name, | |||
355 | [DMATEST_ET_DMA_IN_PROGRESS] = | 372 | [DMATEST_ET_DMA_IN_PROGRESS] = |
356 | "got completion callback (DMA_IN_PROGRESS)", | 373 | "got completion callback (DMA_IN_PROGRESS)", |
357 | [DMATEST_ET_VERIFY] = "errors", | 374 | [DMATEST_ET_VERIFY] = "errors", |
375 | [DMATEST_ET_VERIFY_BUF] = "verify errors", | ||
358 | }; | 376 | }; |
359 | static char buf[512]; | 377 | static char buf[512]; |
360 | 378 | ||
@@ -392,6 +410,51 @@ static int thread_result_add(struct dmatest_info *info, | |||
392 | return 0; | 410 | return 0; |
393 | } | 411 | } |
394 | 412 | ||
413 | static unsigned int verify_result_add(struct dmatest_info *info, | ||
414 | struct dmatest_result *r, unsigned int n, | ||
415 | unsigned int src_off, unsigned int dst_off, unsigned int len, | ||
416 | u8 **bufs, int whence, unsigned int counter, u8 pattern, | ||
417 | bool is_srcbuf) | ||
418 | { | ||
419 | struct dmatest_verify_result *vr; | ||
420 | unsigned int error_count; | ||
421 | unsigned int buf_off = is_srcbuf ? src_off : dst_off; | ||
422 | unsigned int start, end; | ||
423 | |||
424 | if (whence < 0) { | ||
425 | start = 0; | ||
426 | end = buf_off; | ||
427 | } else if (whence > 0) { | ||
428 | start = buf_off + len; | ||
429 | end = info->params.buf_size; | ||
430 | } else { | ||
431 | start = buf_off; | ||
432 | end = buf_off + len; | ||
433 | } | ||
434 | |||
435 | vr = kmalloc(sizeof(*vr), GFP_KERNEL); | ||
436 | if (!vr) { | ||
437 | pr_warn("dmatest: No memory to store verify result\n"); | ||
438 | return dmatest_verify(NULL, bufs, start, end, counter, pattern, | ||
439 | is_srcbuf); | ||
440 | } | ||
441 | |||
442 | vr->pattern = pattern; | ||
443 | vr->is_srcbuf = is_srcbuf; | ||
444 | |||
445 | error_count = dmatest_verify(vr, bufs, start, end, counter, pattern, | ||
446 | is_srcbuf); | ||
447 | if (error_count) { | ||
448 | vr->error_count = error_count; | ||
449 | thread_result_add(info, r, DMATEST_ET_VERIFY_BUF, n, src_off, | ||
450 | dst_off, len, (unsigned long)vr); | ||
451 | return error_count; | ||
452 | } | ||
453 | |||
454 | kfree(vr); | ||
455 | return 0; | ||
456 | } | ||
457 | |||
395 | static void result_free(struct dmatest_info *info, const char *name) | 458 | static void result_free(struct dmatest_info *info, const char *name) |
396 | { | 459 | { |
397 | struct dmatest_result *r, *_r; | 460 | struct dmatest_result *r, *_r; |
@@ -404,6 +467,8 @@ static void result_free(struct dmatest_info *info, const char *name) | |||
404 | continue; | 467 | continue; |
405 | 468 | ||
406 | list_for_each_entry_safe(tr, _tr, &r->results, node) { | 469 | list_for_each_entry_safe(tr, _tr, &r->results, node) { |
470 | if (tr->type == DMATEST_ET_VERIFY_BUF) | ||
471 | kfree(tr->vr); | ||
407 | list_del(&tr->node); | 472 | list_del(&tr->node); |
408 | kfree(tr); | 473 | kfree(tr); |
409 | } | 474 | } |
@@ -687,25 +752,26 @@ static int dmatest_func(void *data) | |||
687 | error_count = 0; | 752 | error_count = 0; |
688 | 753 | ||
689 | pr_debug("%s: verifying source buffer...\n", thread_name); | 754 | pr_debug("%s: verifying source buffer...\n", thread_name); |
690 | error_count += dmatest_verify(thread->srcs, 0, src_off, | 755 | error_count += verify_result_add(info, result, total_tests, |
756 | src_off, dst_off, len, thread->srcs, -1, | ||
691 | 0, PATTERN_SRC, true); | 757 | 0, PATTERN_SRC, true); |
692 | error_count += dmatest_verify(thread->srcs, src_off, | 758 | error_count += verify_result_add(info, result, total_tests, |
693 | src_off + len, src_off, | 759 | src_off, dst_off, len, thread->srcs, 0, |
694 | PATTERN_SRC | PATTERN_COPY, true); | 760 | src_off, PATTERN_SRC | PATTERN_COPY, true); |
695 | error_count += dmatest_verify(thread->srcs, src_off + len, | 761 | error_count += verify_result_add(info, result, total_tests, |
696 | params->buf_size, src_off + len, | 762 | src_off, dst_off, len, thread->srcs, 1, |
697 | PATTERN_SRC, true); | 763 | src_off + len, PATTERN_SRC, true); |
698 | 764 | ||
699 | pr_debug("%s: verifying dest buffer...\n", | 765 | pr_debug("%s: verifying dest buffer...\n", thread_name); |
700 | thread->task->comm); | 766 | error_count += verify_result_add(info, result, total_tests, |
701 | error_count += dmatest_verify(thread->dsts, 0, dst_off, | 767 | src_off, dst_off, len, thread->dsts, -1, |
702 | 0, PATTERN_DST, false); | 768 | 0, PATTERN_DST, false); |
703 | error_count += dmatest_verify(thread->dsts, dst_off, | 769 | error_count += verify_result_add(info, result, total_tests, |
704 | dst_off + len, src_off, | 770 | src_off, dst_off, len, thread->dsts, 0, |
705 | PATTERN_SRC | PATTERN_COPY, false); | 771 | src_off, PATTERN_SRC | PATTERN_COPY, false); |
706 | error_count += dmatest_verify(thread->dsts, dst_off + len, | 772 | error_count += verify_result_add(info, result, total_tests, |
707 | params->buf_size, dst_off + len, | 773 | src_off, dst_off, len, thread->dsts, 1, |
708 | PATTERN_DST, false); | 774 | dst_off + len, PATTERN_DST, false); |
709 | 775 | ||
710 | if (error_count) { | 776 | if (error_count) { |
711 | thread_result_add(info, result, DMATEST_ET_VERIFY, | 777 | thread_result_add(info, result, DMATEST_ET_VERIFY, |
@@ -1085,12 +1151,20 @@ static int dtf_results_show(struct seq_file *sf, void *data) | |||
1085 | struct dmatest_info *info = sf->private; | 1151 | struct dmatest_info *info = sf->private; |
1086 | struct dmatest_result *result; | 1152 | struct dmatest_result *result; |
1087 | struct dmatest_thread_result *tr; | 1153 | struct dmatest_thread_result *tr; |
1154 | unsigned int i; | ||
1088 | 1155 | ||
1089 | mutex_lock(&info->results_lock); | 1156 | mutex_lock(&info->results_lock); |
1090 | list_for_each_entry(result, &info->results, node) { | 1157 | list_for_each_entry(result, &info->results, node) { |
1091 | list_for_each_entry(tr, &result->results, node) | 1158 | list_for_each_entry(tr, &result->results, node) { |
1092 | seq_printf(sf, "%s\n", | 1159 | seq_printf(sf, "%s\n", |
1093 | thread_result_get(result->name, tr)); | 1160 | thread_result_get(result->name, tr)); |
1161 | if (tr->type == DMATEST_ET_VERIFY_BUF) { | ||
1162 | for (i = 0; i < tr->vr->error_count; i++) { | ||
1163 | seq_printf(sf, "\t%s\n", | ||
1164 | verify_result_get_one(tr->vr, i)); | ||
1165 | } | ||
1166 | } | ||
1167 | } | ||
1094 | } | 1168 | } |
1095 | 1169 | ||
1096 | mutex_unlock(&info->results_lock); | 1170 | mutex_unlock(&info->results_lock); |