GNU Linux-libre 4.14.332-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 DB_BITMASK=0x7FFF
22 PERF_RUN_ORDER=32
23 MAX_MW_SIZE=0
24 RUN_DMA_TESTS=
25 DONT_CLEANUP=
26 MW_SIZE=65536
27
28 function show_help()
29 {
30         echo "Usage: $0 [OPTIONS] LOCAL_DEV REMOTE_DEV"
31         echo "Run tests on a pair of NTB endpoints."
32         echo
33         echo "If the NTB device loops back to the same host then,"
34         echo "just specifying the two PCI ids on the command line is"
35         echo "sufficient. Otherwise, if the NTB link spans two hosts"
36         echo "use the -r option to specify the hostname for the remote"
37         echo "device. SSH will then be used to test the remote side."
38         echo "An SSH key between the root users of the host would then"
39         echo "be highly recommended."
40         echo
41         echo "Options:"
42         echo "  -b BITMASK      doorbell clear bitmask for ntb_tool"
43         echo "  -C              don't cleanup ntb modules on exit"
44         echo "  -d              run dma tests"
45         echo "  -h              show this help message"
46         echo "  -l              list available local and remote PCI ids"
47         echo "  -r REMOTE_HOST  specify the remote's hostname to connect"
48         echo "                  to for the test (using ssh)"
49         echo "  -p NUM          ntb_perf run order (default: $PERF_RUN_ORDER)"
50         echo "  -w max_mw_size  maxmium memory window size"
51         echo
52 }
53
54 function parse_args()
55 {
56         OPTIND=0
57         while getopts "b:Cdhlm:r:p:w:" opt; do
58                 case "$opt" in
59                 b)  DB_BITMASK=${OPTARG} ;;
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 link_test()
131 {
132         LOC=$1
133         REM=$2
134         EXP=0
135
136         echo "Running link tests on: $(basename $LOC) / $(basename $REM)"
137
138         if ! write_file "N" "$LOC/link" 2> /dev/null; then
139                 echo "  Unsupported"
140                 return
141         fi
142
143         write_file "N" "$LOC/link_event"
144
145         if [[ $(read_file "$REM/link") != "N" ]]; then
146                 echo "Expected remote link to be down in $REM/link" >&2
147                 exit -1
148         fi
149
150         write_file "Y" "$LOC/link"
151         write_file "Y" "$LOC/link_event"
152
153         echo "  Passed"
154 }
155
156 function doorbell_test()
157 {
158         LOC=$1
159         REM=$2
160         EXP=0
161
162         echo "Running db tests on: $(basename $LOC) / $(basename $REM)"
163
164         write_file "c $DB_BITMASK" "$REM/db"
165
166         for ((i=1; i <= 8; i++)); do
167                 let DB=$(read_file "$REM/db") || true
168                 if [[ "$DB" != "$EXP" ]]; then
169                         echo "Doorbell doesn't match expected value $EXP " \
170                              "in $REM/db" >&2
171                         exit -1
172                 fi
173
174                 let "MASK=1 << ($i-1)" || true
175                 let "EXP=$EXP | $MASK" || true
176                 write_file "s $MASK" "$LOC/peer_db"
177         done
178
179         echo "  Passed"
180 }
181
182 function read_spad()
183 {
184        VPATH=$1
185        IDX=$2
186
187        ROW=($(read_file "$VPATH" | grep -e "^$IDX"))
188        let VAL=${ROW[1]} || true
189        echo $VAL
190 }
191
192 function scratchpad_test()
193 {
194         LOC=$1
195         REM=$2
196         CNT=$(read_file "$LOC/spad" | wc -l)
197
198         echo "Running spad tests on: $(basename $LOC) / $(basename $REM)"
199
200         for ((i = 0; i < $CNT; i++)); do
201                 VAL=$RANDOM
202                 write_file "$i $VAL" "$LOC/peer_spad"
203                 RVAL=$(read_spad "$REM/spad" $i)
204
205                 if [[ "$VAL" != "$RVAL" ]]; then
206                         echo "Scratchpad doesn't match expected value $VAL " \
207                              "in $REM/spad, got $RVAL" >&2
208                         exit -1
209                 fi
210
211         done
212
213         echo "  Passed"
214 }
215
216 function write_mw()
217 {
218         split_remote $2
219
220         if [[ "$REMOTE" != "" ]]; then
221                 ssh "$REMOTE" \
222                         dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true
223         else
224                 dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true
225         fi
226 }
227
228 function mw_test()
229 {
230         IDX=$1
231         LOC=$2
232         REM=$3
233
234         echo "Running $IDX tests on: $(basename $LOC) / $(basename $REM)"
235
236         write_mw "$LOC/$IDX"
237
238         split_remote "$LOC/$IDX"
239         if [[ "$REMOTE" == "" ]]; then
240                 A=$VPATH
241         else
242                 A=/tmp/ntb_test.$$.A
243                 ssh "$REMOTE" cat "$VPATH" > "$A"
244         fi
245
246         split_remote "$REM/peer_$IDX"
247         if [[ "$REMOTE" == "" ]]; then
248                 B=$VPATH
249         else
250                 B=/tmp/ntb_test.$$.B
251                 ssh "$REMOTE" cat "$VPATH" > "$B"
252         fi
253
254         cmp -n $MW_SIZE "$A" "$B"
255         if [[ $? != 0 ]]; then
256                 echo "Memory window $MW did not match!" >&2
257         fi
258
259         if [[ "$A" == "/tmp/*" ]]; then
260                 rm "$A"
261         fi
262
263         if [[ "$B" == "/tmp/*" ]]; then
264                 rm "$B"
265         fi
266
267         echo "  Passed"
268 }
269
270 function pingpong_test()
271 {
272         LOC=$1
273         REM=$2
274
275         echo "Running ping pong tests on: $(basename $LOC) / $(basename $REM)"
276
277         LOC_START=$(read_file $LOC/count)
278         REM_START=$(read_file $REM/count)
279
280         sleep 7
281
282         LOC_END=$(read_file $LOC/count)
283         REM_END=$(read_file $REM/count)
284
285         if [[ $LOC_START == $LOC_END ]] || [[ $REM_START == $REM_END ]]; then
286                 echo "Ping pong counter not incrementing!" >&2
287                 exit 1
288         fi
289
290         echo "  Passed"
291 }
292
293 function perf_test()
294 {
295         USE_DMA=$1
296
297         if [[ $USE_DMA == "1" ]]; then
298                 WITH="with"
299         else
300                 WITH="without"
301         fi
302
303         _modprobe ntb_perf run_order=$PERF_RUN_ORDER \
304                 max_mw_size=$MAX_MW_SIZE use_dma=$USE_DMA
305
306         echo "Running local perf test $WITH DMA"
307         write_file "" $LOCAL_PERF/run
308         echo -n "  "
309         read_file $LOCAL_PERF/run
310         echo "  Passed"
311
312         echo "Running remote perf test $WITH DMA"
313         write_file "" $REMOTE_PERF/run
314         echo -n "  "
315         read_file $REMOTE_PERF/run
316         echo "  Passed"
317
318         _modprobe -r ntb_perf
319 }
320
321 function ntb_tool_tests()
322 {
323         LOCAL_TOOL=$DEBUGFS/ntb_tool/$LOCAL_DEV
324         REMOTE_TOOL=$REMOTE_HOST:$DEBUGFS/ntb_tool/$REMOTE_DEV
325
326         echo "Starting ntb_tool tests..."
327
328         _modprobe ntb_tool
329
330         write_file Y $LOCAL_TOOL/link_event
331         write_file Y $REMOTE_TOOL/link_event
332
333         link_test $LOCAL_TOOL $REMOTE_TOOL
334         link_test $REMOTE_TOOL $LOCAL_TOOL
335
336         #Ensure the link is up on both sides before continuing
337         write_file Y $LOCAL_TOOL/link_event
338         write_file Y $REMOTE_TOOL/link_event
339
340         for PEER_TRANS in $(ls $LOCAL_TOOL/peer_trans*); do
341                 PT=$(basename $PEER_TRANS)
342                 write_file $MW_SIZE $LOCAL_TOOL/$PT
343                 write_file $MW_SIZE $REMOTE_TOOL/$PT
344         done
345
346         doorbell_test $LOCAL_TOOL $REMOTE_TOOL
347         doorbell_test $REMOTE_TOOL $LOCAL_TOOL
348         scratchpad_test $LOCAL_TOOL $REMOTE_TOOL
349         scratchpad_test $REMOTE_TOOL $LOCAL_TOOL
350
351         for MW in $(ls $LOCAL_TOOL/mw*); do
352                 MW=$(basename $MW)
353
354                 mw_test $MW $LOCAL_TOOL $REMOTE_TOOL
355                 mw_test $MW $REMOTE_TOOL $LOCAL_TOOL
356         done
357
358         _modprobe -r ntb_tool
359 }
360
361 function ntb_pingpong_tests()
362 {
363         LOCAL_PP=$DEBUGFS/ntb_pingpong/$LOCAL_DEV
364         REMOTE_PP=$REMOTE_HOST:$DEBUGFS/ntb_pingpong/$REMOTE_DEV
365
366         echo "Starting ntb_pingpong tests..."
367
368         _modprobe ntb_pingpong
369
370         pingpong_test $LOCAL_PP $REMOTE_PP
371
372         _modprobe -r ntb_pingpong
373 }
374
375 function ntb_perf_tests()
376 {
377         LOCAL_PERF=$DEBUGFS/ntb_perf/$LOCAL_DEV
378         REMOTE_PERF=$REMOTE_HOST:$DEBUGFS/ntb_perf/$REMOTE_DEV
379
380         echo "Starting ntb_perf tests..."
381
382         perf_test 0
383
384         if [[ $RUN_DMA_TESTS ]]; then
385                 perf_test 1
386         fi
387 }
388
389 function cleanup()
390 {
391         set +e
392         _modprobe -r ntb_tool 2> /dev/null
393         _modprobe -r ntb_perf 2> /dev/null
394         _modprobe -r ntb_pingpong 2> /dev/null
395         _modprobe -r ntb_transport 2> /dev/null
396         set -e
397 }
398
399 cleanup
400
401 if ! [[ $$DONT_CLEANUP ]]; then
402         trap cleanup EXIT
403 fi
404
405 if [ "$(id -u)" != "0" ]; then
406         echo "This script must be run as root" 1>&2
407         exit 1
408 fi
409
410 if [[ "$LIST_DEVS" == TRUE ]]; then
411         echo "Local Devices:"
412         ls -1 /sys/bus/ntb/devices
413         echo
414
415         if [[ "$REMOTE_HOST" != "" ]]; then
416                 echo "Remote Devices:"
417                 ssh $REMOTE_HOST ls -1 /sys/bus/ntb/devices
418         fi
419
420         exit 0
421 fi
422
423 if [[ "$LOCAL_DEV" == $"" ]] || [[ "$REMOTE_DEV" == $"" ]]; then
424         show_help
425         exit 1
426 fi
427
428 ntb_tool_tests
429 echo
430 ntb_pingpong_tests
431 echo
432 ntb_perf_tests
433 echo