284 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03# This validates that the kernel will fall back to using the fallback mechanism4# to load firmware it can't find on disk itself. We must request a firmware5# that the kernel won't find, and any installed helper (e.g. udev) also6# won't find so that we can do the load ourself manually.7set -e8 9TEST_REQS_FW_SYSFS_FALLBACK="yes"10TEST_REQS_FW_SET_CUSTOM_PATH="no"11TEST_DIR=$(dirname $0)12source $TEST_DIR/fw_lib.sh13 14check_mods15check_setup16verify_reqs17setup_tmp_file18 19trap "test_finish" EXIT20 21load_fw()22{23 local name="$1"24 local file="$2"25 26 # This will block until our load (below) has finished.27 echo -n "$name" >"$DIR"/trigger_request &28 29 # Give kernel a chance to react.30 local timeout=1031 while [ ! -e "$DIR"/"$name"/loading ]; do32 sleep 0.133 timeout=$(( $timeout - 1 ))34 if [ "$timeout" -eq 0 ]; then35 echo "$0: firmware interface never appeared" >&236 exit 137 fi38 done39 40 echo 1 >"$DIR"/"$name"/loading41 cat "$file" >"$DIR"/"$name"/data42 echo 0 >"$DIR"/"$name"/loading43 44 # Wait for request to finish.45 wait46}47 48load_fw_cancel()49{50 local name="$1"51 local file="$2"52 53 # This will block until our load (below) has finished.54 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null &55 56 # Give kernel a chance to react.57 local timeout=1058 while [ ! -e "$DIR"/"$name"/loading ]; do59 sleep 0.160 timeout=$(( $timeout - 1 ))61 if [ "$timeout" -eq 0 ]; then62 echo "$0: firmware interface never appeared" >&263 exit 164 fi65 done66 67 echo -1 >"$DIR"/"$name"/loading68 69 # Wait for request to finish.70 wait71}72 73load_fw_custom()74{75 if [ ! -e "$DIR"/trigger_custom_fallback ]; then76 echo "$0: custom fallback trigger not present, ignoring test" >&277 exit $ksft_skip78 fi79 80 local name="$1"81 local file="$2"82 83 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &84 85 # Give kernel a chance to react.86 local timeout=1087 while [ ! -e "$DIR"/"$name"/loading ]; do88 sleep 0.189 timeout=$(( $timeout - 1 ))90 if [ "$timeout" -eq 0 ]; then91 echo "$0: firmware interface never appeared" >&292 exit 193 fi94 done95 96 echo 1 >"$DIR"/"$name"/loading97 cat "$file" >"$DIR"/"$name"/data98 echo 0 >"$DIR"/"$name"/loading99 100 # Wait for request to finish.101 wait102 return 0103}104 105 106load_fw_custom_cancel()107{108 if [ ! -e "$DIR"/trigger_custom_fallback ]; then109 echo "$0: canceling custom fallback trigger not present, ignoring test" >&2110 exit $ksft_skip111 fi112 113 local name="$1"114 local file="$2"115 116 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &117 118 # Give kernel a chance to react.119 local timeout=10120 while [ ! -e "$DIR"/"$name"/loading ]; do121 sleep 0.1122 timeout=$(( $timeout - 1 ))123 if [ "$timeout" -eq 0 ]; then124 echo "$0: firmware interface never appeared" >&2125 exit 1126 fi127 done128 129 echo -1 >"$DIR"/"$name"/loading130 131 # Wait for request to finish.132 wait133 return 0134}135 136load_fw_fallback_with_child()137{138 local name="$1"139 local file="$2"140 141 # This is the value already set but we want to be explicit142 echo 4 >/sys/class/firmware/timeout143 144 sleep 1 &145 SECONDS_BEFORE=$(date +%s)146 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null147 SECONDS_AFTER=$(date +%s)148 SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE))149 if [ "$SECONDS_DELTA" -lt 4 ]; then150 RET=1151 else152 RET=0153 fi154 wait155 return $RET156}157 158test_syfs_timeout()159{160 DEVPATH="$DIR"/"nope-$NAME"/loading161 162 # Test failure when doing nothing (timeout works).163 echo -n 2 >/sys/class/firmware/timeout164 echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null &165 166 # Give the kernel some time to load the loading file, must be less167 # than the timeout above.168 sleep 1169 if [ ! -f $DEVPATH ]; then170 echo "$0: fallback mechanism immediately cancelled"171 echo ""172 echo "The file never appeared: $DEVPATH"173 echo ""174 echo "This might be a distribution udev rule setup by your distribution"175 echo "to immediately cancel all fallback requests, this must be"176 echo "removed before running these tests. To confirm look for"177 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"178 echo "and see if you have something like this:"179 echo ""180 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""181 echo ""182 echo "If you do remove this file or comment out this line before"183 echo "proceeding with these tests."184 exit 1185 fi186 187 if diff -q "$FW" /dev/test_firmware >/dev/null ; then188 echo "$0: firmware was not expected to match" >&2189 exit 1190 else191 echo "$0: timeout works"192 fi193}194 195run_sysfs_main_tests()196{197 test_syfs_timeout198 # Put timeout high enough for us to do work but not so long that failures199 # slow down this test too much.200 echo 4 >/sys/class/firmware/timeout201 202 # Load this script instead of the desired firmware.203 load_fw "$NAME" "$0"204 if diff -q "$FW" /dev/test_firmware >/dev/null ; then205 echo "$0: firmware was not expected to match" >&2206 exit 1207 else208 echo "$0: firmware comparison works"209 fi210 211 # Do a proper load, which should work correctly.212 load_fw "$NAME" "$FW"213 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then214 echo "$0: firmware was not loaded" >&2215 exit 1216 else217 echo "$0: fallback mechanism works"218 fi219 220 load_fw_cancel "nope-$NAME" "$FW"221 if diff -q "$FW" /dev/test_firmware >/dev/null ; then222 echo "$0: firmware was expected to be cancelled" >&2223 exit 1224 else225 echo "$0: cancelling fallback mechanism works"226 fi227 228 set +e229 load_fw_fallback_with_child "nope-signal-$NAME" "$FW"230 if [ "$?" -eq 0 ]; then231 echo "$0: SIGCHLD on sync ignored as expected" >&2232 else233 echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2234 exit 1235 fi236 set -e237}238 239run_sysfs_custom_load_tests()240{241 RANDOM_FILE_PATH=$(setup_random_file)242 RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"243 if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then244 if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then245 echo "$0: firmware was not loaded" >&2246 exit 1247 else248 echo "$0: custom fallback loading mechanism works"249 fi250 fi251 252 RANDOM_FILE_PATH=$(setup_random_file)253 RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"254 if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then255 if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then256 echo "$0: firmware was not loaded" >&2257 exit 1258 else259 echo "$0: custom fallback loading mechanism works"260 fi261 fi262 263 RANDOM_FILE_REAL="$RANDOM_FILE_PATH"264 FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake)265 FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)"266 267 if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then268 if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then269 echo "$0: firmware was expected to be cancelled" >&2270 exit 1271 else272 echo "$0: cancelling custom fallback mechanism works"273 fi274 fi275}276 277if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then278 run_sysfs_main_tests279fi280 281run_sysfs_custom_load_tests282 283exit 0284