Unverified Commit 78599578 authored by Karen Xie's avatar Karen Xie Committed by GitHub

Merge pull request #151 from karenx-xilinx/master

XDMA: add sanity test script for memory map mode
parents 6aa83736 8408b626
......@@ -80,6 +80,35 @@ Directory and file description:
If a AXI-ST design is independent of H2C and C2H, performance
number can be generated.
- scripts_mm/
This directory contains a set of scripts to check basic driver
loading/unloading and perform dma operations in memory-mapped
mode.
Compare with dma_memory_mapped_test.sh, the test is more
extensive with more dma size and it also utilizes fio tool in
addition to dma_from/to_device tools.
- xdma_mm.sh
top level script.
- io_sweep.sh, io.sh, unaligned
dma test via dma_from/to_device
- fio_test.sh fio_parse_result.sh
dma test via fio tool
- scripts_mm/ dependency
Some test in script_mm/ requires fio tool and python extension
Install fio:
- Centos/RHEL: yum install fio
- Ubuntu: apt install fio
Install python extension openpyxl, xlrd(version 1.2.0)
python --version
pip2 install openpyxl
pip2 install xlrd=1.2.0
Usage:
- Change directory to the driver directory.
cd xdma
......@@ -96,6 +125,12 @@ Usage:
./load_driver.sh
- Run the provided test script to generate basic DMA traffic.
./run_test.sh
For more extensive memory mapped test:
assume the XDMA FGPA is at pci slot 0000:01:00.0
cd scripts_mm
./xdma_mm.sh 0000:01:00.0 | tee /tmp/xdma_mm.log
- Check driver Version number
modinfo xdma (or)
modinfo ../xdma/xdma.ko
......
#!/bin/bash
display_help() {
echo "$0 <xdma id> <io size> <io count> <h2c #> <c2h #>"
echo -e "xdma id:\txdma[N] "
echo -e "io size:\tdma transfer size in byte"
echo -e "io count:\tdma transfer count"
echo -e "h2c #:\tnumber of h2c channels"
echo -e "c2h #:\tnumber of c2h channels"
echo
transferSize=$1
transferCount=$2
h2cChannels=$3
c2hChannels=$4
exit 1
}
if [ $# -eq 0 ]; then
display_help
fi
xid=$1
transferSz=$2
transferCount=$3
h2cChannels=$4
c2hChannels=$5
tool_path=../tools
testError=0
# Run the PCIe DMA memory mapped write read test
echo "Info: Running PCIe DMA memory mapped write read test"
echo " transfer size: $transferSize"
echo " transfer count: $transferCount"
echo -e "\ttransfer size: $transferSz, count: $transferCount"
# Write to all enabled h2cChannels in parallel
if [ $h2cChannels -gt 0 ]; then
# Loop over four blocks of size $transferSize and write to them (in parallel where possible)
for ((i=0; i<=3; i++))
do
addrOffset=$(($transferSize * $i))
# Loop over four blocks of size $transferSz and write to them
for ((i=0; i<=3; i++)); do
addrOffset=$(($transferSz * $i))
curChannel=$(($i % $h2cChannels))
echo "Info: Writing to h2c channel $curChannel at address offset $addrOffset."
$tool_path/dma_to_device -d /dev/xdma0_h2c_${curChannel} -f data/datafile${i}_4K.bin -s $transferSize -a $addrOffset -c $transferCount &
# If all channels have active transactions we must wait for them to complete
echo "Info: Writing to h2c channel $curChannel at address" \
"offset $addrOffset."
$tool_path/dma_to_device -d /dev/${xid}_h2c_${curChannel} \
-f data/datafile${i}_4K.bin -s $transferSz \
-a $addrOffset -c $transferCount &
# If all channels have active transactions we must wait for
# them to complete
if [ $(($curChannel+1)) -eq $h2cChannels ]; then
echo "Info: Wait for current transactions to complete."
wait
......@@ -35,17 +53,21 @@ wait
# Read from all enabled c2hChannels in parallel
if [ $c2hChannels -gt 0 ]; then
# Loop over four blocks of size $transferSize and read from them (in parallel where possible)
for ((i=0; i<=3; i++))
do
addrOffset=$(($transferSize * $i))
# Loop over four blocks of size $transferSz and read from them
for ((i=0; i<=3; i++)); do
addrOffset=$(($transferSz * $i))
curChannel=$(($i % $c2hChannels))
rm -f data/output_datafile${i}_4K.bin
echo "Info: Reading from c2h channel $curChannel at address offset $addrOffset."
$tool_path/dma_from_device -d /dev/xdma0_c2h_${curChannel} -f data/output_datafile${i}_4K.bin -s $transferSize -a $addrOffset -c $transferCount &
# If all channels have active transactions we must wait for them to complete
echo "Info: Reading from c2h channel $curChannel at " \
"address offset $addrOffset."
$tool_path/dma_from_device -d /dev/${xid}_c2h_${curChannel} \
-f data/output_datafile${i}_4K.bin -s $transferSz \
-a $addrOffset -c $transferCount &
# If all channels have active transactions we must wait for
# them to complete
if [ $(($curChannel+1)) -eq $c2hChannels ]; then
echo "Info: Wait for the current transactions to complete."
echo "Info: Wait for current transactions to complete."
wait
fi
done
......@@ -56,23 +78,28 @@ wait
# Verify that the written data matches the read data if possible.
if [ $h2cChannels -eq 0 ]; then
echo "Info: No data verification was performed because no h2c channels are enabled."
echo "Info: No data verification was performed because no h2c " \
"channels are enabled."
elif [ $c2hChannels -eq 0 ]; then
echo "Info: No data verification was performed because no c2h channels are enabled."
echo "Info: No data verification was performed because no c2h " \
"channels are enabled."
else
echo "Info: Checking data integrity."
for ((i=0; i<=3; i++))
do
cmp data/output_datafile${i}_4K.bin data/datafile${i}_4K.bin -n $transferSize
for ((i=0; i<=3; i++)); do
cmp data/output_datafile${i}_4K.bin data/datafile${i}_4K.bin \
-n $transferSz
returnVal=$?
if [ ! $returnVal == 0 ]; then
echo "Error: The data written did not match the data that was read."
echo " address range: $(($i*$transferSize)) - $((($i+1)*$transferSize))"
echo " write data file: data/datafile${i}_4K.bin"
echo " read data file: data/output_datafile${i}_4K.bin"
echo "Error: The data written did not match the data" \
" that was read."
echo -e "\taddress range: " \
"$(($i*$transferSz)) - $((($i+1)*$transferSz))"
echo -e "\twrite data file: data/datafile${i}_4K.bin"
echo -e "\tread data file: data/output_datafile${i}_4K.bin"
testError=1
else
echo "Info: Data check passed for address range $(($i*$transferSize)) - $((($i+1)*$transferSize))."
echo "Info: Data check passed for address range " \
"$(($i*$transferSz)) - $((($i+1)*$transferSz))"
fi
done
fi
......
File mode changed from 100644 to 100755
#!/bin/bash
# set -x
display_help() {
echo "$0 [interrupt mode]"
echo "interrupt mode: optional"
echo "0: auto"
echo "1: MSI"
echo "2: Legacy"
echo "3: MSIx"
echo "4: do not use interrupt, poll mode only"
exit;
}
if [ "$1" == "help" ]; then
display_help
fi;
interrupt_selection=$1
echo "interrupt_selection $interrupt_selection."
device_id=903f
# Make sure only root can run our script
if [[ $EUID -ne 0 ]]; then
......@@ -10,20 +30,55 @@ fi
lsmod | grep xdma
if [ $? -eq 0 ]; then
rmmod xdma
if [ $? -ne 0 ]; then
echo "rmmod xdma failed: $?"
exit 1
fi
fi
echo -n "Loading xdma driver..."
# Use the following command to Load the driver in the default
# or interrupt drive mode. This will allow the driver to use
# interrupts to signal when DMA transfers are completed.
insmod ../xdma/xdma.ko
# Use the following command to Load the driver in Polling
# mode rather than than interrupt mode. This will allow the
# driver to use polling to determ when DMA transfers are
# completed.
#insmod ../xdma/xdma.ko poll_mode=1
if [ ! $? == 0 ]; then
echo "Error: Kernel module did not load properly."
echo -n "Loading driver..."
case $interrupt_selection in
"0")
echo "insmod xdma.ko interrupt_mode=1 ..."
ret=`insmod ../xdma/xdma.ko interrupt_mode=0`
;;
"1")
echo "insmod xdma.ko interrupt_mode=2 ..."
ret=`insmod ../xdma/xdma.ko interrupt_mode=1`
;;
"2")
echo "insmod xdma.ko interrupt_mode=3 ..."
ret=`insmod ../xdma/xdma.ko interrupt_mode=2`
;;
"3")
echo "insmod xdma.ko interrupt_mode=4 ..."
ret=`insmod ../xdma/xdma.ko interrupt_mode=3`
;;
"4")
echo "insmod xdma.ko poll_mode=1 ..."
ret=`insmod ../xdma/xdma.ko poll_mode=1`
;;
*)
intp=`sudo lspci -d :${device_id} -v | grep -o -E "MSI-X"`
intp1=`sudo lspci -d :${device_id} -v | grep -o -E "MSI:"`
if [[ ( -n $intp ) && ( $intp == "MSI-X" ) ]]; then
echo "insmod xdma.ko interrupt_mode=0 ..."
ret=`insmod ../xdma/xdma.ko interrupt_mode=0`
elif [[ ( -n $intp1 ) && ( $intp1 == "MSI:" ) ]]; then
echo "insmod xdma.ko interrupt_mode=1 ..."
ret=`insmod ../xdma/xdma.ko interrupt_mode=1`
else
echo "insmod xdma.ko interrupt_mode=2 ..."
ret=`insmod ../xdma/xdma.ko interrupt_mode=2`
fi
;;
esac
if [ ! $ret == 0 ]; then
echo "Error: xdma driver did not load properly"
echo " FAILED"
exit 1
fi
......@@ -42,4 +97,4 @@ else
exit 1
fi
echo " DONE"
echo "DONE"
File mode changed from 100644 to 100755
......@@ -20,11 +20,18 @@ transferCount=1
# Determine if the core is Memory Mapped or Streaming
isStreaming=0
h2cChannels=0
for ((i=0; i<=3; i++))
do
for ((i=0; i<=3; i++)); do
v=`$tool_path/reg_rw /dev/xdma0_control 0x0${i}00 w`
returnVal=$?
if [ $returnVal -ne 0 ]; then
break;
fi
#v=`echo $v | grep -o '): 0x[0-9a-f]*'`
statusRegVal=`$tool_path/reg_rw /dev/xdma0_control 0x0${i}00 w | grep "Read.*:" | sed 's/Read.*: 0x\([a-z0-9]*\)/\1/'`
channelId=${statusRegVal:0:3}
streamEnable=${statusRegVal:4:1}
if [ $channelId == "1fc" ]; then
h2cChannels=$((h2cChannels + 1))
if [ $streamEnable == "8" ]; then
......@@ -33,20 +40,28 @@ do
fi
done
echo "Info: Number of enabled h2c channels = $h2cChannels"
# Find enabled c2hChannels
c2hChannels=0
for ((i=0; i<=3; i++))
do
$tool_path/reg_rw /dev/xdma0_control 0x1${i}00 w | grep "Read.*: 0x1fc" > /dev/null
for ((i=0; i<=3; i++)); do
v=`$tool_path/reg_rw /dev/xdma0_control 0x1${i}00 w`
returnVal=$?
if [ $returnVal -eq 0 ]; then
c2hChannels=$((c2hChannels + 1))
if [ $streamEnable == "8" ]; then
isStreaming=1
if [ $returnVal -ne 0 ]; then
break;
fi
$tool_path/reg_rw /dev/xdma0_control 0x1${i}00 w | grep "Read.*: 0x1fc" > /dev/null
statusRegVal=`$tool_path/reg_rw /dev/xdma0_control 0x1${i}00 w | grep "Read.*:" | sed 's/Read.*: 0x\([a-z0-9]*\)/\1/'`
channelId=${statusRegVal:0:3}
# there will NOT be a mix of MM & ST channels, so no need to check
# for streaming enabled
if [ $channelId == "1fc" ]; then
c2hChannels=$((c2hChannels + 1))
fi
done
echo "Info: Number of enabled c2h channels = $c2hChannels"
# Report if the PCIe DMA core is memory mapped or streaming
if [ $isStreaming -eq 0 ]; then
echo "Info: The PCIe DMA core is memory mapped."
......@@ -65,7 +80,7 @@ testError=0
if [ $isStreaming -eq 0 ]; then
# Run the PCIe DMA memory mapped write read test
./dma_memory_mapped_test.sh $transferSize $transferCount $h2cChannels $c2hChannels
./dma_memory_mapped_test.sh xdma0 $transferSize $transferCount $h2cChannels $c2hChannels
returnVal=$?
if [ $returnVal -eq 1 ]; then
testError=1
......
#!/bin/bash
##############################################################
#
# parse the fio result directory generated by the fio_test.sh
#
##############################################################
function parse_iops() {
eval str="$1"
value=$(echo $str | awk -F "," '{print $1}' | awk -F "=" '{print $2}')
unit=$(echo $value | awk -F '[0-9,.]*' '{print $2}')
value=$(echo $value | sed 's/[^0-9,.]*//g')
# echo -n " iops: ${value}${unit}"
if [ -z "$unit" ];then
value=$(echo "scale=4; $value/1000" | bc -l)
elif [[ "$unit" == "k" ]];then
value=$(echo "scale=4; $value" | bc -l)
elif [[ "$unit" == "m" ]];then
value=$(echo "scale=4; $value*1000" | bc -l)
else
echo "iops: $value$unit, unknown unit $unit."
fi
}
function parse_bw() {
eval str="$1"
value=$(echo $str | awk -F "," '{print $2}')
value=$(echo $value | awk -F "[(,)]" '{print $2}')
unit=$(echo $value | awk -F '[0-9,.]*' '{print $2}')
value=$(echo $value | sed 's/[^0-9,.]*//g')
# echo -n " bw: ${value}${unit}"
if [[ "$unit" == "kB/s" ]];then
value=$(echo "scale=4; $value" | bc -l)
elif [[ "$unit" == "MB/s" ]];then
value=$(echo "scale=4; $value*1024" | bc -l)
elif [[ "$unit" == "gB/s" ]];then
value=$(echo "scale=4; $value*1024*1024" | bc -l)
else
echo "bw: $value$unit, unknown unit $unit."
fi
}
function parse_latency() {
eval str="$1"
value=$(echo $str | awk -F "," '{print $3}' | awk -F "=" '{print $2}')
unit=$(echo $str | awk -F "[(,)]" '{print $2}')
# echo -n " latency: ${value}${unit}"
if [[ "$unit" == "usec" ]];then
value=$(echo "scale=4; $value" | bc -l)
elif [[ "$unit" == "sec" ]];then
value=$(echo "scale=6; $value*1000000" | bc -l)
elif [[ "$unit" == "msec" ]];then
value=$(echo "scale=6; $value*1000" | bc -l)
elif [[ "$unit" == "nsec" ]];then
value=$(echo "scale=4; $value/1000" | bc -l)
else
echo "latency: $value$unit, unknown unit $unit."
fi
}
##############
# Main body
##############
if [ $# -lt 1 ];then
echo "$0 <result directory>"
exit 1
fi
dir=$1
if [[ ! -d $dir ]];then
echo "$dir does NOT exist."
exit 1
fi
declare -a lat_array
resfname=result.csv
rm -f $dir/$resfname
channel_list=`ls $dir`
for channels in $channel_list; do
cd $dir/$channels
rm -f $dir/$channels/$resfname
iodir_list=`ls`
for iodir in $iodir_list; do
cd $dir/$channels/$iodir
rm -f $resfname
echo > $resfname
fio_list=`ls fio*.log`
for fname in $fio_list; do
# fio result file format fio_<io size>_t<# threads>.log
sz=$(echo $fname | cut -d. -f1 | cut -d_ -f2)
thread=$(echo $fname | cut -d. -f1 | cut -d_ -f3)
thread=$(echo $thread | sed 's/[^0-9]*//')
#echo "$dir/$channels/$iodir/$fname:"
value=0;
unit=0
if [ "$iodir" == "h2c" ]; then
#echo -n "$channels h2c:io $sz thread $thread "
ln=$(grep "write:" $fname)
parse_iops "\${ln}"
echo -n $sz,$thread,$value, >> $resfname
parse_bw "\${ln}"
echo -n $value, >> $resfname
ln=$(grep clat $fname | grep avg)
parse_latency "\${ln}"
echo "$value,,,," >> $resfname
elif [ "$iodir" == "c2h" ]; then
#echo -n "$channels c2h:io $sz thread $thread "
ln=$(grep "read:" $fname)
parse_iops "\${ln}"
echo -n $sz,$thread,,,,$value, >> $resfname
parse_bw "\${ln}"
echo -n $value, >> $resfname
ln=$(grep clat $fname | grep avg)
parse_latency "\${ln}"
echo "$value," >> $resfname
elif [ "$iodir" == "bi" ]; then
#echo -n "$channels bidir:io $sz thread $thread "
readarray lat_array < <(grep clat $fname | \
grep avg)
# h2c
#echo -n "h2c "
ln=$(grep "write:" $fname)
parse_iops "\${ln}"
echo -n $sz,$thread,$value, >> $resfname
parse_bw "\${ln}"
echo -n $value, >> $resfname
parse_latency "\${lat_array[1]}"
echo -n $value, >> $resfname
#c2h
#echo -n " c2h "
ln=$(grep "read:" $fname)
parse_iops "\${ln}"
echo -n $value, >> $resfname
parse_bw "\${ln}"
echo -n $value, >> $resfname
parse_latency "\${lat_array[0]}"
echo $value >> $resfname
fi
done
done
done
echo
cd $dir
for channels in $channel_list; do
cd $dir/$channels
echo -n "iosize(B)","Thread #", > $resfname
echo -n "H2C IOPS(K)","H2C BW(KB/s)","H2C Latency(usec)," >> $resfname
echo "C2H IOPS(K)","C2H BW(KB/s)","C2H Latency(usec)," >> $resfname
for iodir in $iodir_list; do
cat $iodir/$resfname | sort -t, -k1,1n >> $resfname
done
echo "$channels channel results: $dir/$channels/$resfname"
done
#!/bin/bash
display_help() {
echo -n "$0 <xdma id> <# ch> <io sz> < runtime> <iodir> <thread #> "
echo "<logdir>"
echo -e "\t<xdma id>: xdmaN"
echo -e "\t<dir>: io direction <h2c|c2h|bi>"
echo -e "\t<# ch>: fio --num_ch"
echo -e "\t<io sz>: fio --io_size"
echo -e "\t<runtime>: fio --runtime"
echo -e "\t<thread #>: fio --threads"
echo -e "\t<logdir>: log directory"
exit;
}
####################
#
# main body
#
####################
if [ $# -ne 7 ]; then
display_help
fi
xid=$1
iodir=$2
num_ch=$3
io_size=$4
runtime=$5
threads=$6
logdir=$7
outfile="${logdir}/fio_${io_size}_t${threads}.log"
exec_cmd=
op_cmd=
engine=sync
cmd_common="fio --allow_file_create=0 --ioengine=${engine} --zero_buffers"
cmd_common="$cmd_common --mem=mmap --runtime=${runtime} --time_based"
for ((i = 0; i < num_ch; i++)); do
if [ ${iodir} == bi ]; then
op_cmd="${op_cmd} --name=write${i} --bs=${io_size}"
op_cmd="${op_cmd} --size=${io_size} --offset=0 --rw=write"
op_cmd="${op_cmd} --filename=/dev/xdma0_h2c_${i}"
op_cmd="${op_cmd} --numjobs=${threads} --group_reporting"
op_cmd="${op_cmd} --name=read${i} --bs=${io_size}"
op_cmd="${op_cmd} --size=${io_size} --offset=0 --rw=read "
op_cmd="${op_cmd} --filename=/dev/xdma0_c2h_${i}"
op_cmd="${op_cmd} --numjobs=${threads} --group_reporting"
elif [ ${iodir} == h2c ]; then
op_cmd="${op_cmd} --name=write${i} --bs=${io_size}"
op_cmd="${op_cmd} --size=${io_size} --offset=0 --rw=write"
op_cmd="${op_cmd} --filename=/dev/xdma0_${iodir}_${i}"
op_cmd="${op_cmd} --numjobs=${threads} --group_reporting"
else
op_cmd="${op_cmd} --name=read${i} --bs=${io_size}"
op_cmd="${op_cmd} --size=${io_size} --offset=0 --rw=read"
op_cmd="${op_cmd} --filename=/dev/xdma0_${iodir}_${i}"
op_cmd="${op_cmd} --numjobs=${threads} --group_reporting"
fi
done
exec_cmd="${cmd_common}${op_cmd}"
echo -e "${exec_cmd}\n\n" > ${outfile}
${exec_cmd} >> ${outfile} &
pid=$!
wait $pid
#!/bin/sh
tool_path=../../tools
logdir=/tmp
if [ $# -lt 9 ]; then
echo -ne "$0 <dmesg log 0|1> <data check 0|1> <sz> <address> <offset> "
echo "<xid> <h2c channel> <c2h channel> <log dir> [data file]"
echo -e "\t<dmesg log>: log test into dmesg"
echo -e "\t<data check 0|1>: read data back and compare"
echo -e "\t<sz>: dma transfer size"
echo -e "\t<address>: "
echo -e "\t<offset>: "
echo -e "\t<xdma id>: xdma<N>"
echo -e "\t<h2c channel>: dma h2c channel #, 0-based"
echo -e "\t\tif >= 4, no traffic will be ran"
echo -e "\t<c2h channel>: dma c2h channel #, 0-based"
echo -e "\t if channel # >= 4 NO dma will be performed"
echo -e "\t\tif >= 4, no traffic will be ran"
echo -e "\t<log dir>: temp. log directory"
echo -e "\t[data file]: data file, size >= io size, "
echo -e "\t optional if <data check>=0"
exit
fi
dmesg=$1
data_check=$2
sz=$3
address=$4
offset=$5
xid=$6
h2cno=$7
c2hno=$8
logdir=$9
if [ $# -gt 9 ]; then
datafile=${10}
fi
if [ ! -d "$logdir" ]; then
mkdir -p $logdir
fi
echo -en "\n===>$0 $xid, channel $h2cno:$c2hno, io $sz, addr $address, "
echo "off $offset, data: $datafile, integrity $data_check, dmesg $dmesg."
if [ "$h2cno" -ge 4 ] && [ "$c2hno" -ge 4 ]; then
echo "$0: NO valid dma channel $h2cno:$c2hno"
exit 1
fi
h2c_cmd="$tool_path/dma_to_device -d /dev/${xid}_h2c_${h2cno}"
c2h_cmd="$tool_path/dma_from_device -d /dev/${xid}_c2h_${c2hno}"
if [ "$address" -ne "0" ]; then
h2c_cmd="$h2c_cmd -a $address"
c2h_cmd="$c2h_cmd -a $address"
fi
if [ "$offset" -ne "0" ]; then
h2c_cmd="$h2c_cmd -o $offset"
c2h_cmd="$c2h_cmd -o $offset"
fi
if [ "$data_check" -ne 0 ]; then
if [ -z "$datafile" ]; then
echo "no datafile specified"
exit 2
fi
if [ ! -s "$datafile" ]; then
echo "missing datafile: $datafile ..."
exit 3
fi
h2c_fname="$logdir/$xid-h2c${h2cno}-io$sz-o$offset-a$address.bin"
rm -f $h2c_fname
h2c_cmd="$h2c_cmd -f $datafile -w $h2c_fname"
c2h_fname="$logdir/$xid-c2h${c2hno}-io$sz-o$offset-a$address.bin"
rm -f $c2h_fname
c2h_cmd="$c2h_cmd -f $c2h_fname"
fi
if [ "$h2cno" -lt 4 ]; then
if [ "$dmesg" -ne "0" ]; then
echo "$h2c_cmd -s $sz -c 1" > /dev/kmsg
fi
echo "$h2c_cmd -s $sz -c 1 ..." > \
${logdir}/h2c-io${sz}-o${offset}-a${address}.log
out=`$h2c_cmd -s $sz -c 1`
echo $out >> ${logdir}/h2c-io${sz}-o${offset}-a${address}.log
if [ "$?" -ne "0" ]; then
echo -e "\tH2C${h2cno}: io $sz, ERROR $?."
exit 4
fi
fi
if [ "$c2hno" -lt 4 ]; then
if [ "$dmesg" -ne "0" ]; then
echo "$c2h_cmd -s $sz -c 1 ..." > /dev/kmsg
fi
echo "$c2h_cmd -s $sz -c 1 ..." > \
${logdir}/c2h-io${sz}-o${offset}-a${address}.log
out=`./$c2h_cmd -s $sz -c 1`
echo $out >> ${logdir}/c2h-io${sz}-o${offset}-a${address}.log
if [ "$?" -ne "0" ]; then
echo -e "\tC2H$channel: io $sz, ERROR $?."
exit 5
fi
fi
if [ "$data_check" -eq 0 ]; then
# no data integrity check needs to be done
exit 0
fi
#md5sum $c2h_fname
#md5sum $h2c_fname
diff -q $c2h_fname $h2c_fname > /dev/null
if [ "$?" -eq "1" ]; then
echo -e "\t$xid $h2cno:$c2hno: io $sz, addr $address, off $offset," \
"data integrity FAILED!."
exit 6
fi
echo -e "\t$xid $h2cno:$c2hno: io $sz, addr $address, off $offset, data match."
rm -f $c2h_fname $h2c_fname
exit 0
#!/bin/sh
delay=5
if [ $# -lt 9 ]; then
echo -ne "$0: <xid> <h2c channel> <c2h channel> <address> <offset> "
echo "<io min> <io max> <data check> <dmesg log> [log dir]"
echo -e "\t<xdma id>: xdma<N>"
echo -e "\th2c channel: H2C channel #, 0-based"
echo -e "\tc2h channel: C2H channel #, 0-based"
echo -e "\t<address>: "
echo -e "\t<offset>: "
echo -e "\t<io min>,<io max>: dma size in byte, io size start from"
echo -e "\t\tio_min, double each time until reaches io_max"
echo -e "\t<data check>: read back the data and compare, 0|1"
echo -e "\t<dmesg log>: log test info. into dmesg, 0|1"
exit 1
fi
xid=$1
h2cno=$2
c2hno=$3
addr=$4
off=$5
io_min=$6
io_max=$7
data_check=$8
dmesg=$9
tmpdir="/tmp/${xid}_h2c${h2cno}c2h${c2hno}"
echo "====>$0 $xid $h2cno:$c2hno, $io_min~$io_max @$addr $off, $data_check, $tmpdir"
if [ "$dmesg" -ne 0 ]; then
echo "$0 $xid $h2cno:$c2hno, $io_min~$io_max @$addr $off, $tmpdir..." \
>> /dev/kmsg
fi
if [ ! -d "$tmpdir" ]; then
mkdir -p $tmpdir
fi
rm -rf ${tmpdir}/*
if [ "$data_check" -ne 0 ]; then
cnt=$(($io_max / 1024))
if [ "$cnt" -eq 0 ]; then
cnt=1
fi
datafile="$tmpdir/datafile-$cnt-K"
cnt=$(($cnt / 65536))
if [ "$cnt" -eq "0" ]; then
cnt=1
fi
if [ ! -f "$datafile" ]; then
echo "creating datafile: $datafile ..."
let cnt=cnt+1
dd if=/dev/urandom of=$datafile bs=64M count=$cnt \
iflag=fullblock
fi
fi
date
sz=$io_min
while [ "$sz" -le "$io_max" ]; do
./io.sh $dmesg $data_check $sz $addr $off $xid $h2cno $c2hno $tmpdir \
$datafile
if [ "$?" -ne "0" ]; then
#echo -e "\t$xid $h2cno:$c2hno, $sz FAILED"
exit 2
fi
if [ "$sz" -eq "$io_max" ]; then
break
fi
sz=$(($sz * 2))
if [ "$sz" -gt "$io_max" ]; then
sz=$io_max
fi
if [ "$delay" -ne "0" ]; then
sleep $delay
fi
done
echo "====>$0 $xid $h2cno:$c2hno, $io_min~$io_max @$addr $off COMPLETED!"
exit 0
tool_path=../../tools
ERR=255
############################
#
# utility functions
#
############################
# Make sure only root can run the script
function check_if_root() {
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" 1>&2
exit $ERR
fi
}
function check_cmd_exist() {
which $1 > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "$1 NOT found on the system"
return $ERR
fi
return 0
}
# check_rc <error code> <string> <exit if error 0|1>
function check_rc() {
local rc=$1
if [ $rc -ne 0 ]; then
echo "ERR! $2 failed $rc."
if [ $3 -gt 0 ]; then
exit $rc
fi
fi
}
# check_dma_dir <h2c|c2h|bi>
function check_dma_dir() {
if [ "$1" != h2c ] && [ "$1" != c2h ] && [ "$1" != bi ]; then
echo "bad dma direction: $1."
exit $ERR
fi
}
# check_driver_loaded <bdf>
function check_driver_loaded() {
local bdf=$1
lspci -s $bdf -v | grep driver | grep xdma | wc -l
}
# bdf_to_xdmaid <bdf>
function bdf_to_xdmaid() {
cd /sys/bus/pci/devices/$1/
if [ -d "xdma" ]; then
cd xdma/
ls | grep control | cut -d'_' -f1
fi
}
# cfg_reg_read <xid> <reg addr>
function cfg_reg_read() {
local v=`$tool_path/reg_rw /dev/$1_control $2 w | grep "Read.*:" | sed 's/Read.*: 0x\([a-z0-9]*\)/\1/'`
if [ -z "$v" ]; then
return $ERR
else
echo $v
return 0
fi
}
# cfg_reg_write <xid> <reg addr> <reg value>
function cfg_reg_write() {
local v=`$tool_path/reg_rw /dev/$1_control $2 w $3`
return $?
}
# get_streaming_enabled <xid>
function get_streaming_enabled() {
local v=`cfg_reg_read $1 0`
local rc=$?
if [ $rc -ne 0 ]; then
return $rc
fi
local id=${v:0:3}
local stream=${v:4:1}
local st=0
if [ "$id" == "1fc" ]; then
if [ "$stream" == "8" ]; then
st=1
fi
else
echo "$1 reg 0, $v, bad id $id, $stream."
return $ERR
fi
echo $st
return 0
}
# get_h2c_channel_count <xid>
function get_h2c_channel_count() {
local cnt=0
for ((i=0; i<=3; i++)); do
local regval=`cfg_reg_read $1 0x0${i}00`
if [ $? -ne 0 ]; then
break
fi
local id=${regval:0:3}
if [ "$id" == "1fc" ]; then
cnt=$((cnt + 1))
fi
done
echo $cnt
return 0
}
# get_c2h_channel_count <xid>
function get_c2h_channel_count() {
local cnt=0
for ((i=0; i<=3; i++)); do
local regval=`cfg_reg_read $1 0x1${i}00`
if [ $? -ne 0 ]; then
break
fi
local id=${regval:0:3}
if [ "$id" == "1fc" ]; then
cnt=$((cnt + 1))
fi
done
echo $cnt
return 0
}
#############################################################################
#
# test cases
#
#############################################################################
# xdma config bar access
# TC_cfg_reg_rw <xid>
function TC_cfg_reg_rw() {
local reg=0x301c
local val=0
cfg_reg_write $reg $val
local v=$(cfg_reg_read $reg)
let "v = $v + 0"
if [ $v -eq $val ]; then
echo "ERR ${FUNCNAME[0]} reg value mismatch $v, exp $val"
exit $ERR
fi
cfg_reg_write $reg 1
}
# TC_dma_chrdev_open_close <xid> <h2c count> <c2h count>
function TC_dma_chrdev_open_close() {
local xid=$1
local h2c_count=$2
local c2h_count=$3
local err=0
for ((i=0; i<$h2c_count; i++)); do
$tool_path/test_chrdev /dev/${xid}_h2c_$i > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "${FUNCNAME[0]} ${xid}_h2c_$i FAILED"
exit 1
fi
done
for ((i=0; i<$c2h_count; i++)); do
$tool_path/test_chrdev /dev/${xid}_c2h_$i > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "${FUNCNAME[0]} ${xid}_c2h_$i FAILED"
exit 2
fi
done
}
#!/bin/sh
##########################
#
# preset test parameters:
#
##########################
# dma io size
io_list="1 10 127 128 1021 1022 1023 1024 4095 4096 4097 4098 4099 8189 8190 8191 8192"
io_max=8192
# offset
offset_list="1 2 3 4 2045 2046 2047 2048 2049 4091 4092 4093 4094 4095"
# starting address
address=0
# delay(sleep) before moving on to the next channel, if applicable
delay=2
##########################
#
# main
#
##########################
if [ $# -lt 5 ]; then
echo "$0: <xid> <h2c channel> <c2h channel> <data check> <dmesg log>"
echo -e "\t<xid>: xdma<N>"
echo -e "\t<h2c channel>: H2C channel #, 0-based"
echo -e "\t<c2h channel>: C2H channel #, 0-based"
echo -e "\t<data check>: read back the data and compare, 0|1"
echo -e "\t<dmesg log>: log test info. into dmesg, 0|1"
exit
fi
xid=$1
h2cno=$2
c2hno=$3
data_check=$4
dmesg=$5
tmpdir="/tmp/${xid}_h2c${h2cno}_c2h${c2hno}_unaligned"
echo "====>$0 $xid $h2cno:$c2hno, $data_check,$dmesg, $tmpdir"
if [ "$dmesg" -ne 0 ]; then
echo "$0 $xid $h2cno:$c2hno, $tmpdir..." >> /dev/kmsg
fi
if [ ! -d "$tmpdir" ]; then
mkdir -p $tmpdir
fi
rm -rf $tmpdir/*
# generate data file, minimum 64MB
cnt=$(($io_max / 1024))
if [ "$cnt" -eq "0" ]; then
cnt=1
fi
datafile="$tmpdir/datafile-$cnt-K"
cnt=$(($cnt / 65536))
if [ "$cnt" -eq "0" ]; then
cnt=1
fi
if [ ! -f "$datafile" ]; then
echo "creating datafile: $datafile ..."
let cnt=cnt+1
dd if=/dev/urandom of=$datafile bs=64M count=$cnt iflag=fullblock
fi
echo
date
echo "====>$0: $xid $h2cno:$c2hno, addr $address ..." > /dev/kmsg
echo "$0: $xid $h2cno:$c2hno, addr $address ..." > /dev/kmsg
for io in $io_list; do
for offset in $offset_list; do
./io.sh $dmesg $data_check $io $address $offset $xid \
$h2cno $c2hno $tmpdir $datafile
if [ "$?" -ne "0" ]; then
echo -e "\t$xid $h2cno:$c2hno, $io, off $offset FAILED!"
exit 2
fi
done
if [ "$delay" -ne "0" ]; then
sleep $delay
fi
done
date
echo "====>$0: $xid $h2cno:$c2hno, addr $address COMPLETED!"
exit 0
#!/bin/bash
####################
#
# test settings
#
####################
outdir="/tmp"
driver_modes="0 4" ;# driver mode
address=0
offset=0
io_min=64
io_max=$((1 << 30)) ;# 1GB
delay=5 ;# delay between each test
fio_time=30
fio_thread_list="4 8"
fio_iodir_list="h2c c2h bi"
####################
#
# main body
#
####################
display_help() {
echo "$0 <xdma BDF> [log dir]"
echo -e "xdma BDF:\tfpga pci device specified in the format of "
echo -e "\t\t\t<domain>:<bus>:<device>.<func>"
echo -e "log dir:\toptional, default to /tmp"
echo
exit;
}
if [ $# -eq 0 ]; then
display_help
fi
bdf=$1
if [ $# -gt 1 ]; then
outdir=$2
fi
echo "xdma bdf:$bdf, outdir: $outdir"
source ./libtest.sh
check_if_root
curdir=$PWD
for dm in $driver_modes; do
echo -e "\n\n====> xdma mode $dm ...\n"
cd ../../tests
./load_driver.sh $dm
if [ $? -ne 0 ]; then
echo "load_driver.sh failed: $?"
exit 1
fi
cd $curdir
xid=$(bdf_to_xdmaid $bdf)
if [ ! -n "$xid" ]; then
echo "$bdf, no correponding xdma found, driver mode $dm."
exit 1
fi
echo "xdma id: $xid."
h2c_channels=$(get_h2c_channel_count $xid)
check_rc $? get_h2c_channel_count 1
c2h_channels=$(get_c2h_channel_count $xid)
check_rc $? get_c2h_channel_count 1
channel_pairs=$(($h2c_channels < $c2h_channels ? \
$h2c_channels : $c2h_channels))
echo "channels: $h2c_channels,$c2h_channels, pair $channel_pairs"
if [ "$channel_pairs" -eq 0 ]; then
echo "Error: 0 DMA channel pair: $h2c_channels,$c2h_channels."
exit 1
fi
# test cdev
TC_dma_chrdev_open_close $xid $h2c_channels $c2h_channels
#
# run 1 channel at a time
#
for i in {1..80}; do echo -n =; done
echo -e "\nSingle H2C Channel $h2c_channels io test ...\n"
for ((i=0; i<$h2c_channels; i++)); do
# aligned: no data integrity check
./io_sweep.sh $xid $i 4 $address $offset \
$io_min $io_max 0 1
check_rc $? "h2c-$i" 1
./unaligned.sh $xid $i 4 0 1
check_rc $? "h2c-$i-unaligned" 1
done
for i in {1..80}; do echo -n =; done
echo -e "\nSingle C2H Channel $c2h_channels io test ...\n"
for ((i=0; i<$c2h_channels; i++)); do
./io_sweep.sh $xid 4 $i $address $offset \
$io_min $io_max 0 1
check_rc $? "c2h-$i" 1
./unaligned.sh $xid 4 $i 0 1
check_rc $? "c2h-$i-unaligned" 1
done
for i in {1..80}; do echo -n =; done
echo -e "\nh2c/c2h pair $channel_pairs io test with data check ...\n"
for ((i=0; i<$channel_pairs; i++)); do
./io_sweep.sh $xid $i $i $address $offset $io_min $io_max 1 1
check_rc $? "pair-$i" 1
./unaligned.sh $xid $i $i 1 1
check_rc $? "pair-$i-unaligned" 1
done
#
# fio test
#
check_cmd_exist fio
if [ "$?" -ne 0 ]; then
echo "fio test skipped"
continue
fi
for i in {1..80}; do echo -n =; done
echo -e "\nfio test ...\n"
#
# result directory structure:
# - <outdir/fio>
# - <number of channels>
# - <direction: h2c c2h bi>
#
for ((i=1; i<=$channel_pairs; i++)); do
for iodir in $fio_iodir_list; do
out=${outdir}/fio_d${dm}/${i}/${iodir}
mkdir -p ${out}
rm -rf ${out}/*
for (( sz=$io_min; sz<=$io_max; sz=$(($sz*2)) )); do
for thread in $fio_thread_list; do
name=${sz}_t${thread}
echo "$iodir $i: $name ..."
./fio_test.sh $xid $iodir $i ${sz} \
${fio_time} ${thread} ${out}
done
done
done
done
./fio_parse_result.sh ${outdir}/fio_d${dm}
echo -e "\n\n====> xdma mode $dm COMPLETED.\n"
done
echo "$0: COMPLETED."
CC ?= gcc
all: reg_rw dma_to_device dma_from_device performance
all: reg_rw dma_to_device dma_from_device performance test_chrdev
dma_to_device: dma_to_device.o
$(CC) -lrt -o $@ $< -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D_LARGE_FILE_SOURCE
......@@ -14,9 +14,11 @@ performance: performance.o
reg_rw: reg_rw.o
$(CC) -o $@ $<
test_chrdev: test_chrdev.o
$(CC) -o $@ $<
%.o: %.c
$(CC) -c -std=c99 -o $@ $< -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D_LARGE_FILE_SOURCE
clean:
rm -rf reg_rw *.o *.bin dma_to_device dma_from_device performance
rm -rf reg_rw *.o *.bin dma_to_device dma_from_device performance test_chrdev
......@@ -8,9 +8,6 @@
* LICENSE file in the root directory of this source tree)
*/
#define _BSD_SOURCE
#define _XOPEN_SOURCE 500
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
......
......@@ -8,9 +8,6 @@
* LICENSE file in the root directory of this source tree)
*/
#define _BSD_SOURCE
#define _XOPEN_SOURCE 500
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
......
#!/bin/bash
#rm hw_log_h2c.txt
#rm hw_log_c2h.txt
h2c=/dev/xdma0_h2c_0
c2h=/dev/xdma0_c2h_0
iter=1
out_h2c=hw_log_h2c.txt
out_c2h=hw_log_c2h.txt
byte=64
for ((j=0; j<=16; j++)) do
echo "** HW H2C = $h2c bytecount = $byte and iteration = $iter" | tee -a $out_h2c
./performance -d $h2c -c $iter -s $byte | tee -a $out_h2c
byte=$(($byte*2))
done
byte=64
for ((j=0; j<=16; j++)) do
echo "** HW C2H = $c2h bytecount = $byte and iteration = $iter" | tee -a $out_c2h
./performance -d $c2h -c $iter -s $byte | tee -a $out_c2h
byte=$(($byte*2))
done
......@@ -24,7 +24,6 @@
#include <sys/stat.h>
#include <sys/types.h>
/* @TODO During kernel upstreaming, the IOCTL must move into the public user API of the kernel */
#include "../xdma/cdev_sgdma.h"
struct xdma_performance_ioctl perf;
......
......@@ -15,16 +15,14 @@
#include <byteswap.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
/* ltoh: little to host */
/* htol: little to host */
/* ltoh: little endian to host */
/* htol: host to little endian */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ltohl(x) (x)
#define ltohs(x) (x)
......@@ -37,14 +35,14 @@
#define htols(x) __bswap_16(x)
#endif
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
int main(int argc, char **argv)
{
int fd;
int err = 0;
void *map;
uint32_t read_result, writeval;
off_t target;
off_t pgsz, target_aligned, offset;
/* access width */
char access_width = 'w';
char *device;
......@@ -63,8 +61,14 @@ int main(int argc, char **argv)
device = strdup(argv[1]);
target = strtoul(argv[2], 0, 0);
printf("device: %s, address: 0x%08x, access %s.\n",
device, (unsigned int)target, argc >= 4 ? "write" : "read");
/* check for target page alignment */
pgsz = sysconf(_SC_PAGESIZE);
offset = target & (pgsz - 1);
target_aligned = target & (~(pgsz - 1));
printf("device: %s, address: 0x%lx (0x%lx+0x%lx), access %s.\n",
device, target, target_aligned, offset,
argc >= 4 ? "write" : "read");
/* data given? */
if (argc >= 4)
......@@ -81,105 +85,95 @@ int main(int argc, char **argv)
access_width = 'w';
}
if ((fd = open(argv[1], O_RDWR | O_SYNC)) == -1)
FATAL;
if ((fd = open(argv[1], O_RDWR | O_SYNC)) == -1) {
printf("character device %s opened failed: %s.\n",
argv[1], strerror(errno));
return -errno;
}
printf("character device %s opened.\n", argv[1]);
fflush(stdout);
map = mmap(0, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target);
if (map == (void *)-1)
FATAL;
printf("Memory 0x%lx mapped at address %p.\n", target, map);
fflush(stdout);
map = mmap(NULL, offset + 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
target_aligned);
if (map == (void *)-1) {
printf("Memory 0x%lx mapped failed: %s.\n",
target, strerror(errno));
err = 1;
goto close;
}
printf("Memory 0x%lx mapped at address %p.\n", target_aligned, map);
map += offset;
/* read only */
if (argc <= 4) {
switch (access_width) {
case 'b':
read_result = *((uint8_t *) map);
printf
("Read 8-bits value at address 0x%08x (%p): 0x%02x\n",
(unsigned int)target, map,
(unsigned int)read_result);
("Read 8-bits value at address 0x%lx (%p): 0x%02x\n",
target, map, (unsigned int)read_result);
break;
case 'h':
read_result = *((uint16_t *) map);
/* swap 16-bit endianess if host is not little-endian */
read_result = ltohs(read_result);
printf
("Read 16-bit value at address 0x%08x (%p): 0x%04x\n",
(unsigned int)target, map,
(unsigned int)read_result);
("Read 16-bit value at address 0x%lx (%p): 0x%04x\n",
target, map, (unsigned int)read_result);
break;
case 'w':
read_result = *((uint32_t *) map);
/* swap 32-bit endianess if host is not little-endian */
read_result = ltohl(read_result);
printf
("Read 32-bit value at address 0x%08x (%p): 0x%08x\n",
(unsigned int)target, map,
(unsigned int)read_result);
return (int)read_result;
("Read 32-bit value at address 0x%lx (%p): 0x%08x\n",
target, map, (unsigned int)read_result);
break;
default:
fprintf(stderr, "Illegal data type '%c'.\n",
access_width);
exit(2);
err = 1;
goto unmap;
}
fflush(stdout);
}
/* data value given, i.e. writing? */
if (argc >= 5) {
writeval = strtoul(argv[4], 0, 0);
switch (access_width) {
case 'b':
printf("Write 8-bits value 0x%02x to 0x%08x (0x%p)\n",
(unsigned int)writeval, (unsigned int)target,
map);
printf("Write 8-bits value 0x%02x to 0x%lx (0x%p)\n",
(unsigned int)writeval, target, map);
*((uint8_t *) map) = writeval;
#if 0
if (argc > 4) {
read_result = *((uint8_t *) map);
printf("Written 0x%02x; readback 0x%02x\n",
writeval, read_result);
}
#endif
break;
case 'h':
printf("Write 16-bits value 0x%04x to 0x%08x (0x%p)\n",
(unsigned int)writeval, (unsigned int)target,
map);
printf("Write 16-bits value 0x%04x to 0x%lx (0x%p)\n",
(unsigned int)writeval, target, map);
/* swap 16-bit endianess if host is not little-endian */
writeval = htols(writeval);
*((uint16_t *) map) = writeval;
#if 0
if (argc > 4) {
read_result = *((uint16_t *) map);
printf("Written 0x%04x; readback 0x%04x\n",
writeval, read_result);
}
#endif
break;
case 'w':
printf("Write 32-bits value 0x%08x to 0x%08x (0x%p)\n",
(unsigned int)writeval, (unsigned int)target,
map);
printf("Write 32-bits value 0x%08x to 0x%lx (0x%p)\n",
(unsigned int)writeval, target, map);
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t *) map) = writeval;
#if 0
if (argc > 4) {
read_result = *((uint32_t *) map);
printf("Written 0x%08x; readback 0x%08x\n",
writeval, read_result);
}
#endif
break;
default:
fprintf(stderr, "Illegal data type '%c'.\n",
access_width);
err = 1;
goto unmap;
}
fflush(stdout);
}
if (munmap(map, 4) == -1)
FATAL;
unmap:
map -= offset;
if (munmap(map, offset + 4) == -1) {
printf("Memory 0x%lx mapped failed: %s.\n",
target, strerror(errno));
}
close:
close(fd);
return 0;
return err;
}
/*
* This file is part of the Xilinx DMA IP Core driver tools for Linux
*
* Copyright (c) 2016-present, Xilinx, Inc.
* All rights reserved.
*
* This source code is licensed under BSD-style license (found in the
* LICENSE file in the root directory of this source tree)
*/
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
char *filename;
if ( (argc < 2) || (argc >= 3))
{
printf("usage %s <device file>\n",argv[0]);
return -1;
}
filename = argv[1];
fd = open(filename,O_RDWR);
if (fd < 0)
{
perror("Device open Failed");
return fd;
}
printf("%s Device open successfull\n",argv[1]);
if ( close(fd) )
{
perror("Device Close Failed");
return -1;
}
printf("%s Device close successfull\n",argv[1]);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment