selftests: firmware: Add firmware upload selftests

Add selftests to verify the firmware upload mechanism. These test
include simple firmware uploads as well as upload cancellation and
error injection. The test creates three firmware devices and verifies
that they all work correctly and independently.

Tested-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Reviewed-by: Tianfei zhang <tianfei.zhang@intel.com>
Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Link: https://lore.kernel.org/r/20220426163532.114961-1-russell.h.weight@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Russ Weight 2022-04-26 09:35:32 -07:00 committed by Greg Kroah-Hartman
parent cebdc5349f
commit a37ddddd86
5 changed files with 227 additions and 1 deletions

View File

@ -4,7 +4,7 @@ CFLAGS = -Wall \
-O2
TEST_PROGS := fw_run_tests.sh
TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_lib.sh
TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_upload.sh fw_lib.sh
TEST_GEN_FILES := fw_namespace
include ../lib.mk

View File

@ -3,3 +3,4 @@ CONFIG_FW_LOADER=y
CONFIG_FW_LOADER_USER_HELPER=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_FW_UPLOAD=y

View File

@ -64,6 +64,7 @@ check_setup()
HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)"
HAS_FW_LOADER_COMPRESS_XZ="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_XZ=y)"
HAS_FW_LOADER_COMPRESS_ZSTD="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_ZSTD=y)"
HAS_FW_UPLOAD="$(kconfig_has CONFIG_FW_UPLOAD=y)"
PROC_FW_IGNORE_SYSFS_FALLBACK="0"
PROC_FW_FORCE_SYSFS_FALLBACK="0"
@ -119,6 +120,12 @@ verify_reqs()
exit 0
fi
fi
if [ "$TEST_REQS_FW_UPLOAD" = "yes" ]; then
if [ ! "$HAS_FW_UPLOAD" = "yes" ]; then
echo "firmware upload disabled so ignoring test"
exit 0
fi
fi
}
setup_tmp_file()

View File

@ -22,6 +22,10 @@ run_tests()
proc_set_force_sysfs_fallback $1
proc_set_ignore_sysfs_fallback $2
$TEST_DIR/fw_fallback.sh
proc_set_force_sysfs_fallback $1
proc_set_ignore_sysfs_fallback $2
$TEST_DIR/fw_upload.sh
}
run_test_config_0001()

View File

@ -0,0 +1,214 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# This validates the user-initiated fw upload mechanism of the firmware
# loader. It verifies that one or more firmware devices can be created
# for a device driver. It also verifies the data transfer, the
# cancellation support, and the error flows.
set -e
TEST_REQS_FW_UPLOAD="yes"
TEST_DIR=$(dirname $0)
progress_states="preparing transferring programming"
errors="hw-error
timeout
device-busy
invalid-file-size
read-write-error
flash-wearout"
error_abort="user-abort"
fwname1=fw1
fwname2=fw2
fwname3=fw3
source $TEST_DIR/fw_lib.sh
check_mods
check_setup
verify_reqs
trap "upload_finish" EXIT
upload_finish() {
local fwdevs="$fwname1 $fwname2 $fwname3"
for name in $fwdevs; do
if [ -e "$DIR/$name" ]; then
echo -n "$name" > "$DIR"/upload_unregister
fi
done
}
upload_fw() {
local name="$1"
local file="$2"
echo 1 > "$DIR"/"$name"/loading
cat "$file" > "$DIR"/"$name"/data
echo 0 > "$DIR"/"$name"/loading
}
verify_fw() {
local name="$1"
local file="$2"
echo -n "$name" > "$DIR"/config_upload_name
if ! cmp "$file" "$DIR"/upload_read > /dev/null 2>&1; then
echo "$0: firmware compare for $name did not match" >&2
exit 1
fi
echo "$0: firmware upload for $name works" >&2
return 0
}
inject_error() {
local name="$1"
local status="$2"
local error="$3"
echo 1 > "$DIR"/"$name"/loading
echo -n "inject":"$status":"$error" > "$DIR"/"$name"/data
echo 0 > "$DIR"/"$name"/loading
}
await_status() {
local name="$1"
local expected="$2"
local status
local i
let i=0
while [ $i -lt 50 ]; do
status=$(cat "$DIR"/"$name"/status)
if [ "$status" = "$expected" ]; then
return 0;
fi
sleep 1e-03
let i=$i+1
done
echo "$0: Invalid status: Expected $expected, Actual $status" >&2
return 1;
}
await_idle() {
local name="$1"
await_status "$name" "idle"
return $?
}
expect_error() {
local name="$1"
local expected="$2"
local error=$(cat "$DIR"/"$name"/error)
if [ "$error" != "$expected" ]; then
echo "Invalid error: Expected $expected, Actual $error" >&2
return 1
fi
return 0
}
random_firmware() {
local bs="$1"
local count="$2"
local file=$(mktemp -p /tmp uploadfwXXX.bin)
dd if=/dev/urandom of="$file" bs="$bs" count="$count" > /dev/null 2>&1
echo "$file"
}
test_upload_cancel() {
local name="$1"
local status
for status in $progress_states; do
inject_error $name $status $error_abort
if ! await_status $name $status; then
exit 1
fi
echo 1 > "$DIR"/"$name"/cancel
if ! await_idle $name; then
exit 1
fi
if ! expect_error $name "$status":"$error_abort"; then
exit 1
fi
done
echo "$0: firmware upload cancellation works"
return 0
}
test_error_handling() {
local name=$1
local status
local error
for status in $progress_states; do
for error in $errors; do
inject_error $name $status $error
if ! await_idle $name; then
exit 1
fi
if ! expect_error $name "$status":"$error"; then
exit 1
fi
done
done
echo "$0: firmware upload error handling works"
}
test_fw_too_big() {
local name=$1
local fw_too_big=`random_firmware 512 5`
local expected="preparing:invalid-file-size"
upload_fw $name $fw_too_big
rm -f $fw_too_big
if ! await_idle $name; then
exit 1
fi
if ! expect_error $name $expected; then
exit 1
fi
echo "$0: oversized firmware error handling works"
}
echo -n "$fwname1" > "$DIR"/upload_register
echo -n "$fwname2" > "$DIR"/upload_register
echo -n "$fwname3" > "$DIR"/upload_register
test_upload_cancel $fwname1
test_error_handling $fwname1
test_fw_too_big $fwname1
fw_file1=`random_firmware 512 4`
fw_file2=`random_firmware 512 3`
fw_file3=`random_firmware 512 2`
upload_fw $fwname1 $fw_file1
upload_fw $fwname2 $fw_file2
upload_fw $fwname3 $fw_file3
verify_fw ${fwname1} ${fw_file1}
verify_fw ${fwname2} ${fw_file2}
verify_fw ${fwname3} ${fw_file3}
echo -n "$fwname1" > "$DIR"/upload_unregister
echo -n "$fwname2" > "$DIR"/upload_unregister
echo -n "$fwname3" > "$DIR"/upload_unregister
exit 0