diff options
-rw-r--r-- | drivers/dma/dmatest.c | 109 |
1 files changed, 62 insertions, 47 deletions
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 475a21ad6657..c6e5d8331c66 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c | |||
@@ -97,7 +97,7 @@ struct dmatest_chan { | |||
97 | }; | 97 | }; |
98 | 98 | ||
99 | /** | 99 | /** |
100 | * struct dmatest_info - test information. | 100 | * struct dmatest_params - test parameters. |
101 | * @buf_size: size of the memcpy test buffer | 101 | * @buf_size: size of the memcpy test buffer |
102 | * @channel: bus ID of the channel to test | 102 | * @channel: bus ID of the channel to test |
103 | * @device: bus ID of the DMA Engine to test | 103 | * @device: bus ID of the DMA Engine to test |
@@ -108,8 +108,7 @@ struct dmatest_chan { | |||
108 | * @pq_sources: number of p+q source buffers | 108 | * @pq_sources: number of p+q source buffers |
109 | * @timeout: transfer timeout in msec, -1 for infinite timeout | 109 | * @timeout: transfer timeout in msec, -1 for infinite timeout |
110 | */ | 110 | */ |
111 | struct dmatest_info { | 111 | struct dmatest_params { |
112 | /* Test parameters */ | ||
113 | unsigned int buf_size; | 112 | unsigned int buf_size; |
114 | char channel[20]; | 113 | char channel[20]; |
115 | char device[20]; | 114 | char device[20]; |
@@ -119,6 +118,15 @@ struct dmatest_info { | |||
119 | unsigned int xor_sources; | 118 | unsigned int xor_sources; |
120 | unsigned int pq_sources; | 119 | unsigned int pq_sources; |
121 | int timeout; | 120 | int timeout; |
121 | }; | ||
122 | |||
123 | /** | ||
124 | * struct dmatest_info - test information. | ||
125 | * @params: test parameters | ||
126 | */ | ||
127 | struct dmatest_info { | ||
128 | /* Test parameters */ | ||
129 | struct dmatest_params params; | ||
122 | 130 | ||
123 | /* Internal state */ | 131 | /* Internal state */ |
124 | struct list_head channels; | 132 | struct list_head channels; |
@@ -127,20 +135,20 @@ struct dmatest_info { | |||
127 | 135 | ||
128 | static struct dmatest_info test_info; | 136 | static struct dmatest_info test_info; |
129 | 137 | ||
130 | static bool dmatest_match_channel(struct dmatest_info *info, | 138 | static bool dmatest_match_channel(struct dmatest_params *params, |
131 | struct dma_chan *chan) | 139 | struct dma_chan *chan) |
132 | { | 140 | { |
133 | if (info->channel[0] == '\0') | 141 | if (params->channel[0] == '\0') |
134 | return true; | 142 | return true; |
135 | return strcmp(dma_chan_name(chan), info->channel) == 0; | 143 | return strcmp(dma_chan_name(chan), params->channel) == 0; |
136 | } | 144 | } |
137 | 145 | ||
138 | static bool dmatest_match_device(struct dmatest_info *info, | 146 | static bool dmatest_match_device(struct dmatest_params *params, |
139 | struct dma_device *device) | 147 | struct dma_device *device) |
140 | { | 148 | { |
141 | if (info->device[0] == '\0') | 149 | if (params->device[0] == '\0') |
142 | return true; | 150 | return true; |
143 | return strcmp(dev_name(device->dev), info->device) == 0; | 151 | return strcmp(dev_name(device->dev), params->device) == 0; |
144 | } | 152 | } |
145 | 153 | ||
146 | static unsigned long dmatest_random(void) | 154 | static unsigned long dmatest_random(void) |
@@ -300,6 +308,7 @@ static int dmatest_func(void *data) | |||
300 | struct dmatest_thread *thread = data; | 308 | struct dmatest_thread *thread = data; |
301 | struct dmatest_done done = { .wait = &done_wait }; | 309 | struct dmatest_done done = { .wait = &done_wait }; |
302 | struct dmatest_info *info; | 310 | struct dmatest_info *info; |
311 | struct dmatest_params *params; | ||
303 | struct dma_chan *chan; | 312 | struct dma_chan *chan; |
304 | struct dma_device *dev; | 313 | struct dma_device *dev; |
305 | const char *thread_name; | 314 | const char *thread_name; |
@@ -323,20 +332,21 @@ static int dmatest_func(void *data) | |||
323 | 332 | ||
324 | smp_rmb(); | 333 | smp_rmb(); |
325 | info = thread->info; | 334 | info = thread->info; |
335 | params = &info->params; | ||
326 | chan = thread->chan; | 336 | chan = thread->chan; |
327 | dev = chan->device; | 337 | dev = chan->device; |
328 | if (thread->type == DMA_MEMCPY) | 338 | if (thread->type == DMA_MEMCPY) |
329 | src_cnt = dst_cnt = 1; | 339 | src_cnt = dst_cnt = 1; |
330 | else if (thread->type == DMA_XOR) { | 340 | else if (thread->type == DMA_XOR) { |
331 | /* force odd to ensure dst = src */ | 341 | /* force odd to ensure dst = src */ |
332 | src_cnt = min_odd(info->xor_sources | 1, dev->max_xor); | 342 | src_cnt = min_odd(params->xor_sources | 1, dev->max_xor); |
333 | dst_cnt = 1; | 343 | dst_cnt = 1; |
334 | } else if (thread->type == DMA_PQ) { | 344 | } else if (thread->type == DMA_PQ) { |
335 | /* force odd to ensure dst = src */ | 345 | /* force odd to ensure dst = src */ |
336 | src_cnt = min_odd(info->pq_sources | 1, dma_maxpq(dev, 0)); | 346 | src_cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0)); |
337 | dst_cnt = 2; | 347 | dst_cnt = 2; |
338 | 348 | ||
339 | pq_coefs = kmalloc(info->pq_sources+1, GFP_KERNEL); | 349 | pq_coefs = kmalloc(params->pq_sources+1, GFP_KERNEL); |
340 | if (!pq_coefs) | 350 | if (!pq_coefs) |
341 | goto err_thread_type; | 351 | goto err_thread_type; |
342 | 352 | ||
@@ -349,7 +359,7 @@ static int dmatest_func(void *data) | |||
349 | if (!thread->srcs) | 359 | if (!thread->srcs) |
350 | goto err_srcs; | 360 | goto err_srcs; |
351 | for (i = 0; i < src_cnt; i++) { | 361 | for (i = 0; i < src_cnt; i++) { |
352 | thread->srcs[i] = kmalloc(info->buf_size, GFP_KERNEL); | 362 | thread->srcs[i] = kmalloc(params->buf_size, GFP_KERNEL); |
353 | if (!thread->srcs[i]) | 363 | if (!thread->srcs[i]) |
354 | goto err_srcbuf; | 364 | goto err_srcbuf; |
355 | } | 365 | } |
@@ -359,7 +369,7 @@ static int dmatest_func(void *data) | |||
359 | if (!thread->dsts) | 369 | if (!thread->dsts) |
360 | goto err_dsts; | 370 | goto err_dsts; |
361 | for (i = 0; i < dst_cnt; i++) { | 371 | for (i = 0; i < dst_cnt; i++) { |
362 | thread->dsts[i] = kmalloc(info->buf_size, GFP_KERNEL); | 372 | thread->dsts[i] = kmalloc(params->buf_size, GFP_KERNEL); |
363 | if (!thread->dsts[i]) | 373 | if (!thread->dsts[i]) |
364 | goto err_dstbuf; | 374 | goto err_dstbuf; |
365 | } | 375 | } |
@@ -375,7 +385,7 @@ static int dmatest_func(void *data) | |||
375 | | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE; | 385 | | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE; |
376 | 386 | ||
377 | while (!kthread_should_stop() | 387 | while (!kthread_should_stop() |
378 | && !(info->iterations && total_tests >= info->iterations)) { | 388 | && !(params->iterations && total_tests >= params->iterations)) { |
379 | struct dma_async_tx_descriptor *tx = NULL; | 389 | struct dma_async_tx_descriptor *tx = NULL; |
380 | dma_addr_t dma_srcs[src_cnt]; | 390 | dma_addr_t dma_srcs[src_cnt]; |
381 | dma_addr_t dma_dsts[dst_cnt]; | 391 | dma_addr_t dma_dsts[dst_cnt]; |
@@ -391,24 +401,24 @@ static int dmatest_func(void *data) | |||
391 | else if (thread->type == DMA_PQ) | 401 | else if (thread->type == DMA_PQ) |
392 | align = dev->pq_align; | 402 | align = dev->pq_align; |
393 | 403 | ||
394 | if (1 << align > info->buf_size) { | 404 | if (1 << align > params->buf_size) { |
395 | pr_err("%u-byte buffer too small for %d-byte alignment\n", | 405 | pr_err("%u-byte buffer too small for %d-byte alignment\n", |
396 | info->buf_size, 1 << align); | 406 | params->buf_size, 1 << align); |
397 | break; | 407 | break; |
398 | } | 408 | } |
399 | 409 | ||
400 | len = dmatest_random() % info->buf_size + 1; | 410 | len = dmatest_random() % params->buf_size + 1; |
401 | len = (len >> align) << align; | 411 | len = (len >> align) << align; |
402 | if (!len) | 412 | if (!len) |
403 | len = 1 << align; | 413 | len = 1 << align; |
404 | src_off = dmatest_random() % (info->buf_size - len + 1); | 414 | src_off = dmatest_random() % (params->buf_size - len + 1); |
405 | dst_off = dmatest_random() % (info->buf_size - len + 1); | 415 | dst_off = dmatest_random() % (params->buf_size - len + 1); |
406 | 416 | ||
407 | src_off = (src_off >> align) << align; | 417 | src_off = (src_off >> align) << align; |
408 | dst_off = (dst_off >> align) << align; | 418 | dst_off = (dst_off >> align) << align; |
409 | 419 | ||
410 | dmatest_init_srcs(thread->srcs, src_off, len, info->buf_size); | 420 | dmatest_init_srcs(thread->srcs, src_off, len, params->buf_size); |
411 | dmatest_init_dsts(thread->dsts, dst_off, len, info->buf_size); | 421 | dmatest_init_dsts(thread->dsts, dst_off, len, params->buf_size); |
412 | 422 | ||
413 | for (i = 0; i < src_cnt; i++) { | 423 | for (i = 0; i < src_cnt; i++) { |
414 | u8 *buf = thread->srcs[i] + src_off; | 424 | u8 *buf = thread->srcs[i] + src_off; |
@@ -429,16 +439,17 @@ static int dmatest_func(void *data) | |||
429 | /* map with DMA_BIDIRECTIONAL to force writeback/invalidate */ | 439 | /* map with DMA_BIDIRECTIONAL to force writeback/invalidate */ |
430 | for (i = 0; i < dst_cnt; i++) { | 440 | for (i = 0; i < dst_cnt; i++) { |
431 | dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i], | 441 | dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i], |
432 | info->buf_size, | 442 | params->buf_size, |
433 | DMA_BIDIRECTIONAL); | 443 | DMA_BIDIRECTIONAL); |
434 | ret = dma_mapping_error(dev->dev, dma_dsts[i]); | 444 | ret = dma_mapping_error(dev->dev, dma_dsts[i]); |
435 | if (ret) { | 445 | if (ret) { |
436 | unmap_src(dev->dev, dma_srcs, len, src_cnt); | 446 | unmap_src(dev->dev, dma_srcs, len, src_cnt); |
437 | unmap_dst(dev->dev, dma_dsts, info->buf_size, i); | 447 | unmap_dst(dev->dev, dma_dsts, params->buf_size, |
448 | i); | ||
438 | pr_warn("%s: #%u: mapping error %d with " | 449 | pr_warn("%s: #%u: mapping error %d with " |
439 | "dst_off=0x%x len=0x%x\n", | 450 | "dst_off=0x%x len=0x%x\n", |
440 | thread_name, total_tests - 1, ret, | 451 | thread_name, total_tests - 1, ret, |
441 | dst_off, info->buf_size); | 452 | dst_off, params->buf_size); |
442 | failed_tests++; | 453 | failed_tests++; |
443 | continue; | 454 | continue; |
444 | } | 455 | } |
@@ -466,7 +477,8 @@ static int dmatest_func(void *data) | |||
466 | 477 | ||
467 | if (!tx) { | 478 | if (!tx) { |
468 | unmap_src(dev->dev, dma_srcs, len, src_cnt); | 479 | unmap_src(dev->dev, dma_srcs, len, src_cnt); |
469 | unmap_dst(dev->dev, dma_dsts, info->buf_size, dst_cnt); | 480 | unmap_dst(dev->dev, dma_dsts, params->buf_size, |
481 | dst_cnt); | ||
470 | pr_warning("%s: #%u: prep error with src_off=0x%x " | 482 | pr_warning("%s: #%u: prep error with src_off=0x%x " |
471 | "dst_off=0x%x len=0x%x\n", | 483 | "dst_off=0x%x len=0x%x\n", |
472 | thread_name, total_tests - 1, | 484 | thread_name, total_tests - 1, |
@@ -494,7 +506,7 @@ static int dmatest_func(void *data) | |||
494 | 506 | ||
495 | wait_event_freezable_timeout(done_wait, | 507 | wait_event_freezable_timeout(done_wait, |
496 | done.done || kthread_should_stop(), | 508 | done.done || kthread_should_stop(), |
497 | msecs_to_jiffies(info->timeout)); | 509 | msecs_to_jiffies(params->timeout)); |
498 | 510 | ||
499 | status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); | 511 | status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); |
500 | 512 | ||
@@ -521,7 +533,7 @@ static int dmatest_func(void *data) | |||
521 | } | 533 | } |
522 | 534 | ||
523 | /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ | 535 | /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ |
524 | unmap_dst(dev->dev, dma_dsts, info->buf_size, dst_cnt); | 536 | unmap_dst(dev->dev, dma_dsts, params->buf_size, dst_cnt); |
525 | 537 | ||
526 | error_count = 0; | 538 | error_count = 0; |
527 | 539 | ||
@@ -532,7 +544,7 @@ static int dmatest_func(void *data) | |||
532 | src_off + len, src_off, | 544 | src_off + len, src_off, |
533 | PATTERN_SRC | PATTERN_COPY, true); | 545 | PATTERN_SRC | PATTERN_COPY, true); |
534 | error_count += dmatest_verify(thread->srcs, src_off + len, | 546 | error_count += dmatest_verify(thread->srcs, src_off + len, |
535 | info->buf_size, src_off + len, | 547 | params->buf_size, src_off + len, |
536 | PATTERN_SRC, true); | 548 | PATTERN_SRC, true); |
537 | 549 | ||
538 | pr_debug("%s: verifying dest buffer...\n", | 550 | pr_debug("%s: verifying dest buffer...\n", |
@@ -543,7 +555,7 @@ static int dmatest_func(void *data) | |||
543 | dst_off + len, src_off, | 555 | dst_off + len, src_off, |
544 | PATTERN_SRC | PATTERN_COPY, false); | 556 | PATTERN_SRC | PATTERN_COPY, false); |
545 | error_count += dmatest_verify(thread->dsts, dst_off + len, | 557 | error_count += dmatest_verify(thread->dsts, dst_off + len, |
546 | info->buf_size, dst_off + len, | 558 | params->buf_size, dst_off + len, |
547 | PATTERN_DST, false); | 559 | PATTERN_DST, false); |
548 | 560 | ||
549 | if (error_count) { | 561 | if (error_count) { |
@@ -580,7 +592,7 @@ err_thread_type: | |||
580 | if (ret) | 592 | if (ret) |
581 | dmaengine_terminate_all(chan); | 593 | dmaengine_terminate_all(chan); |
582 | 594 | ||
583 | if (info->iterations > 0) | 595 | if (params->iterations > 0) |
584 | while (!kthread_should_stop()) { | 596 | while (!kthread_should_stop()) { |
585 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); | 597 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); |
586 | interruptible_sleep_on(&wait_dmatest_exit); | 598 | interruptible_sleep_on(&wait_dmatest_exit); |
@@ -612,6 +624,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) | |||
612 | static int dmatest_add_threads(struct dmatest_info *info, | 624 | static int dmatest_add_threads(struct dmatest_info *info, |
613 | struct dmatest_chan *dtc, enum dma_transaction_type type) | 625 | struct dmatest_chan *dtc, enum dma_transaction_type type) |
614 | { | 626 | { |
627 | struct dmatest_params *params = &info->params; | ||
615 | struct dmatest_thread *thread; | 628 | struct dmatest_thread *thread; |
616 | struct dma_chan *chan = dtc->chan; | 629 | struct dma_chan *chan = dtc->chan; |
617 | char *op; | 630 | char *op; |
@@ -626,7 +639,7 @@ static int dmatest_add_threads(struct dmatest_info *info, | |||
626 | else | 639 | else |
627 | return -EINVAL; | 640 | return -EINVAL; |
628 | 641 | ||
629 | for (i = 0; i < info->threads_per_chan; i++) { | 642 | for (i = 0; i < params->threads_per_chan; i++) { |
630 | thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); | 643 | thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); |
631 | if (!thread) { | 644 | if (!thread) { |
632 | pr_warning("dmatest: No memory for %s-%s%u\n", | 645 | pr_warning("dmatest: No memory for %s-%s%u\n", |
@@ -696,10 +709,10 @@ static int dmatest_add_channel(struct dmatest_info *info, | |||
696 | 709 | ||
697 | static bool filter(struct dma_chan *chan, void *param) | 710 | static bool filter(struct dma_chan *chan, void *param) |
698 | { | 711 | { |
699 | struct dmatest_info *info = param; | 712 | struct dmatest_params *params = param; |
700 | 713 | ||
701 | if (!dmatest_match_channel(info, chan) || | 714 | if (!dmatest_match_channel(params, chan) || |
702 | !dmatest_match_device(info, chan->device)) | 715 | !dmatest_match_device(params, chan->device)) |
703 | return false; | 716 | return false; |
704 | else | 717 | else |
705 | return true; | 718 | return true; |
@@ -709,12 +722,13 @@ static int run_threaded_test(struct dmatest_info *info) | |||
709 | { | 722 | { |
710 | dma_cap_mask_t mask; | 723 | dma_cap_mask_t mask; |
711 | struct dma_chan *chan; | 724 | struct dma_chan *chan; |
725 | struct dmatest_params *params = &info->params; | ||
712 | int err = 0; | 726 | int err = 0; |
713 | 727 | ||
714 | dma_cap_zero(mask); | 728 | dma_cap_zero(mask); |
715 | dma_cap_set(DMA_MEMCPY, mask); | 729 | dma_cap_set(DMA_MEMCPY, mask); |
716 | for (;;) { | 730 | for (;;) { |
717 | chan = dma_request_channel(mask, filter, info); | 731 | chan = dma_request_channel(mask, filter, params); |
718 | if (chan) { | 732 | if (chan) { |
719 | err = dmatest_add_channel(info, chan); | 733 | err = dmatest_add_channel(info, chan); |
720 | if (err) { | 734 | if (err) { |
@@ -723,8 +737,8 @@ static int run_threaded_test(struct dmatest_info *info) | |||
723 | } | 737 | } |
724 | } else | 738 | } else |
725 | break; /* no more channels available */ | 739 | break; /* no more channels available */ |
726 | if (info->max_channels && | 740 | if (params->max_channels && |
727 | info->nr_channels >= info->max_channels) | 741 | info->nr_channels >= params->max_channels) |
728 | break; /* we have all we need */ | 742 | break; /* we have all we need */ |
729 | } | 743 | } |
730 | return err; | 744 | return err; |
@@ -749,21 +763,22 @@ static void stop_threaded_test(struct dmatest_info *info) | |||
749 | static int __init dmatest_init(void) | 763 | static int __init dmatest_init(void) |
750 | { | 764 | { |
751 | struct dmatest_info *info = &test_info; | 765 | struct dmatest_info *info = &test_info; |
766 | struct dmatest_params *params = &info->params; | ||
752 | 767 | ||
753 | memset(info, 0, sizeof(*info)); | 768 | memset(info, 0, sizeof(*info)); |
754 | 769 | ||
755 | INIT_LIST_HEAD(&info->channels); | 770 | INIT_LIST_HEAD(&info->channels); |
756 | 771 | ||
757 | /* Set default parameters */ | 772 | /* Set default parameters */ |
758 | info->buf_size = test_buf_size; | 773 | params->buf_size = test_buf_size; |
759 | strlcpy(info->channel, test_channel, sizeof(info->channel)); | 774 | strlcpy(params->channel, test_channel, sizeof(params->channel)); |
760 | strlcpy(info->device, test_device, sizeof(info->device)); | 775 | strlcpy(params->device, test_device, sizeof(params->device)); |
761 | info->threads_per_chan = threads_per_chan; | 776 | params->threads_per_chan = threads_per_chan; |
762 | info->max_channels = max_channels; | 777 | params->max_channels = max_channels; |
763 | info->iterations = iterations; | 778 | params->iterations = iterations; |
764 | info->xor_sources = xor_sources; | 779 | params->xor_sources = xor_sources; |
765 | info->pq_sources = pq_sources; | 780 | params->pq_sources = pq_sources; |
766 | info->timeout = timeout; | 781 | params->timeout = timeout; |
767 | 782 | ||
768 | return run_threaded_test(info); | 783 | return run_threaded_test(info); |
769 | } | 784 | } |