Home | History | Annotate | Download | only in ntb
      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 (at] 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 "$LOC"/${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
    591