mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-04 01:24:12 +08:00
selftests: Add test to verify power supply properties
Add a kselftest that verifies power supply properties from sysfs and uevent. It checks whether they are present, readable and return valid values. This initial set of properties is not comprehensive, but rather the ones that I was able to validate locally. Co-developed-by: Sebastian Reichel <sebastian.reichel@collabora.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
This commit is contained in:
parent
2dd0b5a8fc
commit
4a679c5afc
@ -17524,6 +17524,7 @@ F: Documentation/devicetree/bindings/power/supply/
|
||||
F: drivers/power/supply/
|
||||
F: include/linux/power/
|
||||
F: include/linux/power_supply.h
|
||||
F: tools/testing/selftests/power_supply/
|
||||
|
||||
POWERNV OPERATOR PANEL LCD DISPLAY DRIVER
|
||||
M: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
|
||||
|
@ -67,6 +67,7 @@ TARGETS += nsfs
|
||||
TARGETS += perf_events
|
||||
TARGETS += pidfd
|
||||
TARGETS += pid_namespace
|
||||
TARGETS += power_supply
|
||||
TARGETS += powerpc
|
||||
TARGETS += prctl
|
||||
TARGETS += proc
|
||||
|
4
tools/testing/selftests/power_supply/Makefile
Normal file
4
tools/testing/selftests/power_supply/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
TEST_PROGS := test_power_supply_properties.sh
|
||||
TEST_FILES := helpers.sh
|
||||
|
||||
include ../lib.mk
|
178
tools/testing/selftests/power_supply/helpers.sh
Normal file
178
tools/testing/selftests/power_supply/helpers.sh
Normal file
@ -0,0 +1,178 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (c) 2022, 2024 Collabora Ltd
|
||||
SYSFS_SUPPLIES=/sys/class/power_supply
|
||||
|
||||
calc() {
|
||||
awk "BEGIN { print $* }";
|
||||
}
|
||||
|
||||
test_sysfs_prop() {
|
||||
PROP="$1"
|
||||
VALUE="$2" # optional
|
||||
|
||||
PROP_PATH="$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP"
|
||||
TEST_NAME="$DEVNAME".sysfs."$PROP"
|
||||
|
||||
if [ -z "$VALUE" ]; then
|
||||
ktap_test_result "$TEST_NAME" [ -f "$PROP_PATH" ]
|
||||
else
|
||||
ktap_test_result "$TEST_NAME" grep -q "$VALUE" "$PROP_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
to_human_readable_unit() {
|
||||
VALUE="$1"
|
||||
UNIT="$2"
|
||||
|
||||
case "$VALUE" in
|
||||
*[!0-9]* ) return ;; # Not a number
|
||||
esac
|
||||
|
||||
if [ "$UNIT" = "uA" ]; then
|
||||
new_unit="mA"
|
||||
div=1000
|
||||
elif [ "$UNIT" = "uV" ]; then
|
||||
new_unit="V"
|
||||
div=1000000
|
||||
elif [ "$UNIT" = "uAh" ]; then
|
||||
new_unit="Ah"
|
||||
div=1000000
|
||||
elif [ "$UNIT" = "uW" ]; then
|
||||
new_unit="mW"
|
||||
div=1000
|
||||
elif [ "$UNIT" = "uWh" ]; then
|
||||
new_unit="Wh"
|
||||
div=1000000
|
||||
else
|
||||
return
|
||||
fi
|
||||
|
||||
value_converted=$(calc "$VALUE"/"$div")
|
||||
echo "$value_converted" "$new_unit"
|
||||
}
|
||||
|
||||
_check_sysfs_prop_available() {
|
||||
PROP=$1
|
||||
|
||||
PROP_PATH="$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP"
|
||||
TEST_NAME="$DEVNAME".sysfs."$PROP"
|
||||
|
||||
if [ ! -e "$PROP_PATH" ] ; then
|
||||
ktap_test_skip "$TEST_NAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! cat "$PROP_PATH" >/dev/null; then
|
||||
ktap_print_msg "Failed to read"
|
||||
ktap_test_fail "$TEST_NAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
test_sysfs_prop_optional() {
|
||||
PROP=$1
|
||||
UNIT=$2 # optional
|
||||
|
||||
TEST_NAME="$DEVNAME".sysfs."$PROP"
|
||||
|
||||
_check_sysfs_prop_available "$PROP" || return
|
||||
DATA=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP")
|
||||
|
||||
ktap_print_msg "Reported: '$DATA' $UNIT ($(to_human_readable_unit "$DATA" "$UNIT"))"
|
||||
ktap_test_pass "$TEST_NAME"
|
||||
}
|
||||
|
||||
test_sysfs_prop_optional_range() {
|
||||
PROP=$1
|
||||
MIN=$2
|
||||
MAX=$3
|
||||
UNIT=$4 # optional
|
||||
|
||||
TEST_NAME="$DEVNAME".sysfs."$PROP"
|
||||
|
||||
_check_sysfs_prop_available "$PROP" || return
|
||||
DATA=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP")
|
||||
|
||||
if [ "$DATA" -lt "$MIN" ] || [ "$DATA" -gt "$MAX" ]; then
|
||||
ktap_print_msg "'$DATA' is out of range (min=$MIN, max=$MAX)"
|
||||
ktap_test_fail "$TEST_NAME"
|
||||
else
|
||||
ktap_print_msg "Reported: '$DATA' $UNIT ($(to_human_readable_unit "$DATA" "$UNIT"))"
|
||||
ktap_test_pass "$TEST_NAME"
|
||||
fi
|
||||
}
|
||||
|
||||
test_sysfs_prop_optional_list() {
|
||||
PROP=$1
|
||||
LIST=$2
|
||||
|
||||
TEST_NAME="$DEVNAME".sysfs."$PROP"
|
||||
|
||||
_check_sysfs_prop_available "$PROP" || return
|
||||
DATA=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP")
|
||||
|
||||
valid=0
|
||||
|
||||
OLDIFS=$IFS
|
||||
IFS=","
|
||||
for item in $LIST; do
|
||||
if [ "$DATA" = "$item" ]; then
|
||||
valid=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$valid" -eq 1 ]; then
|
||||
ktap_print_msg "Reported: '$DATA'"
|
||||
ktap_test_pass "$TEST_NAME"
|
||||
else
|
||||
ktap_print_msg "'$DATA' is not a valid value for this property"
|
||||
ktap_test_fail "$TEST_NAME"
|
||||
fi
|
||||
IFS=$OLDIFS
|
||||
}
|
||||
|
||||
dump_file() {
|
||||
FILE="$1"
|
||||
while read -r line; do
|
||||
ktap_print_msg "$line"
|
||||
done < "$FILE"
|
||||
}
|
||||
|
||||
__test_uevent_prop() {
|
||||
PROP="$1"
|
||||
OPTIONAL="$2"
|
||||
VALUE="$3" # optional
|
||||
|
||||
UEVENT_PATH="$SYSFS_SUPPLIES"/"$DEVNAME"/uevent
|
||||
TEST_NAME="$DEVNAME".uevent."$PROP"
|
||||
|
||||
if ! grep -q "POWER_SUPPLY_$PROP=" "$UEVENT_PATH"; then
|
||||
if [ "$OPTIONAL" -eq 1 ]; then
|
||||
ktap_test_skip "$TEST_NAME"
|
||||
else
|
||||
ktap_print_msg "Missing property"
|
||||
ktap_test_fail "$TEST_NAME"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
if ! grep -q "POWER_SUPPLY_$PROP=$VALUE" "$UEVENT_PATH"; then
|
||||
ktap_print_msg "Invalid value for uevent property, dumping..."
|
||||
dump_file "$UEVENT_PATH"
|
||||
ktap_test_fail "$TEST_NAME"
|
||||
else
|
||||
ktap_test_pass "$TEST_NAME"
|
||||
fi
|
||||
}
|
||||
|
||||
test_uevent_prop() {
|
||||
__test_uevent_prop "$1" 0 "$2"
|
||||
}
|
||||
|
||||
test_uevent_prop_optional() {
|
||||
__test_uevent_prop "$1" 1 "$2"
|
||||
}
|
114
tools/testing/selftests/power_supply/test_power_supply_properties.sh
Executable file
114
tools/testing/selftests/power_supply/test_power_supply_properties.sh
Executable file
@ -0,0 +1,114 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (c) 2022, 2024 Collabora Ltd
|
||||
#
|
||||
# This test validates the power supply uAPI: namely, the files in sysfs and
|
||||
# lines in uevent that expose the power supply properties.
|
||||
#
|
||||
# By default all power supplies available are tested. Optionally the name of a
|
||||
# power supply can be passed as a parameter to test only that one instead.
|
||||
DIR="$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
. "${DIR}"/../kselftest/ktap_helpers.sh
|
||||
|
||||
. "${DIR}"/helpers.sh
|
||||
|
||||
count_tests() {
|
||||
SUPPLIES=$1
|
||||
|
||||
# This needs to be updated every time a new test is added.
|
||||
NUM_TESTS=33
|
||||
|
||||
total_tests=0
|
||||
|
||||
for i in $SUPPLIES; do
|
||||
total_tests=$(("$total_tests" + "$NUM_TESTS"))
|
||||
done
|
||||
|
||||
echo "$total_tests"
|
||||
}
|
||||
|
||||
ktap_print_header
|
||||
|
||||
SYSFS_SUPPLIES=/sys/class/power_supply/
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
supplies=$(ls "$SYSFS_SUPPLIES")
|
||||
else
|
||||
supplies=$1
|
||||
fi
|
||||
|
||||
ktap_set_plan "$(count_tests "$supplies")"
|
||||
|
||||
for DEVNAME in $supplies; do
|
||||
ktap_print_msg Testing device "$DEVNAME"
|
||||
|
||||
if [ ! -d "$SYSFS_SUPPLIES"/"$DEVNAME" ]; then
|
||||
ktap_test_fail "$DEVNAME".exists
|
||||
ktap_exit_fail_msg Device does not exist
|
||||
fi
|
||||
|
||||
ktap_test_pass "$DEVNAME".exists
|
||||
|
||||
test_uevent_prop NAME "$DEVNAME"
|
||||
|
||||
test_sysfs_prop type
|
||||
SUPPLY_TYPE=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/type)
|
||||
# This fails on kernels < 5.8 (needs 2ad3d74e3c69f)
|
||||
test_uevent_prop TYPE "$SUPPLY_TYPE"
|
||||
|
||||
test_sysfs_prop_optional usb_type
|
||||
|
||||
test_sysfs_prop_optional_range online 0 2
|
||||
test_sysfs_prop_optional_range present 0 1
|
||||
|
||||
test_sysfs_prop_optional_list status "Unknown","Charging","Discharging","Not charging","Full"
|
||||
|
||||
# Capacity is reported as percentage, thus any value less than 0 and
|
||||
# greater than 100 are not allowed.
|
||||
test_sysfs_prop_optional_range capacity 0 100 "%"
|
||||
|
||||
test_sysfs_prop_optional_list capacity_level "Unknown","Critical","Low","Normal","High","Full"
|
||||
|
||||
test_sysfs_prop_optional model_name
|
||||
test_sysfs_prop_optional manufacturer
|
||||
test_sysfs_prop_optional serial_number
|
||||
test_sysfs_prop_optional_list technology "Unknown","NiMH","Li-ion","Li-poly","LiFe","NiCd","LiMn"
|
||||
|
||||
test_sysfs_prop_optional cycle_count
|
||||
|
||||
test_sysfs_prop_optional_list scope "Unknown","System","Device"
|
||||
|
||||
test_sysfs_prop_optional input_current_limit "uA"
|
||||
test_sysfs_prop_optional input_voltage_limit "uV"
|
||||
|
||||
# Technically the power-supply class does not limit reported values.
|
||||
# E.g. one could expose an RTC backup-battery, which goes below 1.5V or
|
||||
# an electric vehicle battery with over 300V. But most devices do not
|
||||
# have a step-up capable regulator behind the battery and operate with
|
||||
# voltages considered safe to touch, so we limit the allowed range to
|
||||
# 1.8V-60V to catch drivers reporting incorrectly scaled values. E.g. a
|
||||
# common mistake is reporting data in mV instead of µV.
|
||||
test_sysfs_prop_optional_range voltage_now 1800000 60000000 "uV"
|
||||
test_sysfs_prop_optional_range voltage_min 1800000 60000000 "uV"
|
||||
test_sysfs_prop_optional_range voltage_max 1800000 60000000 "uV"
|
||||
test_sysfs_prop_optional_range voltage_min_design 1800000 60000000 "uV"
|
||||
test_sysfs_prop_optional_range voltage_max_design 1800000 60000000 "uV"
|
||||
|
||||
# current based systems
|
||||
test_sysfs_prop_optional current_now "uA"
|
||||
test_sysfs_prop_optional current_max "uA"
|
||||
test_sysfs_prop_optional charge_now "uAh"
|
||||
test_sysfs_prop_optional charge_full "uAh"
|
||||
test_sysfs_prop_optional charge_full_design "uAh"
|
||||
|
||||
# power based systems
|
||||
test_sysfs_prop_optional power_now "uW"
|
||||
test_sysfs_prop_optional energy_now "uWh"
|
||||
test_sysfs_prop_optional energy_full "uWh"
|
||||
test_sysfs_prop_optional energy_full_design "uWh"
|
||||
test_sysfs_prop_optional energy_full_design "uWh"
|
||||
done
|
||||
|
||||
ktap_finished
|
Loading…
Reference in New Issue
Block a user