162306a36Sopenharmony_ci#!/bin/bash 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 362306a36Sopenharmony_ci# This validates that the kernel will fall back to using the fallback mechanism 462306a36Sopenharmony_ci# to load firmware it can't find on disk itself. We must request a firmware 562306a36Sopenharmony_ci# that the kernel won't find, and any installed helper (e.g. udev) also 662306a36Sopenharmony_ci# won't find so that we can do the load ourself manually. 762306a36Sopenharmony_ciset -e 862306a36Sopenharmony_ci 962306a36Sopenharmony_ciTEST_REQS_FW_SYSFS_FALLBACK="yes" 1062306a36Sopenharmony_ciTEST_REQS_FW_SET_CUSTOM_PATH="no" 1162306a36Sopenharmony_ciTEST_DIR=$(dirname $0) 1262306a36Sopenharmony_cisource $TEST_DIR/fw_lib.sh 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cicheck_mods 1562306a36Sopenharmony_cicheck_setup 1662306a36Sopenharmony_civerify_reqs 1762306a36Sopenharmony_cisetup_tmp_file 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_citrap "test_finish" EXIT 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciload_fw() 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci local name="$1" 2462306a36Sopenharmony_ci local file="$2" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci # This will block until our load (below) has finished. 2762306a36Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_request & 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci # Give kernel a chance to react. 3062306a36Sopenharmony_ci local timeout=10 3162306a36Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 3262306a36Sopenharmony_ci sleep 0.1 3362306a36Sopenharmony_ci timeout=$(( $timeout - 1 )) 3462306a36Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 3562306a36Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 3662306a36Sopenharmony_ci exit 1 3762306a36Sopenharmony_ci fi 3862306a36Sopenharmony_ci done 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci echo 1 >"$DIR"/"$name"/loading 4162306a36Sopenharmony_ci cat "$file" >"$DIR"/"$name"/data 4262306a36Sopenharmony_ci echo 0 >"$DIR"/"$name"/loading 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci # Wait for request to finish. 4562306a36Sopenharmony_ci wait 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciload_fw_cancel() 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci local name="$1" 5162306a36Sopenharmony_ci local file="$2" 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci # This will block until our load (below) has finished. 5462306a36Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_request 2>/dev/null & 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci # Give kernel a chance to react. 5762306a36Sopenharmony_ci local timeout=10 5862306a36Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 5962306a36Sopenharmony_ci sleep 0.1 6062306a36Sopenharmony_ci timeout=$(( $timeout - 1 )) 6162306a36Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 6262306a36Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 6362306a36Sopenharmony_ci exit 1 6462306a36Sopenharmony_ci fi 6562306a36Sopenharmony_ci done 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci echo -1 >"$DIR"/"$name"/loading 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci # Wait for request to finish. 7062306a36Sopenharmony_ci wait 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciload_fw_custom() 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci if [ ! -e "$DIR"/trigger_custom_fallback ]; then 7662306a36Sopenharmony_ci echo "$0: custom fallback trigger not present, ignoring test" >&2 7762306a36Sopenharmony_ci exit $ksft_skip 7862306a36Sopenharmony_ci fi 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci local name="$1" 8162306a36Sopenharmony_ci local file="$2" 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci # Give kernel a chance to react. 8662306a36Sopenharmony_ci local timeout=10 8762306a36Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 8862306a36Sopenharmony_ci sleep 0.1 8962306a36Sopenharmony_ci timeout=$(( $timeout - 1 )) 9062306a36Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 9162306a36Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 9262306a36Sopenharmony_ci exit 1 9362306a36Sopenharmony_ci fi 9462306a36Sopenharmony_ci done 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci echo 1 >"$DIR"/"$name"/loading 9762306a36Sopenharmony_ci cat "$file" >"$DIR"/"$name"/data 9862306a36Sopenharmony_ci echo 0 >"$DIR"/"$name"/loading 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci # Wait for request to finish. 10162306a36Sopenharmony_ci wait 10262306a36Sopenharmony_ci return 0 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciload_fw_custom_cancel() 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci if [ ! -e "$DIR"/trigger_custom_fallback ]; then 10962306a36Sopenharmony_ci echo "$0: canceling custom fallback trigger not present, ignoring test" >&2 11062306a36Sopenharmony_ci exit $ksft_skip 11162306a36Sopenharmony_ci fi 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci local name="$1" 11462306a36Sopenharmony_ci local file="$2" 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci # Give kernel a chance to react. 11962306a36Sopenharmony_ci local timeout=10 12062306a36Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 12162306a36Sopenharmony_ci sleep 0.1 12262306a36Sopenharmony_ci timeout=$(( $timeout - 1 )) 12362306a36Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 12462306a36Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 12562306a36Sopenharmony_ci exit 1 12662306a36Sopenharmony_ci fi 12762306a36Sopenharmony_ci done 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci echo -1 >"$DIR"/"$name"/loading 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci # Wait for request to finish. 13262306a36Sopenharmony_ci wait 13362306a36Sopenharmony_ci return 0 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciload_fw_fallback_with_child() 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci local name="$1" 13962306a36Sopenharmony_ci local file="$2" 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci # This is the value already set but we want to be explicit 14262306a36Sopenharmony_ci echo 4 >/sys/class/firmware/timeout 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci sleep 1 & 14562306a36Sopenharmony_ci SECONDS_BEFORE=$(date +%s) 14662306a36Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_request 2>/dev/null 14762306a36Sopenharmony_ci SECONDS_AFTER=$(date +%s) 14862306a36Sopenharmony_ci SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE)) 14962306a36Sopenharmony_ci if [ "$SECONDS_DELTA" -lt 4 ]; then 15062306a36Sopenharmony_ci RET=1 15162306a36Sopenharmony_ci else 15262306a36Sopenharmony_ci RET=0 15362306a36Sopenharmony_ci fi 15462306a36Sopenharmony_ci wait 15562306a36Sopenharmony_ci return $RET 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_citest_syfs_timeout() 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci DEVPATH="$DIR"/"nope-$NAME"/loading 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci # Test failure when doing nothing (timeout works). 16362306a36Sopenharmony_ci echo -n 2 >/sys/class/firmware/timeout 16462306a36Sopenharmony_ci echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci # Give the kernel some time to load the loading file, must be less 16762306a36Sopenharmony_ci # than the timeout above. 16862306a36Sopenharmony_ci sleep 1 16962306a36Sopenharmony_ci if [ ! -f $DEVPATH ]; then 17062306a36Sopenharmony_ci echo "$0: fallback mechanism immediately cancelled" 17162306a36Sopenharmony_ci echo "" 17262306a36Sopenharmony_ci echo "The file never appeared: $DEVPATH" 17362306a36Sopenharmony_ci echo "" 17462306a36Sopenharmony_ci echo "This might be a distribution udev rule setup by your distribution" 17562306a36Sopenharmony_ci echo "to immediately cancel all fallback requests, this must be" 17662306a36Sopenharmony_ci echo "removed before running these tests. To confirm look for" 17762306a36Sopenharmony_ci echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules" 17862306a36Sopenharmony_ci echo "and see if you have something like this:" 17962306a36Sopenharmony_ci echo "" 18062306a36Sopenharmony_ci echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" 18162306a36Sopenharmony_ci echo "" 18262306a36Sopenharmony_ci echo "If you do remove this file or comment out this line before" 18362306a36Sopenharmony_ci echo "proceeding with these tests." 18462306a36Sopenharmony_ci exit 1 18562306a36Sopenharmony_ci fi 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if diff -q "$FW" /dev/test_firmware >/dev/null ; then 18862306a36Sopenharmony_ci echo "$0: firmware was not expected to match" >&2 18962306a36Sopenharmony_ci exit 1 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci echo "$0: timeout works" 19262306a36Sopenharmony_ci fi 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cirun_sysfs_main_tests() 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci test_syfs_timeout 19862306a36Sopenharmony_ci # Put timeout high enough for us to do work but not so long that failures 19962306a36Sopenharmony_ci # slow down this test too much. 20062306a36Sopenharmony_ci echo 4 >/sys/class/firmware/timeout 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci # Load this script instead of the desired firmware. 20362306a36Sopenharmony_ci load_fw "$NAME" "$0" 20462306a36Sopenharmony_ci if diff -q "$FW" /dev/test_firmware >/dev/null ; then 20562306a36Sopenharmony_ci echo "$0: firmware was not expected to match" >&2 20662306a36Sopenharmony_ci exit 1 20762306a36Sopenharmony_ci else 20862306a36Sopenharmony_ci echo "$0: firmware comparison works" 20962306a36Sopenharmony_ci fi 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci # Do a proper load, which should work correctly. 21262306a36Sopenharmony_ci load_fw "$NAME" "$FW" 21362306a36Sopenharmony_ci if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 21462306a36Sopenharmony_ci echo "$0: firmware was not loaded" >&2 21562306a36Sopenharmony_ci exit 1 21662306a36Sopenharmony_ci else 21762306a36Sopenharmony_ci echo "$0: fallback mechanism works" 21862306a36Sopenharmony_ci fi 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci load_fw_cancel "nope-$NAME" "$FW" 22162306a36Sopenharmony_ci if diff -q "$FW" /dev/test_firmware >/dev/null ; then 22262306a36Sopenharmony_ci echo "$0: firmware was expected to be cancelled" >&2 22362306a36Sopenharmony_ci exit 1 22462306a36Sopenharmony_ci else 22562306a36Sopenharmony_ci echo "$0: cancelling fallback mechanism works" 22662306a36Sopenharmony_ci fi 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci set +e 22962306a36Sopenharmony_ci load_fw_fallback_with_child "nope-signal-$NAME" "$FW" 23062306a36Sopenharmony_ci if [ "$?" -eq 0 ]; then 23162306a36Sopenharmony_ci echo "$0: SIGCHLD on sync ignored as expected" >&2 23262306a36Sopenharmony_ci else 23362306a36Sopenharmony_ci echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2 23462306a36Sopenharmony_ci exit 1 23562306a36Sopenharmony_ci fi 23662306a36Sopenharmony_ci set -e 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cirun_sysfs_custom_load_tests() 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci RANDOM_FILE_PATH=$(setup_random_file) 24262306a36Sopenharmony_ci RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 24362306a36Sopenharmony_ci if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then 24462306a36Sopenharmony_ci if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then 24562306a36Sopenharmony_ci echo "$0: firmware was not loaded" >&2 24662306a36Sopenharmony_ci exit 1 24762306a36Sopenharmony_ci else 24862306a36Sopenharmony_ci echo "$0: custom fallback loading mechanism works" 24962306a36Sopenharmony_ci fi 25062306a36Sopenharmony_ci fi 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci RANDOM_FILE_PATH=$(setup_random_file) 25362306a36Sopenharmony_ci RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 25462306a36Sopenharmony_ci if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then 25562306a36Sopenharmony_ci if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then 25662306a36Sopenharmony_ci echo "$0: firmware was not loaded" >&2 25762306a36Sopenharmony_ci exit 1 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci echo "$0: custom fallback loading mechanism works" 26062306a36Sopenharmony_ci fi 26162306a36Sopenharmony_ci fi 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci RANDOM_FILE_REAL="$RANDOM_FILE_PATH" 26462306a36Sopenharmony_ci FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake) 26562306a36Sopenharmony_ci FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)" 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then 26862306a36Sopenharmony_ci if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then 26962306a36Sopenharmony_ci echo "$0: firmware was expected to be cancelled" >&2 27062306a36Sopenharmony_ci exit 1 27162306a36Sopenharmony_ci else 27262306a36Sopenharmony_ci echo "$0: cancelling custom fallback mechanism works" 27362306a36Sopenharmony_ci fi 27462306a36Sopenharmony_ci fi 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ciif [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then 27862306a36Sopenharmony_ci run_sysfs_main_tests 27962306a36Sopenharmony_cifi 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cirun_sysfs_custom_load_tests 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ciexit 0 284