@@ -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+
89122struct dmatest_info ;
90123
91124struct 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
151188static 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+
9481112static 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
10201190err_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}
10691243module_exit (dmatest_exit );
10701244
0 commit comments