Path: blob/master/tools/testing/selftests/firmware/fw_fallback.sh
26285 views
#!/bin/bash1# SPDX-License-Identifier: GPL-2.02# This validates that the kernel will fall back to using the fallback mechanism3# to load firmware it can't find on disk itself. We must request a firmware4# that the kernel won't find, and any installed helper (e.g. udev) also5# won't find so that we can do the load ourself manually.6set -e78TEST_REQS_FW_SYSFS_FALLBACK="yes"9TEST_REQS_FW_SET_CUSTOM_PATH="no"10TEST_DIR=$(dirname $0)11source $TEST_DIR/fw_lib.sh1213check_mods14check_setup15verify_reqs16setup_tmp_file1718trap "test_finish" EXIT1920load_fw()21{22local name="$1"23local file="$2"2425# This will block until our load (below) has finished.26echo -n "$name" >"$DIR"/trigger_request &2728# Give kernel a chance to react.29local timeout=1030while [ ! -e "$DIR"/"$name"/loading ]; do31sleep 0.132timeout=$(( $timeout - 1 ))33if [ "$timeout" -eq 0 ]; then34echo "$0: firmware interface never appeared" >&235exit 136fi37done3839echo 1 >"$DIR"/"$name"/loading40cat "$file" >"$DIR"/"$name"/data41echo 0 >"$DIR"/"$name"/loading4243# Wait for request to finish.44wait45}4647load_fw_cancel()48{49local name="$1"50local file="$2"5152# This will block until our load (below) has finished.53echo -n "$name" >"$DIR"/trigger_request 2>/dev/null &5455# Give kernel a chance to react.56local timeout=1057while [ ! -e "$DIR"/"$name"/loading ]; do58sleep 0.159timeout=$(( $timeout - 1 ))60if [ "$timeout" -eq 0 ]; then61echo "$0: firmware interface never appeared" >&262exit 163fi64done6566echo -1 >"$DIR"/"$name"/loading6768# Wait for request to finish.69wait70}7172load_fw_custom()73{74if [ ! -e "$DIR"/trigger_custom_fallback ]; then75echo "$0: custom fallback trigger not present, ignoring test" >&276exit $ksft_skip77fi7879local name="$1"80local file="$2"8182echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &8384# Give kernel a chance to react.85local timeout=1086while [ ! -e "$DIR"/"$name"/loading ]; do87sleep 0.188timeout=$(( $timeout - 1 ))89if [ "$timeout" -eq 0 ]; then90echo "$0: firmware interface never appeared" >&291exit 192fi93done9495echo 1 >"$DIR"/"$name"/loading96cat "$file" >"$DIR"/"$name"/data97echo 0 >"$DIR"/"$name"/loading9899# Wait for request to finish.100wait101return 0102}103104105load_fw_custom_cancel()106{107if [ ! -e "$DIR"/trigger_custom_fallback ]; then108echo "$0: canceling custom fallback trigger not present, ignoring test" >&2109exit $ksft_skip110fi111112local name="$1"113local file="$2"114115echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &116117# Give kernel a chance to react.118local timeout=10119while [ ! -e "$DIR"/"$name"/loading ]; do120sleep 0.1121timeout=$(( $timeout - 1 ))122if [ "$timeout" -eq 0 ]; then123echo "$0: firmware interface never appeared" >&2124exit 1125fi126done127128echo -1 >"$DIR"/"$name"/loading129130# Wait for request to finish.131wait132return 0133}134135load_fw_fallback_with_child()136{137local name="$1"138local file="$2"139140# This is the value already set but we want to be explicit141echo 4 >/sys/class/firmware/timeout142143sleep 1 &144SECONDS_BEFORE=$(date +%s)145echo -n "$name" >"$DIR"/trigger_request 2>/dev/null146SECONDS_AFTER=$(date +%s)147SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE))148if [ "$SECONDS_DELTA" -lt 4 ]; then149RET=1150else151RET=0152fi153wait154return $RET155}156157test_syfs_timeout()158{159DEVPATH="$DIR"/"nope-$NAME"/loading160161# Test failure when doing nothing (timeout works).162echo -n 2 >/sys/class/firmware/timeout163echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null &164165# Give the kernel some time to load the loading file, must be less166# than the timeout above.167sleep 1168if [ ! -f $DEVPATH ]; then169echo "$0: fallback mechanism immediately cancelled"170echo ""171echo "The file never appeared: $DEVPATH"172echo ""173echo "This might be a distribution udev rule setup by your distribution"174echo "to immediately cancel all fallback requests, this must be"175echo "removed before running these tests. To confirm look for"176echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"177echo "and see if you have something like this:"178echo ""179echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""180echo ""181echo "If you do remove this file or comment out this line before"182echo "proceeding with these tests."183exit 1184fi185186if diff -q "$FW" /dev/test_firmware >/dev/null ; then187echo "$0: firmware was not expected to match" >&2188exit 1189else190echo "$0: timeout works"191fi192}193194run_sysfs_main_tests()195{196test_syfs_timeout197# Put timeout high enough for us to do work but not so long that failures198# slow down this test too much.199echo 4 >/sys/class/firmware/timeout200201# Load this script instead of the desired firmware.202load_fw "$NAME" "$0"203if diff -q "$FW" /dev/test_firmware >/dev/null ; then204echo "$0: firmware was not expected to match" >&2205exit 1206else207echo "$0: firmware comparison works"208fi209210# Do a proper load, which should work correctly.211load_fw "$NAME" "$FW"212if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then213echo "$0: firmware was not loaded" >&2214exit 1215else216echo "$0: fallback mechanism works"217fi218219load_fw_cancel "nope-$NAME" "$FW"220if diff -q "$FW" /dev/test_firmware >/dev/null ; then221echo "$0: firmware was expected to be cancelled" >&2222exit 1223else224echo "$0: cancelling fallback mechanism works"225fi226227set +e228load_fw_fallback_with_child "nope-signal-$NAME" "$FW"229if [ "$?" -eq 0 ]; then230echo "$0: SIGCHLD on sync ignored as expected" >&2231else232echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2233exit 1234fi235set -e236}237238run_sysfs_custom_load_tests()239{240RANDOM_FILE_PATH=$(setup_random_file)241RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"242if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then243if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then244echo "$0: firmware was not loaded" >&2245exit 1246else247echo "$0: custom fallback loading mechanism works"248fi249fi250251RANDOM_FILE_PATH=$(setup_random_file)252RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"253if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then254if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then255echo "$0: firmware was not loaded" >&2256exit 1257else258echo "$0: custom fallback loading mechanism works"259fi260fi261262RANDOM_FILE_REAL="$RANDOM_FILE_PATH"263FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake)264FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)"265266if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then267if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then268echo "$0: firmware was expected to be cancelled" >&2269exit 1270else271echo "$0: cancelling custom fallback mechanism works"272fi273fi274}275276if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then277run_sysfs_main_tests278fi279280run_sysfs_custom_load_tests281282exit 0283284285