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