Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Russ Weight and committed by
Greg Kroah-Hartman
a37ddddd cebdc534

+227 -1
+1 -1
tools/testing/selftests/firmware/Makefile
··· 4 4 -O2 5 5 6 6 TEST_PROGS := fw_run_tests.sh 7 - TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_lib.sh 7 + TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_upload.sh fw_lib.sh 8 8 TEST_GEN_FILES := fw_namespace 9 9 10 10 include ../lib.mk
+1
tools/testing/selftests/firmware/config
··· 3 3 CONFIG_FW_LOADER_USER_HELPER=y 4 4 CONFIG_IKCONFIG=y 5 5 CONFIG_IKCONFIG_PROC=y 6 + CONFIG_FW_UPLOAD=y
+7
tools/testing/selftests/firmware/fw_lib.sh
··· 64 64 HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)" 65 65 HAS_FW_LOADER_COMPRESS_XZ="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_XZ=y)" 66 66 HAS_FW_LOADER_COMPRESS_ZSTD="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_ZSTD=y)" 67 + HAS_FW_UPLOAD="$(kconfig_has CONFIG_FW_UPLOAD=y)" 67 68 PROC_FW_IGNORE_SYSFS_FALLBACK="0" 68 69 PROC_FW_FORCE_SYSFS_FALLBACK="0" 69 70 ··· 117 116 if [ "$TEST_REQS_FW_SYSFS_FALLBACK" = "yes" ]; then 118 117 if [ ! "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then 119 118 echo "usermode helper disabled so ignoring test" 119 + exit 0 120 + fi 121 + fi 122 + if [ "$TEST_REQS_FW_UPLOAD" = "yes" ]; then 123 + if [ ! "$HAS_FW_UPLOAD" = "yes" ]; then 124 + echo "firmware upload disabled so ignoring test" 120 125 exit 0 121 126 fi 122 127 fi
+4
tools/testing/selftests/firmware/fw_run_tests.sh
··· 22 22 proc_set_force_sysfs_fallback $1 23 23 proc_set_ignore_sysfs_fallback $2 24 24 $TEST_DIR/fw_fallback.sh 25 + 26 + proc_set_force_sysfs_fallback $1 27 + proc_set_ignore_sysfs_fallback $2 28 + $TEST_DIR/fw_upload.sh 25 29 } 26 30 27 31 run_test_config_0001()
+214
tools/testing/selftests/firmware/fw_upload.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # This validates the user-initiated fw upload mechanism of the firmware 4 + # loader. It verifies that one or more firmware devices can be created 5 + # for a device driver. It also verifies the data transfer, the 6 + # cancellation support, and the error flows. 7 + set -e 8 + 9 + TEST_REQS_FW_UPLOAD="yes" 10 + TEST_DIR=$(dirname $0) 11 + 12 + progress_states="preparing transferring programming" 13 + errors="hw-error 14 + timeout 15 + device-busy 16 + invalid-file-size 17 + read-write-error 18 + flash-wearout" 19 + error_abort="user-abort" 20 + fwname1=fw1 21 + fwname2=fw2 22 + fwname3=fw3 23 + 24 + source $TEST_DIR/fw_lib.sh 25 + 26 + check_mods 27 + check_setup 28 + verify_reqs 29 + 30 + trap "upload_finish" EXIT 31 + 32 + upload_finish() { 33 + local fwdevs="$fwname1 $fwname2 $fwname3" 34 + 35 + for name in $fwdevs; do 36 + if [ -e "$DIR/$name" ]; then 37 + echo -n "$name" > "$DIR"/upload_unregister 38 + fi 39 + done 40 + } 41 + 42 + upload_fw() { 43 + local name="$1" 44 + local file="$2" 45 + 46 + echo 1 > "$DIR"/"$name"/loading 47 + cat "$file" > "$DIR"/"$name"/data 48 + echo 0 > "$DIR"/"$name"/loading 49 + } 50 + 51 + verify_fw() { 52 + local name="$1" 53 + local file="$2" 54 + 55 + echo -n "$name" > "$DIR"/config_upload_name 56 + if ! cmp "$file" "$DIR"/upload_read > /dev/null 2>&1; then 57 + echo "$0: firmware compare for $name did not match" >&2 58 + exit 1 59 + fi 60 + 61 + echo "$0: firmware upload for $name works" >&2 62 + return 0 63 + } 64 + 65 + inject_error() { 66 + local name="$1" 67 + local status="$2" 68 + local error="$3" 69 + 70 + echo 1 > "$DIR"/"$name"/loading 71 + echo -n "inject":"$status":"$error" > "$DIR"/"$name"/data 72 + echo 0 > "$DIR"/"$name"/loading 73 + } 74 + 75 + await_status() { 76 + local name="$1" 77 + local expected="$2" 78 + local status 79 + local i 80 + 81 + let i=0 82 + while [ $i -lt 50 ]; do 83 + status=$(cat "$DIR"/"$name"/status) 84 + if [ "$status" = "$expected" ]; then 85 + return 0; 86 + fi 87 + sleep 1e-03 88 + let i=$i+1 89 + done 90 + 91 + echo "$0: Invalid status: Expected $expected, Actual $status" >&2 92 + return 1; 93 + } 94 + 95 + await_idle() { 96 + local name="$1" 97 + 98 + await_status "$name" "idle" 99 + return $? 100 + } 101 + 102 + expect_error() { 103 + local name="$1" 104 + local expected="$2" 105 + local error=$(cat "$DIR"/"$name"/error) 106 + 107 + if [ "$error" != "$expected" ]; then 108 + echo "Invalid error: Expected $expected, Actual $error" >&2 109 + return 1 110 + fi 111 + 112 + return 0 113 + } 114 + 115 + random_firmware() { 116 + local bs="$1" 117 + local count="$2" 118 + local file=$(mktemp -p /tmp uploadfwXXX.bin) 119 + 120 + dd if=/dev/urandom of="$file" bs="$bs" count="$count" > /dev/null 2>&1 121 + echo "$file" 122 + } 123 + 124 + test_upload_cancel() { 125 + local name="$1" 126 + local status 127 + 128 + for status in $progress_states; do 129 + inject_error $name $status $error_abort 130 + if ! await_status $name $status; then 131 + exit 1 132 + fi 133 + 134 + echo 1 > "$DIR"/"$name"/cancel 135 + 136 + if ! await_idle $name; then 137 + exit 1 138 + fi 139 + 140 + if ! expect_error $name "$status":"$error_abort"; then 141 + exit 1 142 + fi 143 + done 144 + 145 + echo "$0: firmware upload cancellation works" 146 + return 0 147 + } 148 + 149 + test_error_handling() { 150 + local name=$1 151 + local status 152 + local error 153 + 154 + for status in $progress_states; do 155 + for error in $errors; do 156 + inject_error $name $status $error 157 + 158 + if ! await_idle $name; then 159 + exit 1 160 + fi 161 + 162 + if ! expect_error $name "$status":"$error"; then 163 + exit 1 164 + fi 165 + 166 + done 167 + done 168 + echo "$0: firmware upload error handling works" 169 + } 170 + 171 + test_fw_too_big() { 172 + local name=$1 173 + local fw_too_big=`random_firmware 512 5` 174 + local expected="preparing:invalid-file-size" 175 + 176 + upload_fw $name $fw_too_big 177 + rm -f $fw_too_big 178 + 179 + if ! await_idle $name; then 180 + exit 1 181 + fi 182 + 183 + if ! expect_error $name $expected; then 184 + exit 1 185 + fi 186 + 187 + echo "$0: oversized firmware error handling works" 188 + } 189 + 190 + echo -n "$fwname1" > "$DIR"/upload_register 191 + echo -n "$fwname2" > "$DIR"/upload_register 192 + echo -n "$fwname3" > "$DIR"/upload_register 193 + 194 + test_upload_cancel $fwname1 195 + test_error_handling $fwname1 196 + test_fw_too_big $fwname1 197 + 198 + fw_file1=`random_firmware 512 4` 199 + fw_file2=`random_firmware 512 3` 200 + fw_file3=`random_firmware 512 2` 201 + 202 + upload_fw $fwname1 $fw_file1 203 + upload_fw $fwname2 $fw_file2 204 + upload_fw $fwname3 $fw_file3 205 + 206 + verify_fw ${fwname1} ${fw_file1} 207 + verify_fw ${fwname2} ${fw_file2} 208 + verify_fw ${fwname3} ${fw_file3} 209 + 210 + echo -n "$fwname1" > "$DIR"/upload_unregister 211 + echo -n "$fwname2" > "$DIR"/upload_unregister 212 + echo -n "$fwname3" > "$DIR"/upload_unregister 213 + 214 + exit 0