#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # This validates that the kernel will load firmware out of its list of # firmware locations on disk. Since the user helper does similar work, # we reset the custom load directory to a location the user helper doesn't # know so we can be sure we're not accidentally testing the user helper. set -e TEST_REQS_FW_SYSFS_FALLBACK="no" TEST_REQS_FW_SET_CUSTOM_PATH="yes" TEST_DIR=$(dirname $0) source $TEST_DIR/fw_lib.sh check_mods check_setup verify_reqs setup_tmp_file trap "test_finish" EXIT if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then # Turn down the timeout so failures don't take so long. echo 1 >/sys/class/firmware/timeout fi if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then echo "$0: empty filename should not succeed" >&2 exit 1 fi if [ ! -e "$DIR"/trigger_async_request ]; then echo "$0: empty filename: async trigger not present, ignoring test" >&2 exit $ksft_skip else if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then echo "$0: empty filename should not succeed (async)" >&2 exit 1 fi fi # Request a firmware that doesn't exist, it should fail. if echo -n "nope-$NAME" >"$DIR"/trigger_request 2> /dev/null; then echo "$0: firmware shouldn't have loaded" >&2 exit 1 fi if diff -q "$FW" /dev/test_firmware >/dev/null ; then echo "$0: firmware was not expected to match" >&2 exit 1 else if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then echo "$0: timeout works" fi fi # This should succeed via kernel load or will fail after 1 second after # being handed over to the user helper, which won't find the fw either. if ! echo -n "$NAME" >"$DIR"/trigger_request ; then echo "$0: could not trigger request" >&2 exit 1 fi # Verify the contents are what we expect. if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then echo "$0: firmware was not loaded" >&2 exit 1 else echo "$0: filesystem loading works" fi # Try the asynchronous version too if [ ! -e "$DIR"/trigger_async_request ]; then echo "$0: firmware loading: async trigger not present, ignoring test" >&2 exit $ksft_skip else if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then echo "$0: could not trigger async request" >&2 exit 1 fi # Verify the contents are what we expect. if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then echo "$0: firmware was not loaded (async)" >&2 exit 1 else echo "$0: async filesystem loading works" fi fi ### Batched requests tests test_config_present() { if [ ! -f $DIR/reset ]; then echo "Configuration triggers not present, ignoring test" exit $ksft_skip fi } # Defaults : # # send_uevent: 1 # sync_direct: 0 # name: test-firmware.bin # num_requests: 4 config_reset() { echo 1 > $DIR/reset } release_all_firmware() { echo 1 > $DIR/release_all_firmware } config_set_name() { echo -n $1 > $DIR/config_name } config_set_sync_direct() { echo 1 > $DIR/config_sync_direct } config_unset_sync_direct() { echo 0 > $DIR/config_sync_direct } config_set_uevent() { echo 1 > $DIR/config_send_uevent } config_unset_uevent() { echo 0 > $DIR/config_send_uevent } config_trigger_sync() { echo -n 1 > $DIR/trigger_batched_requests 2>/dev/null } config_trigger_async() { echo -n 1 > $DIR/trigger_batched_requests_async 2> /dev/null } config_set_read_fw_idx() { echo -n $1 > $DIR/config_read_fw_idx 2> /dev/null } read_firmwares() { for i in $(seq 0 3); do config_set_read_fw_idx $i # Verify the contents are what we expect. # -Z required for now -- check for yourself, md5sum # on $FW and DIR/read_firmware will yield the same. Even # cmp agrees, so something is off. if ! diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then echo "request #$i: firmware was not loaded" >&2 exit 1 fi done } read_firmwares_expect_nofile() { for i in $(seq 0 3); do config_set_read_fw_idx $i # Ensures contents differ if diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then echo "request $i: file was not expected to match" >&2 exit 1 fi done } test_batched_request_firmware_nofile() { echo -n "Batched request_firmware() nofile try #$1: " config_reset config_set_name nope-test-firmware.bin config_trigger_sync read_firmwares_expect_nofile release_all_firmware echo "OK" } test_batched_request_firmware_direct_nofile() { echo -n "Batched request_firmware_direct() nofile try #$1: " config_reset config_set_name nope-test-firmware.bin config_set_sync_direct config_trigger_sync release_all_firmware echo "OK" } test_request_firmware_nowait_uevent_nofile() { echo -n "Batched request_firmware_nowait(uevent=true) nofile try #$1: " config_reset config_set_name nope-test-firmware.bin config_trigger_async release_all_firmware echo "OK" } test_wait_and_cancel_custom_load() { if [ "$HAS_FW_LOADER_USER_HELPER" != "yes" ]; then return fi local timeout=10 name=$1 while [ ! -e "$DIR"/"$name"/loading ]; do sleep 0.1 timeout=$(( $timeout - 1 )) if [ "$timeout" -eq 0 ]; then echo "firmware interface never appeared:" >&2 echo "$DIR/$name/loading" >&2 exit 1 fi done echo -1 >"$DIR"/"$name"/loading } test_request_firmware_nowait_custom_nofile() { echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: " config_reset config_unset_uevent RANDOM_FILE_PATH=$(setup_random_file_fake) RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" config_set_name $RANDOM_FILE config_trigger_async & test_wait_and_cancel_custom_load $RANDOM_FILE wait release_all_firmware echo "OK" } test_batched_request_firmware() { echo -n "Batched request_firmware() try #$1: " config_reset config_trigger_sync read_firmwares release_all_firmware echo "OK" } test_batched_request_firmware_direct() { echo -n "Batched request_firmware_direct() try #$1: " config_reset config_set_sync_direct config_trigger_sync release_all_firmware echo "OK" } test_request_firmware_nowait_uevent() { echo -n "Batched request_firmware_nowait(uevent=true) try #$1: " config_reset config_trigger_async release_all_firmware echo "OK" } test_request_firmware_nowait_custom() { echo -n "Batched request_firmware_nowait(uevent=false) try #$1: " config_reset config_unset_uevent RANDOM_FILE_PATH=$(setup_random_file) RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" config_set_name $RANDOM_FILE config_trigger_async release_all_firmware echo "OK" } # Only continue if batched request triggers are present on the # test-firmware driver test_config_present # test with the file present echo echo "Testing with the file present..." for i in $(seq 1 5); do test_batched_request_firmware $i done for i in $(seq 1 5); do test_batched_request_firmware_direct $i done for i in $(seq 1 5); do test_request_firmware_nowait_uevent $i done for i in $(seq 1 5); do test_request_firmware_nowait_custom $i done # Test for file not found, errors are expected, the failure would be # a hung task, which would require a hard reset. echo echo "Testing with the file missing..." for i in $(seq 1 5); do test_batched_request_firmware_nofile $i done for i in $(seq 1 5); do test_batched_request_firmware_direct_nofile $i done for i in $(seq 1 5); do test_request_firmware_nowait_uevent_nofile $i done for i in $(seq 1 5); do test_request_firmware_nowait_custom_nofile $i done exit 0