GNU Linux-libre 4.19.264-gnu1
[releases.git] / tools / testing / selftests / ntb / ntb_test.sh
1 #!/bin/bash
2 # Copyright (c) 2016 Microsemi. All Rights Reserved.
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 2 of
7 # the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it would be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # Author: Logan Gunthorpe <logang@deltatee.com>
15
16 REMOTE_HOST=
17 LIST_DEVS=FALSE
18
19 DEBUGFS=${DEBUGFS-/sys/kernel/debug}
20
21 PERF_RUN_ORDER=32
22 MAX_MW_SIZE=0
23 RUN_DMA_TESTS=
24 DONT_CLEANUP=
25 MW_SIZE=65536
26
27 function show_help()
28 {
29         echo "Usage: $0 [OPTIONS] LOCAL_DEV REMOTE_DEV"
30         echo "Run tests on a pair of NTB endpoints."
31         echo
32         echo "If the NTB device loops back to the same host then,"
33         echo "just specifying the two PCI ids on the command line is"
34         echo "sufficient. Otherwise, if the NTB link spans two hosts"
35         echo "use the -r option to specify the hostname for the remote"
36         echo "device. SSH will then be used to test the remote side."
37         echo "An SSH key between the root users of the host would then"
38         echo "be highly recommended."
39         echo
40         echo "Options:"
41         echo "  -C              don't cleanup ntb modules on exit"
42         echo "  -h              show this help message"
43         echo "  -l              list available local and remote PCI ids"
44         echo "  -r REMOTE_HOST  specify the remote's hostname to connect"
45         echo "                  to for the test (using ssh)"
46         echo "  -m MW_SIZE      memory window size for ntb_tool"
47         echo "                  (default: $MW_SIZE)"
48         echo "  -d              run dma tests for ntb_perf"
49         echo "  -p ORDER        total data order for ntb_perf"
50         echo "                  (default: $PERF_RUN_ORDER)"
51         echo "  -w MAX_MW_SIZE  maxmium memory window size for ntb_perf"
52         echo
53 }
54
55 function parse_args()
56 {
57         OPTIND=0
58         while getopts "b:Cdhlm:r:p:w:" opt; do
59                 case "$opt" in
60                 C)  DONT_CLEANUP=1 ;;
61                 d)  RUN_DMA_TESTS=1 ;;
62                 h)  show_help; exit 0 ;;
63                 l)  LIST_DEVS=TRUE ;;
64                 m)  MW_SIZE=${OPTARG} ;;
65                 r)  REMOTE_HOST=${OPTARG} ;;
66                 p)  PERF_RUN_ORDER=${OPTARG} ;;
67                 w)  MAX_MW_SIZE=${OPTARG} ;;
68                 \?)
69                     echo "Invalid option: -$OPTARG" >&2
70                     exit 1
71                     ;;
72                 esac
73         done
74 }
75
76 parse_args "$@"
77 shift $((OPTIND-1))
78 LOCAL_DEV=$1
79 shift
80 parse_args "$@"
81 shift $((OPTIND-1))
82 REMOTE_DEV=$1
83 shift
84 parse_args "$@"
85
86 set -e
87
88 function _modprobe()
89 {
90         modprobe "$@"
91
92         if [[ "$REMOTE_HOST" != "" ]]; then
93                 ssh "$REMOTE_HOST" modprobe "$@"
94         fi
95 }
96
97 function split_remote()
98 {
99         VPATH=$1
100         REMOTE=
101
102         if [[ "$VPATH" == *":/"* ]]; then
103                 REMOTE=${VPATH%%:*}
104                 VPATH=${VPATH#*:}
105         fi
106 }
107
108 function read_file()
109 {
110         split_remote $1
111         if [[ "$REMOTE" != "" ]]; then
112                 ssh "$REMOTE" cat "$VPATH"
113         else
114                 cat "$VPATH"
115         fi
116 }
117
118 function write_file()
119 {
120         split_remote $2
121         VALUE=$1
122
123         if [[ "$REMOTE" != "" ]]; then
124                 ssh "$REMOTE" "echo \"$VALUE\" > \"$VPATH\""
125         else
126                 echo "$VALUE" > "$VPATH"
127         fi
128 }
129
130 function check_file()
131 {
132         split_remote $1
133
134         if [[ "$REMOTE" != "" ]]; then
135                 ssh "$REMOTE" "[[ -e ${VPATH} ]]"
136         else
137                 [[ -e ${VPATH} ]]
138         fi
139 }
140
141 function subdirname()
142 {
143         echo $(basename $(dirname $1)) 2> /dev/null
144 }
145
146 function find_pidx()
147 {
148         PORT=$1
149         PPATH=$2
150
151         for ((i = 0; i < 64; i++)); do
152                 PEER_DIR="$PPATH/peer$i"
153
154                 check_file ${PEER_DIR} || break
155
156                 PEER_PORT=$(read_file "${PEER_DIR}/port")
157                 if [[ ${PORT} -eq $PEER_PORT ]]; then
158                         echo $i
159                         return 0
160                 fi
161         done
162
163         return 1
164 }
165
166 function port_test()
167 {
168         LOC=$1
169         REM=$2
170
171         echo "Running port tests on: $(basename $LOC) / $(basename $REM)"
172
173         LOCAL_PORT=$(read_file "$LOC/port")
174         REMOTE_PORT=$(read_file "$REM/port")
175
176         LOCAL_PIDX=$(find_pidx ${REMOTE_PORT} "$LOC")
177         REMOTE_PIDX=$(find_pidx ${LOCAL_PORT} "$REM")
178
179         echo "Local port ${LOCAL_PORT} with index ${REMOTE_PIDX} on remote host"
180         echo "Peer port ${REMOTE_PORT} with index ${LOCAL_PIDX} on local host"
181
182         echo "  Passed"
183 }
184
185 function link_test()
186 {
187         LOC=$1
188         REM=$2
189         EXP=0
190
191         echo "Running link tests on: $(subdirname $LOC) / $(subdirname $REM)"
192
193         if ! write_file "N" "$LOC/../link" 2> /dev/null; then
194                 echo "  Unsupported"
195                 return
196         fi
197
198         write_file "N" "$LOC/link_event"
199
200         if [[ $(read_file "$REM/link") != "N" ]]; then
201                 echo "Expected link to be down in $REM/link" >&2
202                 exit -1
203         fi
204
205         write_file "Y" "$LOC/../link"
206
207         echo "  Passed"
208 }
209
210 function doorbell_test()
211 {
212         LOC=$1
213         REM=$2
214         EXP=0
215
216         echo "Running db tests on: $(basename $LOC) / $(basename $REM)"
217
218         DB_VALID_MASK=$(read_file "$LOC/db_valid_mask")
219
220         write_file "c $DB_VALID_MASK" "$REM/db"
221
222         for ((i = 0; i < 64; i++)); do
223                 DB=$(read_file "$REM/db")
224                 if [[ "$DB" -ne "$EXP" ]]; then
225                         echo "Doorbell doesn't match expected value $EXP " \
226                              "in $REM/db" >&2
227                         exit -1
228                 fi
229
230                 let "MASK = (1 << $i) & $DB_VALID_MASK" || true
231                 let "EXP = $EXP | $MASK" || true
232
233                 write_file "s $MASK" "$LOC/peer_db"
234         done
235
236         write_file "c $DB_VALID_MASK" "$REM/db_mask"
237         write_file $DB_VALID_MASK "$REM/db_event"
238         write_file "s $DB_VALID_MASK" "$REM/db_mask"
239
240         write_file "c $DB_VALID_MASK" "$REM/db"
241
242         echo "  Passed"
243 }
244
245 function get_files_count()
246 {
247         NAME=$1
248         LOC=$2
249
250         split_remote $LOC
251
252         if [[ "$REMOTE" == "" ]]; then
253                 echo $(ls -1 "$VPATH"/${NAME}* 2>/dev/null | wc -l)
254         else
255                 echo $(ssh "$REMOTE" "ls -1 \"$VPATH\"/${NAME}* | \
256                        wc -l" 2> /dev/null)
257         fi
258 }
259
260 function scratchpad_test()
261 {
262         LOC=$1
263         REM=$2
264
265         echo "Running spad tests on: $(subdirname $LOC) / $(subdirname $REM)"
266
267         CNT=$(get_files_count "spad" "$LOC")
268
269         if [[ $CNT -eq 0 ]]; then
270                 echo "  Unsupported"
271                 return
272         fi
273
274         for ((i = 0; i < $CNT; i++)); do
275                 VAL=$RANDOM
276                 write_file "$VAL" "$LOC/spad$i"
277                 RVAL=$(read_file "$REM/../spad$i")
278
279                 if [[ "$VAL" -ne "$RVAL" ]]; then
280                         echo "Scratchpad $i value $RVAL doesn't match $VAL" >&2
281                         exit -1
282                 fi
283         done
284
285         echo "  Passed"
286 }
287
288 function message_test()
289 {
290         LOC=$1
291         REM=$2
292
293         echo "Running msg tests on: $(subdirname $LOC) / $(subdirname $REM)"
294
295         CNT=$(get_files_count "msg" "$LOC")
296
297         if [[ $CNT -eq 0 ]]; then
298                 echo "  Unsupported"
299                 return
300         fi
301
302         MSG_OUTBITS_MASK=$(read_file "$LOC/../msg_inbits")
303         MSG_INBITS_MASK=$(read_file "$REM/../msg_inbits")
304
305         write_file "c $MSG_OUTBITS_MASK" "$LOC/../msg_sts"
306         write_file "c $MSG_INBITS_MASK" "$REM/../msg_sts"
307
308         for ((i = 0; i < $CNT; i++)); do
309                 VAL=$RANDOM
310                 write_file "$VAL" "$LOC/msg$i"
311                 RVAL=$(read_file "$REM/../msg$i")
312
313                 if [[ "$VAL" -ne "${RVAL%%<-*}" ]]; then
314                         echo "Message $i value $RVAL doesn't match $VAL" >&2
315                         exit -1
316                 fi
317         done
318
319         echo "  Passed"
320 }
321
322 function get_number()
323 {
324         KEY=$1
325
326         sed -n "s/^\(${KEY}\)[ \t]*\(0x[0-9a-fA-F]*\)\(\[p\]\)\?$/\2/p"
327 }
328
329 function mw_alloc()
330 {
331         IDX=$1
332         LOC=$2
333         REM=$3
334
335         write_file $MW_SIZE "$LOC/mw_trans$IDX"
336
337         INB_MW=$(read_file "$LOC/mw_trans$IDX")
338         MW_ALIGNED_SIZE=$(echo "$INB_MW" | get_number "Window Size")
339         MW_DMA_ADDR=$(echo "$INB_MW" | get_number "DMA Address")
340
341         write_file "$MW_DMA_ADDR:$(($MW_ALIGNED_SIZE))" "$REM/peer_mw_trans$IDX"
342
343         if [[ $MW_SIZE -ne $MW_ALIGNED_SIZE ]]; then
344                 echo "MW $IDX size aligned to $MW_ALIGNED_SIZE"
345         fi
346 }
347
348 function write_mw()
349 {
350         split_remote $2
351
352         if [[ "$REMOTE" != "" ]]; then
353                 ssh "$REMOTE" \
354                         dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true
355         else
356                 dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true
357         fi
358 }
359
360 function mw_check()
361 {
362         IDX=$1
363         LOC=$2
364         REM=$3
365
366         write_mw "$LOC/mw$IDX"
367
368         split_remote "$LOC/mw$IDX"
369         if [[ "$REMOTE" == "" ]]; then
370                 A=$VPATH
371         else
372                 A=/tmp/ntb_test.$$.A
373                 ssh "$REMOTE" cat "$VPATH" > "$A"
374         fi
375
376         split_remote "$REM/peer_mw$IDX"
377         if [[ "$REMOTE" == "" ]]; then
378                 B=$VPATH
379         else
380                 B=/tmp/ntb_test.$$.B
381                 ssh "$REMOTE" cat "$VPATH" > "$B"
382         fi
383
384         cmp -n $MW_ALIGNED_SIZE "$A" "$B"
385         if [[ $? != 0 ]]; then
386                 echo "Memory window $MW did not match!" >&2
387         fi
388
389         if [[ "$A" == "/tmp/*" ]]; then
390                 rm "$A"
391         fi
392
393         if [[ "$B" == "/tmp/*" ]]; then
394                 rm "$B"
395         fi
396 }
397
398 function mw_free()
399 {
400         IDX=$1
401         LOC=$2
402         REM=$3
403
404         write_file "$MW_DMA_ADDR:0" "$REM/peer_mw_trans$IDX"
405
406         write_file 0 "$LOC/mw_trans$IDX"
407 }
408
409 function mw_test()
410 {
411         LOC=$1
412         REM=$2
413
414         CNT=$(get_files_count "mw_trans" "$LOC")
415
416         for ((i = 0; i < $CNT; i++)); do
417                 echo "Running mw$i tests on: $(subdirname $LOC) / " \
418                      "$(subdirname $REM)"
419
420                 mw_alloc $i $LOC $REM
421
422                 mw_check $i $LOC $REM
423
424                 mw_free $i $LOC  $REM
425
426                 echo "  Passed"
427         done
428
429 }
430
431 function pingpong_test()
432 {
433         LOC=$1
434         REM=$2
435
436         echo "Running ping pong tests on: $(basename $LOC) / $(basename $REM)"
437
438         LOC_START=$(read_file "$LOC/count")
439         REM_START=$(read_file "$REM/count")
440
441         sleep 7
442
443         LOC_END=$(read_file "$LOC/count")
444         REM_END=$(read_file "$REM/count")
445
446         if [[ $LOC_START == $LOC_END ]] || [[ $REM_START == $REM_END ]]; then
447                 echo "Ping pong counter not incrementing!" >&2
448                 exit 1
449         fi
450
451         echo "  Passed"
452 }
453
454 function perf_test()
455 {
456         USE_DMA=$1
457
458         if [[ $USE_DMA == "1" ]]; then
459                 WITH="with"
460         else
461                 WITH="without"
462         fi
463
464         _modprobe ntb_perf total_order=$PERF_RUN_ORDER \
465                 max_mw_size=$MAX_MW_SIZE use_dma=$USE_DMA
466
467         echo "Running local perf test $WITH DMA"
468         write_file "$LOCAL_PIDX" "$LOCAL_PERF/run"
469         echo -n "  "
470         read_file "$LOCAL_PERF/run"
471         echo "  Passed"
472
473         echo "Running remote perf test $WITH DMA"
474         write_file "$REMOTE_PIDX" "$REMOTE_PERF/run"
475         echo -n "  "
476         read_file "$REMOTE_PERF/run"
477         echo "  Passed"
478
479         _modprobe -r ntb_perf
480 }
481
482 function ntb_tool_tests()
483 {
484         LOCAL_TOOL="$DEBUGFS/ntb_tool/$LOCAL_DEV"
485         REMOTE_TOOL="$REMOTE_HOST:$DEBUGFS/ntb_tool/$REMOTE_DEV"
486
487         echo "Starting ntb_tool tests..."
488
489         _modprobe ntb_tool
490
491         port_test "$LOCAL_TOOL" "$REMOTE_TOOL"
492
493         LOCAL_PEER_TOOL="$LOCAL_TOOL/peer$LOCAL_PIDX"
494         REMOTE_PEER_TOOL="$REMOTE_TOOL/peer$REMOTE_PIDX"
495
496         link_test "$LOCAL_PEER_TOOL" "$REMOTE_PEER_TOOL"
497         link_test "$REMOTE_PEER_TOOL" "$LOCAL_PEER_TOOL"
498
499         #Ensure the link is up on both sides before continuing
500         write_file "Y" "$LOCAL_PEER_TOOL/link_event"
501         write_file "Y" "$REMOTE_PEER_TOOL/link_event"
502
503         doorbell_test "$LOCAL_TOOL" "$REMOTE_TOOL"
504         doorbell_test "$REMOTE_TOOL" "$LOCAL_TOOL"
505
506         scratchpad_test "$LOCAL_PEER_TOOL" "$REMOTE_PEER_TOOL"
507         scratchpad_test "$REMOTE_PEER_TOOL" "$LOCAL_PEER_TOOL"
508
509         message_test "$LOCAL_PEER_TOOL" "$REMOTE_PEER_TOOL"
510         message_test "$REMOTE_PEER_TOOL" "$LOCAL_PEER_TOOL"
511
512         mw_test "$LOCAL_PEER_TOOL" "$REMOTE_PEER_TOOL"
513         mw_test "$REMOTE_PEER_TOOL" "$LOCAL_PEER_TOOL"
514
515         _modprobe -r ntb_tool
516 }
517
518 function ntb_pingpong_tests()
519 {
520         LOCAL_PP="$DEBUGFS/ntb_pingpong/$LOCAL_DEV"
521         REMOTE_PP="$REMOTE_HOST:$DEBUGFS/ntb_pingpong/$REMOTE_DEV"
522
523         echo "Starting ntb_pingpong tests..."
524
525         _modprobe ntb_pingpong
526
527         pingpong_test $LOCAL_PP $REMOTE_PP
528
529         _modprobe -r ntb_pingpong
530 }
531
532 function ntb_perf_tests()
533 {
534         LOCAL_PERF="$DEBUGFS/ntb_perf/$LOCAL_DEV"
535         REMOTE_PERF="$REMOTE_HOST:$DEBUGFS/ntb_perf/$REMOTE_DEV"
536
537         echo "Starting ntb_perf tests..."
538
539         perf_test 0
540
541         if [[ $RUN_DMA_TESTS ]]; then
542                 perf_test 1
543         fi
544 }
545
546 function cleanup()
547 {
548         set +e
549         _modprobe -r ntb_tool 2> /dev/null
550         _modprobe -r ntb_perf 2> /dev/null
551         _modprobe -r ntb_pingpong 2> /dev/null
552         _modprobe -r ntb_transport 2> /dev/null
553         set -e
554 }
555
556 cleanup
557
558 if ! [[ $$DONT_CLEANUP ]]; then
559         trap cleanup EXIT
560 fi
561
562 if [ "$(id -u)" != "0" ]; then
563         echo "This script must be run as root" 1>&2
564         exit 1
565 fi
566
567 if [[ "$LIST_DEVS" == TRUE ]]; then
568         echo "Local Devices:"
569         ls -1 /sys/bus/ntb/devices
570         echo
571
572         if [[ "$REMOTE_HOST" != "" ]]; then
573                 echo "Remote Devices:"
574                 ssh $REMOTE_HOST ls -1 /sys/bus/ntb/devices
575         fi
576
577         exit 0
578 fi
579
580 if [[ "$LOCAL_DEV" == $"" ]] || [[ "$REMOTE_DEV" == $"" ]]; then
581         show_help
582         exit 1
583 fi
584
585 ntb_tool_tests
586 echo
587 ntb_pingpong_tests
588 echo
589 ntb_perf_tests
590 echo