a37ddddd86
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>
215 lines
3.9 KiB
Bash
Executable File
215 lines
3.9 KiB
Bash
Executable File
#!/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
|