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# Try platform (EFI embedded fw) loading too 90if [ ! -e "$DIR"/trigger_request_platform ]; then 91 echo "$0: firmware loading: platform trigger not present, ignoring test" >&2 92else 93 if printf '\000' >"$DIR"/trigger_request_platform 2> /dev/null; then 94 echo "$0: empty filename should not succeed (platform)" >&2 95 exit 1 96 fi 97 98 # Note we echo a non-existing name, since files on the file-system 99 # are preferred over firmware embedded inside the platform's firmware 100 # The test adds a fake entry with the requested name to the platform's 101 # fw list, so the name does not matter as long as it does not exist 102 if ! echo -n "nope-$NAME" >"$DIR"/trigger_request_platform ; then 103 echo "$0: could not trigger request platform" >&2 104 exit 1 105 fi 106 107 # The test verifies itself that the loaded firmware contents matches 108 # the contents for the fake platform fw entry it added. 109 echo "$0: platform loading works" 110fi 111 112### Batched requests tests 113test_config_present() 114{ 115 if [ ! -f $DIR/reset ]; then 116 echo "Configuration triggers not present, ignoring test" 117 exit $ksft_skip 118 fi 119} 120 121# Defaults : 122# 123# send_uevent: 1 124# sync_direct: 0 125# name: test-firmware.bin 126# num_requests: 4 127config_reset() 128{ 129 echo 1 > $DIR/reset 130} 131 132release_all_firmware() 133{ 134 echo 1 > $DIR/release_all_firmware 135} 136 137config_set_name() 138{ 139 echo -n $1 > $DIR/config_name 140} 141 142config_set_into_buf() 143{ 144 echo 1 > $DIR/config_into_buf 145} 146 147config_unset_into_buf() 148{ 149 echo 0 > $DIR/config_into_buf 150} 151 152config_set_sync_direct() 153{ 154 echo 1 > $DIR/config_sync_direct 155} 156 157config_unset_sync_direct() 158{ 159 echo 0 > $DIR/config_sync_direct 160} 161 162config_set_uevent() 163{ 164 echo 1 > $DIR/config_send_uevent 165} 166 167config_unset_uevent() 168{ 169 echo 0 > $DIR/config_send_uevent 170} 171 172config_trigger_sync() 173{ 174 echo -n 1 > $DIR/trigger_batched_requests 2>/dev/null 175} 176 177config_trigger_async() 178{ 179 echo -n 1 > $DIR/trigger_batched_requests_async 2> /dev/null 180} 181 182config_set_read_fw_idx() 183{ 184 echo -n $1 > $DIR/config_read_fw_idx 2> /dev/null 185} 186 187read_firmwares() 188{ 189 if [ "$(cat $DIR/config_into_buf)" == "1" ]; then 190 fwfile="$FW_INTO_BUF" 191 else 192 fwfile="$FW" 193 fi 194 if [ "$1" = "xzonly" ]; then 195 fwfile="${fwfile}-orig" 196 fi 197 for i in $(seq 0 3); do 198 config_set_read_fw_idx $i 199 # Verify the contents are what we expect. 200 # -Z required for now -- check for yourself, md5sum 201 # on $FW and DIR/read_firmware will yield the same. Even 202 # cmp agrees, so something is off. 203 if ! diff -q -Z "$fwfile" $DIR/read_firmware 2>/dev/null ; then 204 echo "request #$i: firmware was not loaded" >&2 205 exit 1 206 fi 207 done 208} 209 210read_firmwares_expect_nofile() 211{ 212 for i in $(seq 0 3); do 213 config_set_read_fw_idx $i 214 # Ensures contents differ 215 if diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then 216 echo "request $i: file was not expected to match" >&2 217 exit 1 218 fi 219 done 220} 221 222test_batched_request_firmware_nofile() 223{ 224 echo -n "Batched request_firmware() nofile try #$1: " 225 config_reset 226 config_set_name nope-test-firmware.bin 227 config_trigger_sync 228 read_firmwares_expect_nofile 229 release_all_firmware 230 echo "OK" 231} 232 233test_batched_request_firmware_into_buf_nofile() 234{ 235 echo -n "Batched request_firmware_into_buf() nofile try #$1: " 236 config_reset 237 config_set_name nope-test-firmware.bin 238 config_set_into_buf 239 config_trigger_sync 240 read_firmwares_expect_nofile 241 release_all_firmware 242 echo "OK" 243} 244 245test_batched_request_firmware_direct_nofile() 246{ 247 echo -n "Batched request_firmware_direct() nofile try #$1: " 248 config_reset 249 config_set_name nope-test-firmware.bin 250 config_set_sync_direct 251 config_trigger_sync 252 release_all_firmware 253 echo "OK" 254} 255 256test_request_firmware_nowait_uevent_nofile() 257{ 258 echo -n "Batched request_firmware_nowait(uevent=true) nofile try #$1: " 259 config_reset 260 config_set_name nope-test-firmware.bin 261 config_trigger_async 262 release_all_firmware 263 echo "OK" 264} 265 266test_wait_and_cancel_custom_load() 267{ 268 if [ "$HAS_FW_LOADER_USER_HELPER" != "yes" ]; then 269 return 270 fi 271 local timeout=10 272 name=$1 273 while [ ! -e "$DIR"/"$name"/loading ]; do 274 sleep 0.1 275 timeout=$(( $timeout - 1 )) 276 if [ "$timeout" -eq 0 ]; then 277 echo "firmware interface never appeared:" >&2 278 echo "$DIR/$name/loading" >&2 279 exit 1 280 fi 281 done 282 echo -1 >"$DIR"/"$name"/loading 283} 284 285test_request_firmware_nowait_custom_nofile() 286{ 287 echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: " 288 config_reset 289 config_unset_uevent 290 RANDOM_FILE_PATH=$(setup_random_file_fake) 291 RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 292 config_set_name $RANDOM_FILE 293 config_trigger_async & 294 test_wait_and_cancel_custom_load $RANDOM_FILE 295 wait 296 release_all_firmware 297 echo "OK" 298} 299 300test_batched_request_firmware() 301{ 302 echo -n "Batched request_firmware() $2 try #$1: " 303 config_reset 304 config_trigger_sync 305 read_firmwares $2 306 release_all_firmware 307 echo "OK" 308} 309 310test_batched_request_firmware_into_buf() 311{ 312 echo -n "Batched request_firmware_into_buf() $2 try #$1: " 313 config_reset 314 config_set_name $TEST_FIRMWARE_INTO_BUF_FILENAME 315 config_set_into_buf 316 config_trigger_sync 317 read_firmwares $2 318 release_all_firmware 319 echo "OK" 320} 321 322test_batched_request_firmware_direct() 323{ 324 echo -n "Batched request_firmware_direct() $2 try #$1: " 325 config_reset 326 config_set_sync_direct 327 config_trigger_sync 328 release_all_firmware 329 echo "OK" 330} 331 332test_request_firmware_nowait_uevent() 333{ 334 echo -n "Batched request_firmware_nowait(uevent=true) $2 try #$1: " 335 config_reset 336 config_trigger_async 337 release_all_firmware 338 echo "OK" 339} 340 341test_request_firmware_nowait_custom() 342{ 343 echo -n "Batched request_firmware_nowait(uevent=false) $2 try #$1: " 344 config_reset 345 config_unset_uevent 346 RANDOM_FILE_PATH=$(setup_random_file) 347 RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 348 if [ "$2" = "both" ]; then 349 xz -9 -C crc32 -k $RANDOM_FILE_PATH 350 elif [ "$2" = "xzonly" ]; then 351 xz -9 -C crc32 $RANDOM_FILE_PATH 352 fi 353 config_set_name $RANDOM_FILE 354 config_trigger_async 355 release_all_firmware 356 echo "OK" 357} 358 359# Only continue if batched request triggers are present on the 360# test-firmware driver 361test_config_present 362 363# test with the file present 364echo 365echo "Testing with the file present..." 366for i in $(seq 1 5); do 367 test_batched_request_firmware $i normal 368done 369 370for i in $(seq 1 5); do 371 test_batched_request_firmware_into_buf $i normal 372done 373 374for i in $(seq 1 5); do 375 test_batched_request_firmware_direct $i normal 376done 377 378for i in $(seq 1 5); do 379 test_request_firmware_nowait_uevent $i normal 380done 381 382for i in $(seq 1 5); do 383 test_request_firmware_nowait_custom $i normal 384done 385 386# Test for file not found, errors are expected, the failure would be 387# a hung task, which would require a hard reset. 388echo 389echo "Testing with the file missing..." 390for i in $(seq 1 5); do 391 test_batched_request_firmware_nofile $i 392done 393 394for i in $(seq 1 5); do 395 test_batched_request_firmware_into_buf_nofile $i 396done 397 398for i in $(seq 1 5); do 399 test_batched_request_firmware_direct_nofile $i 400done 401 402for i in $(seq 1 5); do 403 test_request_firmware_nowait_uevent_nofile $i 404done 405 406for i in $(seq 1 5); do 407 test_request_firmware_nowait_custom_nofile $i 408done 409 410test "$HAS_FW_LOADER_COMPRESS" != "yes" && exit 0 411 412# test with both files present 413xz -9 -C crc32 -k $FW 414config_set_name $NAME 415echo 416echo "Testing with both plain and xz files present..." 417for i in $(seq 1 5); do 418 test_batched_request_firmware $i both 419done 420 421for i in $(seq 1 5); do 422 test_batched_request_firmware_into_buf $i both 423done 424 425for i in $(seq 1 5); do 426 test_batched_request_firmware_direct $i both 427done 428 429for i in $(seq 1 5); do 430 test_request_firmware_nowait_uevent $i both 431done 432 433for i in $(seq 1 5); do 434 test_request_firmware_nowait_custom $i both 435done 436 437# test with only xz file present 438mv "$FW" "${FW}-orig" 439echo 440echo "Testing with only xz file present..." 441for i in $(seq 1 5); do 442 test_batched_request_firmware $i xzonly 443done 444 445for i in $(seq 1 5); do 446 test_batched_request_firmware_into_buf $i xzonly 447done 448 449for i in $(seq 1 5); do 450 test_batched_request_firmware_direct $i xzonly 451done 452 453for i in $(seq 1 5); do 454 test_request_firmware_nowait_uevent $i xzonly 455done 456 457for i in $(seq 1 5); do 458 test_request_firmware_nowait_custom $i xzonly 459done 460 461exit 0 462