1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# This validates that the kernel will load firmware out of its list of 4# firmware locations on disk. Since the user helper does similar work, 5# we reset the custom load directory to a location the user helper doesn't 6# know so we can be sure we're not accidentally testing the user helper. 7set -e 8 9TEST_REQS_FW_SYSFS_FALLBACK="no" 10TEST_REQS_FW_SET_CUSTOM_PATH="yes" 11TEST_DIR=$(dirname $0) 12source $TEST_DIR/fw_lib.sh 13 14check_mods 15check_setup 16verify_reqs 17setup_tmp_file 18 19trap "test_finish" EXIT 20 21if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then 22 # Turn down the timeout so failures don't take so long. 23 echo 1 >/sys/class/firmware/timeout 24fi 25 26if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then 27 echo "$0: empty filename should not succeed" >&2 28 exit 1 29fi 30 31if [ ! -e "$DIR"/trigger_async_request ]; then 32 echo "$0: empty filename: async trigger not present, ignoring test" >&2 33 exit $ksft_skip 34else 35 if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then 36 echo "$0: empty filename should not succeed (async)" >&2 37 exit 1 38 fi 39fi 40 41# Request a firmware that doesn't exist, it should fail. 42if echo -n "nope-$NAME" >"$DIR"/trigger_request 2> /dev/null; then 43 echo "$0: firmware shouldn't have loaded" >&2 44 exit 1 45fi 46if diff -q "$FW" /dev/test_firmware >/dev/null ; then 47 echo "$0: firmware was not expected to match" >&2 48 exit 1 49else 50 if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then 51 echo "$0: timeout works" 52 fi 53fi 54 55# This should succeed via kernel load or will fail after 1 second after 56# being handed over to the user helper, which won't find the fw either. 57if ! echo -n "$NAME" >"$DIR"/trigger_request ; then 58 echo "$0: could not trigger request" >&2 59 exit 1 60fi 61 62# Verify the contents are what we expect. 63if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 64 echo "$0: firmware was not loaded" >&2 65 exit 1 66else 67 echo "$0: filesystem loading works" 68fi 69 70# Try the asynchronous version too 71if [ ! -e "$DIR"/trigger_async_request ]; then 72 echo "$0: firmware loading: async trigger not present, ignoring test" >&2 73 exit $ksft_skip 74else 75 if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then 76 echo "$0: could not trigger async request" >&2 77 exit 1 78 fi 79 80 # Verify the contents are what we expect. 81 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 82 echo "$0: firmware was not loaded (async)" >&2 83 exit 1 84 else 85 echo "$0: async filesystem loading works" 86 fi 87fi 88 89### Batched requests tests 90test_config_present() 91{ 92 if [ ! -f $DIR/reset ]; then 93 echo "Configuration triggers not present, ignoring test" 94 exit $ksft_skip 95 fi 96} 97 98# Defaults : 99# 100# send_uevent: 1 101# sync_direct: 0 102# name: test-firmware.bin 103# num_requests: 4 104config_reset() 105{ 106 echo 1 > $DIR/reset 107} 108 109release_all_firmware() 110{ 111 echo 1 > $DIR/release_all_firmware 112} 113 114config_set_name() 115{ 116 echo -n $1 > $DIR/config_name 117} 118 119config_set_sync_direct() 120{ 121 echo 1 > $DIR/config_sync_direct 122} 123 124config_unset_sync_direct() 125{ 126 echo 0 > $DIR/config_sync_direct 127} 128 129config_set_uevent() 130{ 131 echo 1 > $DIR/config_send_uevent 132} 133 134config_unset_uevent() 135{ 136 echo 0 > $DIR/config_send_uevent 137} 138 139config_trigger_sync() 140{ 141 echo -n 1 > $DIR/trigger_batched_requests 2>/dev/null 142} 143 144config_trigger_async() 145{ 146 echo -n 1 > $DIR/trigger_batched_requests_async 2> /dev/null 147} 148 149config_set_read_fw_idx() 150{ 151 echo -n $1 > $DIR/config_read_fw_idx 2> /dev/null 152} 153 154read_firmwares() 155{ 156 if [ "$1" = "xzonly" ]; then 157 fwfile="${FW}-orig" 158 else 159 fwfile="$FW" 160 fi 161 for i in $(seq 0 3); do 162 config_set_read_fw_idx $i 163 # Verify the contents are what we expect. 164 # -Z required for now -- check for yourself, md5sum 165 # on $FW and DIR/read_firmware will yield the same. Even 166 # cmp agrees, so something is off. 167 if ! diff -q -Z "$fwfile" $DIR/read_firmware 2>/dev/null ; then 168 echo "request #$i: firmware was not loaded" >&2 169 exit 1 170 fi 171 done 172} 173 174read_firmwares_expect_nofile() 175{ 176 for i in $(seq 0 3); do 177 config_set_read_fw_idx $i 178 # Ensures contents differ 179 if diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then 180 echo "request $i: file was not expected to match" >&2 181 exit 1 182 fi 183 done 184} 185 186test_batched_request_firmware_nofile() 187{ 188 echo -n "Batched request_firmware() nofile try #$1: " 189 config_reset 190 config_set_name nope-test-firmware.bin 191 config_trigger_sync 192 read_firmwares_expect_nofile 193 release_all_firmware 194 echo "OK" 195} 196 197test_batched_request_firmware_direct_nofile() 198{ 199 echo -n "Batched request_firmware_direct() nofile try #$1: " 200 config_reset 201 config_set_name nope-test-firmware.bin 202 config_set_sync_direct 203 config_trigger_sync 204 release_all_firmware 205 echo "OK" 206} 207 208test_request_firmware_nowait_uevent_nofile() 209{ 210 echo -n "Batched request_firmware_nowait(uevent=true) nofile try #$1: " 211 config_reset 212 config_set_name nope-test-firmware.bin 213 config_trigger_async 214 release_all_firmware 215 echo "OK" 216} 217 218test_wait_and_cancel_custom_load() 219{ 220 if [ "$HAS_FW_LOADER_USER_HELPER" != "yes" ]; then 221 return 222 fi 223 local timeout=10 224 name=$1 225 while [ ! -e "$DIR"/"$name"/loading ]; do 226 sleep 0.1 227 timeout=$(( $timeout - 1 )) 228 if [ "$timeout" -eq 0 ]; then 229 echo "firmware interface never appeared:" >&2 230 echo "$DIR/$name/loading" >&2 231 exit 1 232 fi 233 done 234 echo -1 >"$DIR"/"$name"/loading 235} 236 237test_request_firmware_nowait_custom_nofile() 238{ 239 echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: " 240 config_reset 241 config_unset_uevent 242 RANDOM_FILE_PATH=$(setup_random_file_fake) 243 RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 244 config_set_name $RANDOM_FILE 245 config_trigger_async & 246 test_wait_and_cancel_custom_load $RANDOM_FILE 247 wait 248 release_all_firmware 249 echo "OK" 250} 251 252test_batched_request_firmware() 253{ 254 echo -n "Batched request_firmware() $2 try #$1: " 255 config_reset 256 config_trigger_sync 257 read_firmwares $2 258 release_all_firmware 259 echo "OK" 260} 261 262test_batched_request_firmware_direct() 263{ 264 echo -n "Batched request_firmware_direct() $2 try #$1: " 265 config_reset 266 config_set_sync_direct 267 config_trigger_sync 268 release_all_firmware 269 echo "OK" 270} 271 272test_request_firmware_nowait_uevent() 273{ 274 echo -n "Batched request_firmware_nowait(uevent=true) $2 try #$1: " 275 config_reset 276 config_trigger_async 277 release_all_firmware 278 echo "OK" 279} 280 281test_request_firmware_nowait_custom() 282{ 283 echo -n "Batched request_firmware_nowait(uevent=false) $2 try #$1: " 284 config_reset 285 config_unset_uevent 286 RANDOM_FILE_PATH=$(setup_random_file) 287 RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 288 if [ "$2" = "both" ]; then 289 xz -9 -C crc32 -k $RANDOM_FILE_PATH 290 elif [ "$2" = "xzonly" ]; then 291 xz -9 -C crc32 $RANDOM_FILE_PATH 292 fi 293 config_set_name $RANDOM_FILE 294 config_trigger_async 295 release_all_firmware 296 echo "OK" 297} 298 299# Only continue if batched request triggers are present on the 300# test-firmware driver 301test_config_present 302 303# test with the file present 304echo 305echo "Testing with the file present..." 306for i in $(seq 1 5); do 307 test_batched_request_firmware $i normal 308done 309 310for i in $(seq 1 5); do 311 test_batched_request_firmware_direct $i normal 312done 313 314for i in $(seq 1 5); do 315 test_request_firmware_nowait_uevent $i normal 316done 317 318for i in $(seq 1 5); do 319 test_request_firmware_nowait_custom $i normal 320done 321 322# Test for file not found, errors are expected, the failure would be 323# a hung task, which would require a hard reset. 324echo 325echo "Testing with the file missing..." 326for i in $(seq 1 5); do 327 test_batched_request_firmware_nofile $i 328done 329 330for i in $(seq 1 5); do 331 test_batched_request_firmware_direct_nofile $i 332done 333 334for i in $(seq 1 5); do 335 test_request_firmware_nowait_uevent_nofile $i 336done 337 338for i in $(seq 1 5); do 339 test_request_firmware_nowait_custom_nofile $i 340done 341 342test "$HAS_FW_LOADER_COMPRESS" != "yes" && exit 0 343 344# test with both files present 345xz -9 -C crc32 -k $FW 346config_set_name $NAME 347echo 348echo "Testing with both plain and xz files present..." 349for i in $(seq 1 5); do 350 test_batched_request_firmware $i both 351done 352 353for i in $(seq 1 5); do 354 test_batched_request_firmware_direct $i both 355done 356 357for i in $(seq 1 5); do 358 test_request_firmware_nowait_uevent $i both 359done 360 361for i in $(seq 1 5); do 362 test_request_firmware_nowait_custom $i both 363done 364 365# test with only xz file present 366mv "$FW" "${FW}-orig" 367echo 368echo "Testing with only xz file present..." 369for i in $(seq 1 5); do 370 test_batched_request_firmware $i xzonly 371done 372 373for i in $(seq 1 5); do 374 test_batched_request_firmware_direct $i xzonly 375done 376 377for i in $(seq 1 5); do 378 test_request_firmware_nowait_uevent $i xzonly 379done 380 381for i in $(seq 1 5); do 382 test_request_firmware_nowait_custom $i xzonly 383done 384 385exit 0 386