selftests/pcie_bwctrl: Create selftests

Create selftests for PCIe BW control through the PCIe cooling device sysfs
interface.

First, the BW control selftest finds the PCIe Port to test with. By
default, the PCIe Port with the highest Link Speed is selected but
another PCIe Port can be provided with -d parameter.

The actual test steps the cur_state of the cooling device one-by-one
from max_state to what the cur_state was initially. The speed change
is confirmed by observing the current_link_speed for the corresponding
PCIe Port.

Link: https://lore.kernel.org/r/20241018144755.7875-10-ilpo.jarvinen@linux.intel.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
Ilpo Järvinen 2024-10-18 17:47:55 +03:00 committed by Bjorn Helgaas
parent d278b09828
commit 838f12c3d5
5 changed files with 193 additions and 0 deletions

View file

@ -17940,6 +17940,7 @@ S: Supported
F: drivers/pci/pcie/bwctrl.c
F: drivers/thermal/pcie_cooling.c
F: include/linux/pci-bwctrl.h
F: tools/testing/selftests/pcie_bwctrl/
PCIE DRIVER FOR AMAZON ANNAPURNA LABS
M: Jonathan Chocron <jonnyc@amazon.com>

View file

@ -72,6 +72,7 @@ TARGETS += net/packetdrill
TARGETS += net/rds
TARGETS += net/tcp_ao
TARGETS += nsfs
TARGETS += pcie_bwctrl
TARGETS += perf_events
TARGETS += pidfd
TARGETS += pid_namespace

View file

@ -0,0 +1,2 @@
TEST_PROGS = set_pcie_cooling_state.sh
include ../lib.mk

View file

@ -0,0 +1,122 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
SYSFS=
# Kselftest framework requirement - SKIP code is 4.
ksft_skip=4
retval=0
skipmsg="skip all tests:"
PCIEPORTTYPE="PCIe_Port_Link_Speed"
prerequisite()
{
local ports
if [ $UID != 0 ]; then
echo $skipmsg must be run as root >&2
exit $ksft_skip
fi
SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
if [ ! -d "$SYSFS" ]; then
echo $skipmsg sysfs is not mounted >&2
exit $ksft_skip
fi
if ! ls $SYSFS/class/thermal/cooling_device* > /dev/null 2>&1; then
echo $skipmsg thermal cooling devices missing >&2
exit $ksft_skip
fi
ports=`grep -e "^$PCIEPORTTYPE" $SYSFS/class/thermal/cooling_device*/type | wc -l`
if [ $ports -eq 0 ]; then
echo $skipmsg pcie cooling devices missing >&2
exit $ksft_skip
fi
}
testport=
find_pcie_port()
{
local patt="$1"
local pcieports
local max
local cur
local delta
local bestdelta=-1
pcieports=`grep -l -F -e "$patt" /sys/class/thermal/cooling_device*/type`
if [ -z "$pcieports" ]; then
return
fi
pcieports=${pcieports//\/type/}
# Find the port with the highest PCIe Link Speed
for port in $pcieports; do
max=`cat $port/max_state`
cur=`cat $port/cur_state`
delta=$((max-cur))
if [ $delta -gt $bestdelta ]; then
testport="$port"
bestdelta=$delta
fi
done
}
sysfspcidev=
find_sysfs_pci_dev()
{
local typefile="$1/type"
local pcidir
pcidir="$SYSFS/bus/pci/devices/`sed -e "s|^${PCIEPORTTYPE}_||g" $typefile`"
if [ -r "$pcidir/current_link_speed" ]; then
sysfspcidev="$pcidir/current_link_speed"
fi
}
usage()
{
echo "Usage $0 [ -d dev ]"
echo -e "\t-d: PCIe port BDF string (e.g., 0000:00:04.0)"
}
pattern="$PCIEPORTTYPE"
parse_arguments()
{
while getopts d:h opt; do
case $opt in
h)
usage "$0"
exit 0
;;
d)
pattern="$PCIEPORTTYPE_$OPTARG"
;;
*)
usage "$0"
exit 0
;;
esac
done
}
parse_arguments "$@"
prerequisite
find_pcie_port "$pattern"
if [ -z "$testport" ]; then
echo $skipmsg "pcie cooling device not found from sysfs" >&2
exit $ksft_skip
fi
find_sysfs_pci_dev "$testport"
if [ -z "$sysfspcidev" ]; then
echo $skipmsg "PCIe port device not found from sysfs" >&2
exit $ksft_skip
fi
./set_pcie_speed.sh "$testport" "$sysfspcidev"
retval=$?
exit $retval

View file

@ -0,0 +1,67 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
set -e
TESTNAME=set_pcie_speed
declare -a PCIELINKSPEED=(
"2.5 GT/s PCIe"
"5.0 GT/s PCIe"
"8.0 GT/s PCIe"
"16.0 GT/s PCIe"
"32.0 GT/s PCIe"
"64.0 GT/s PCIe"
)
# Kselftest framework requirement - SKIP code is 4.
ksft_skip=4
retval=0
coolingdev="$1"
statefile="$coolingdev/cur_state"
maxfile="$coolingdev/max_state"
linkspeedfile="$2"
oldstate=`cat $statefile`
maxstate=`cat $maxfile`
set_state()
{
local state=$1
local linkspeed
local expected_linkspeed
echo $state > $statefile
sleep 1
linkspeed="`cat $linkspeedfile`"
expected_linkspeed=$((maxstate-state))
expected_str="${PCIELINKSPEED[$expected_linkspeed]}"
if [ ! "${expected_str}" = "${linkspeed}" ]; then
echo "$TESTNAME failed: expected: ${expected_str}; got ${linkspeed}"
retval=1
fi
}
cleanup_skip ()
{
set_state $oldstate
exit $ksft_skip
}
trap cleanup_skip EXIT
echo "$TESTNAME: testing states $maxstate .. $oldstate with $coolingdev"
for i in $(seq $maxstate -1 $oldstate); do
set_state "$i"
done
trap EXIT
if [ $retval -eq 0 ]; then
echo "$TESTNAME [PASS]"
else
echo "$TESTNAME [FAIL]"
fi
exit $retval