18c2ecf20Sopenharmony_ci#!/bin/bash 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 38c2ecf20Sopenharmony_ci# This validates that the kernel will fall back to using the fallback mechanism 48c2ecf20Sopenharmony_ci# to load firmware it can't find on disk itself. We must request a firmware 58c2ecf20Sopenharmony_ci# that the kernel won't find, and any installed helper (e.g. udev) also 68c2ecf20Sopenharmony_ci# won't find so that we can do the load ourself manually. 78c2ecf20Sopenharmony_ciset -e 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ciTEST_REQS_FW_SYSFS_FALLBACK="yes" 108c2ecf20Sopenharmony_ciTEST_REQS_FW_SET_CUSTOM_PATH="no" 118c2ecf20Sopenharmony_ciTEST_DIR=$(dirname $0) 128c2ecf20Sopenharmony_cisource $TEST_DIR/fw_lib.sh 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cicheck_mods 158c2ecf20Sopenharmony_cicheck_setup 168c2ecf20Sopenharmony_civerify_reqs 178c2ecf20Sopenharmony_cisetup_tmp_file 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_citrap "test_finish" EXIT 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciload_fw() 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci local name="$1" 248c2ecf20Sopenharmony_ci local file="$2" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci # This will block until our load (below) has finished. 278c2ecf20Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_request & 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci # Give kernel a chance to react. 308c2ecf20Sopenharmony_ci local timeout=10 318c2ecf20Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 328c2ecf20Sopenharmony_ci sleep 0.1 338c2ecf20Sopenharmony_ci timeout=$(( $timeout - 1 )) 348c2ecf20Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 358c2ecf20Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 368c2ecf20Sopenharmony_ci exit 1 378c2ecf20Sopenharmony_ci fi 388c2ecf20Sopenharmony_ci done 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci echo 1 >"$DIR"/"$name"/loading 418c2ecf20Sopenharmony_ci cat "$file" >"$DIR"/"$name"/data 428c2ecf20Sopenharmony_ci echo 0 >"$DIR"/"$name"/loading 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci # Wait for request to finish. 458c2ecf20Sopenharmony_ci wait 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciload_fw_cancel() 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci local name="$1" 518c2ecf20Sopenharmony_ci local file="$2" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci # This will block until our load (below) has finished. 548c2ecf20Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_request 2>/dev/null & 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci # Give kernel a chance to react. 578c2ecf20Sopenharmony_ci local timeout=10 588c2ecf20Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 598c2ecf20Sopenharmony_ci sleep 0.1 608c2ecf20Sopenharmony_ci timeout=$(( $timeout - 1 )) 618c2ecf20Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 628c2ecf20Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 638c2ecf20Sopenharmony_ci exit 1 648c2ecf20Sopenharmony_ci fi 658c2ecf20Sopenharmony_ci done 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci echo -1 >"$DIR"/"$name"/loading 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci # Wait for request to finish. 708c2ecf20Sopenharmony_ci wait 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciload_fw_custom() 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci if [ ! -e "$DIR"/trigger_custom_fallback ]; then 768c2ecf20Sopenharmony_ci echo "$0: custom fallback trigger not present, ignoring test" >&2 778c2ecf20Sopenharmony_ci exit $ksft_skip 788c2ecf20Sopenharmony_ci fi 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci local name="$1" 818c2ecf20Sopenharmony_ci local file="$2" 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci # Give kernel a chance to react. 868c2ecf20Sopenharmony_ci local timeout=10 878c2ecf20Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 888c2ecf20Sopenharmony_ci sleep 0.1 898c2ecf20Sopenharmony_ci timeout=$(( $timeout - 1 )) 908c2ecf20Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 918c2ecf20Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 928c2ecf20Sopenharmony_ci exit 1 938c2ecf20Sopenharmony_ci fi 948c2ecf20Sopenharmony_ci done 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci echo 1 >"$DIR"/"$name"/loading 978c2ecf20Sopenharmony_ci cat "$file" >"$DIR"/"$name"/data 988c2ecf20Sopenharmony_ci echo 0 >"$DIR"/"$name"/loading 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci # Wait for request to finish. 1018c2ecf20Sopenharmony_ci wait 1028c2ecf20Sopenharmony_ci return 0 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciload_fw_custom_cancel() 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci if [ ! -e "$DIR"/trigger_custom_fallback ]; then 1098c2ecf20Sopenharmony_ci echo "$0: canceling custom fallback trigger not present, ignoring test" >&2 1108c2ecf20Sopenharmony_ci exit $ksft_skip 1118c2ecf20Sopenharmony_ci fi 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci local name="$1" 1148c2ecf20Sopenharmony_ci local file="$2" 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci # Give kernel a chance to react. 1198c2ecf20Sopenharmony_ci local timeout=10 1208c2ecf20Sopenharmony_ci while [ ! -e "$DIR"/"$name"/loading ]; do 1218c2ecf20Sopenharmony_ci sleep 0.1 1228c2ecf20Sopenharmony_ci timeout=$(( $timeout - 1 )) 1238c2ecf20Sopenharmony_ci if [ "$timeout" -eq 0 ]; then 1248c2ecf20Sopenharmony_ci echo "$0: firmware interface never appeared" >&2 1258c2ecf20Sopenharmony_ci exit 1 1268c2ecf20Sopenharmony_ci fi 1278c2ecf20Sopenharmony_ci done 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci echo -1 >"$DIR"/"$name"/loading 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci # Wait for request to finish. 1328c2ecf20Sopenharmony_ci wait 1338c2ecf20Sopenharmony_ci return 0 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciload_fw_fallback_with_child() 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci local name="$1" 1398c2ecf20Sopenharmony_ci local file="$2" 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci # This is the value already set but we want to be explicit 1428c2ecf20Sopenharmony_ci echo 4 >/sys/class/firmware/timeout 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci sleep 1 & 1458c2ecf20Sopenharmony_ci SECONDS_BEFORE=$(date +%s) 1468c2ecf20Sopenharmony_ci echo -n "$name" >"$DIR"/trigger_request 2>/dev/null 1478c2ecf20Sopenharmony_ci SECONDS_AFTER=$(date +%s) 1488c2ecf20Sopenharmony_ci SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE)) 1498c2ecf20Sopenharmony_ci if [ "$SECONDS_DELTA" -lt 4 ]; then 1508c2ecf20Sopenharmony_ci RET=1 1518c2ecf20Sopenharmony_ci else 1528c2ecf20Sopenharmony_ci RET=0 1538c2ecf20Sopenharmony_ci fi 1548c2ecf20Sopenharmony_ci wait 1558c2ecf20Sopenharmony_ci return $RET 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_citest_syfs_timeout() 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci DEVPATH="$DIR"/"nope-$NAME"/loading 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci # Test failure when doing nothing (timeout works). 1638c2ecf20Sopenharmony_ci echo -n 2 >/sys/class/firmware/timeout 1648c2ecf20Sopenharmony_ci echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci # Give the kernel some time to load the loading file, must be less 1678c2ecf20Sopenharmony_ci # than the timeout above. 1688c2ecf20Sopenharmony_ci sleep 1 1698c2ecf20Sopenharmony_ci if [ ! -f $DEVPATH ]; then 1708c2ecf20Sopenharmony_ci echo "$0: fallback mechanism immediately cancelled" 1718c2ecf20Sopenharmony_ci echo "" 1728c2ecf20Sopenharmony_ci echo "The file never appeared: $DEVPATH" 1738c2ecf20Sopenharmony_ci echo "" 1748c2ecf20Sopenharmony_ci echo "This might be a distribution udev rule setup by your distribution" 1758c2ecf20Sopenharmony_ci echo "to immediately cancel all fallback requests, this must be" 1768c2ecf20Sopenharmony_ci echo "removed before running these tests. To confirm look for" 1778c2ecf20Sopenharmony_ci echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules" 1788c2ecf20Sopenharmony_ci echo "and see if you have something like this:" 1798c2ecf20Sopenharmony_ci echo "" 1808c2ecf20Sopenharmony_ci echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" 1818c2ecf20Sopenharmony_ci echo "" 1828c2ecf20Sopenharmony_ci echo "If you do remove this file or comment out this line before" 1838c2ecf20Sopenharmony_ci echo "proceeding with these tests." 1848c2ecf20Sopenharmony_ci exit 1 1858c2ecf20Sopenharmony_ci fi 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if diff -q "$FW" /dev/test_firmware >/dev/null ; then 1888c2ecf20Sopenharmony_ci echo "$0: firmware was not expected to match" >&2 1898c2ecf20Sopenharmony_ci exit 1 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci echo "$0: timeout works" 1928c2ecf20Sopenharmony_ci fi 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cirun_sysfs_main_tests() 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci test_syfs_timeout 1988c2ecf20Sopenharmony_ci # Put timeout high enough for us to do work but not so long that failures 1998c2ecf20Sopenharmony_ci # slow down this test too much. 2008c2ecf20Sopenharmony_ci echo 4 >/sys/class/firmware/timeout 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci # Load this script instead of the desired firmware. 2038c2ecf20Sopenharmony_ci load_fw "$NAME" "$0" 2048c2ecf20Sopenharmony_ci if diff -q "$FW" /dev/test_firmware >/dev/null ; then 2058c2ecf20Sopenharmony_ci echo "$0: firmware was not expected to match" >&2 2068c2ecf20Sopenharmony_ci exit 1 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci echo "$0: firmware comparison works" 2098c2ecf20Sopenharmony_ci fi 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci # Do a proper load, which should work correctly. 2128c2ecf20Sopenharmony_ci load_fw "$NAME" "$FW" 2138c2ecf20Sopenharmony_ci if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 2148c2ecf20Sopenharmony_ci echo "$0: firmware was not loaded" >&2 2158c2ecf20Sopenharmony_ci exit 1 2168c2ecf20Sopenharmony_ci else 2178c2ecf20Sopenharmony_ci echo "$0: fallback mechanism works" 2188c2ecf20Sopenharmony_ci fi 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci load_fw_cancel "nope-$NAME" "$FW" 2218c2ecf20Sopenharmony_ci if diff -q "$FW" /dev/test_firmware >/dev/null ; then 2228c2ecf20Sopenharmony_ci echo "$0: firmware was expected to be cancelled" >&2 2238c2ecf20Sopenharmony_ci exit 1 2248c2ecf20Sopenharmony_ci else 2258c2ecf20Sopenharmony_ci echo "$0: cancelling fallback mechanism works" 2268c2ecf20Sopenharmony_ci fi 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci set +e 2298c2ecf20Sopenharmony_ci load_fw_fallback_with_child "nope-signal-$NAME" "$FW" 2308c2ecf20Sopenharmony_ci if [ "$?" -eq 0 ]; then 2318c2ecf20Sopenharmony_ci echo "$0: SIGCHLD on sync ignored as expected" >&2 2328c2ecf20Sopenharmony_ci else 2338c2ecf20Sopenharmony_ci echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2 2348c2ecf20Sopenharmony_ci exit 1 2358c2ecf20Sopenharmony_ci fi 2368c2ecf20Sopenharmony_ci set -e 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cirun_sysfs_custom_load_tests() 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci RANDOM_FILE_PATH=$(setup_random_file) 2428c2ecf20Sopenharmony_ci RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 2438c2ecf20Sopenharmony_ci if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then 2448c2ecf20Sopenharmony_ci if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then 2458c2ecf20Sopenharmony_ci echo "$0: firmware was not loaded" >&2 2468c2ecf20Sopenharmony_ci exit 1 2478c2ecf20Sopenharmony_ci else 2488c2ecf20Sopenharmony_ci echo "$0: custom fallback loading mechanism works" 2498c2ecf20Sopenharmony_ci fi 2508c2ecf20Sopenharmony_ci fi 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci RANDOM_FILE_PATH=$(setup_random_file) 2538c2ecf20Sopenharmony_ci RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 2548c2ecf20Sopenharmony_ci if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then 2558c2ecf20Sopenharmony_ci if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then 2568c2ecf20Sopenharmony_ci echo "$0: firmware was not loaded" >&2 2578c2ecf20Sopenharmony_ci exit 1 2588c2ecf20Sopenharmony_ci else 2598c2ecf20Sopenharmony_ci echo "$0: custom fallback loading mechanism works" 2608c2ecf20Sopenharmony_ci fi 2618c2ecf20Sopenharmony_ci fi 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci RANDOM_FILE_REAL="$RANDOM_FILE_PATH" 2648c2ecf20Sopenharmony_ci FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake) 2658c2ecf20Sopenharmony_ci FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)" 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then 2688c2ecf20Sopenharmony_ci if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then 2698c2ecf20Sopenharmony_ci echo "$0: firmware was expected to be cancelled" >&2 2708c2ecf20Sopenharmony_ci exit 1 2718c2ecf20Sopenharmony_ci else 2728c2ecf20Sopenharmony_ci echo "$0: cancelling custom fallback mechanism works" 2738c2ecf20Sopenharmony_ci fi 2748c2ecf20Sopenharmony_ci fi 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ciif [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then 2788c2ecf20Sopenharmony_ci run_sysfs_main_tests 2798c2ecf20Sopenharmony_cifi 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cirun_sysfs_custom_load_tests 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciexit 0 284