1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# This validates that the kernel will fall back to using the fallback mechanism 4# to load firmware it can't find on disk itself. We must request a firmware 5# that the kernel won't find, and any installed helper (e.g. udev) also 6# won't find so that we can do the load ourself manually. 7set -e 8 9TEST_REQS_FW_SYSFS_FALLBACK="yes" 10TEST_REQS_FW_SET_CUSTOM_PATH="no" 11TEST_DIR=$(dirname $0) 12source $TEST_DIR/fw_lib.sh 13 14check_mods 15check_setup 16verify_reqs 17setup_tmp_file 18 19trap "test_finish" EXIT 20 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=10 31 while [ ! -e "$DIR"/"$name"/loading ]; do 32 sleep 0.1 33 timeout=$(( $timeout - 1 )) 34 if [ "$timeout" -eq 0 ]; then 35 echo "$0: firmware interface never appeared" >&2 36 exit 1 37 fi 38 done 39 40 echo 1 >"$DIR"/"$name"/loading 41 cat "$file" >"$DIR"/"$name"/data 42 echo 0 >"$DIR"/"$name"/loading 43 44 # Wait for request to finish. 45 wait 46} 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=10 58 while [ ! -e "$DIR"/"$name"/loading ]; do 59 sleep 0.1 60 timeout=$(( $timeout - 1 )) 61 if [ "$timeout" -eq 0 ]; then 62 echo "$0: firmware interface never appeared" >&2 63 exit 1 64 fi 65 done 66 67 echo -1 >"$DIR"/"$name"/loading 68 69 # Wait for request to finish. 70 wait 71} 72 73load_fw_custom() 74{ 75 if [ ! -e "$DIR"/trigger_custom_fallback ]; then 76 echo "$0: custom fallback trigger not present, ignoring test" >&2 77 return 1 78 fi 79 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=10 87 while [ ! -e "$DIR"/"$name"/loading ]; do 88 sleep 0.1 89 timeout=$(( $timeout - 1 )) 90 if [ "$timeout" -eq 0 ]; then 91 echo "$0: firmware interface never appeared" >&2 92 exit 1 93 fi 94 done 95 96 echo 1 >"$DIR"/"$name"/loading 97 cat "$file" >"$DIR"/"$name"/data 98 echo 0 >"$DIR"/"$name"/loading 99 100 # Wait for request to finish. 101 wait 102 return 0 103} 104 105 106load_fw_custom_cancel() 107{ 108 if [ ! -e "$DIR"/trigger_custom_fallback ]; then 109 echo "$0: canceling custom fallback trigger not present, ignoring test" >&2 110 return 1 111 fi 112 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=10 120 while [ ! -e "$DIR"/"$name"/loading ]; do 121 sleep 0.1 122 timeout=$(( $timeout - 1 )) 123 if [ "$timeout" -eq 0 ]; then 124 echo "$0: firmware interface never appeared" >&2 125 exit 1 126 fi 127 done 128 129 echo -1 >"$DIR"/"$name"/loading 130 131 # Wait for request to finish. 132 wait 133 return 0 134} 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 explicit 142 echo 4 >/sys/class/firmware/timeout 143 144 sleep 1 & 145 SECONDS_BEFORE=$(date +%s) 146 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null 147 SECONDS_AFTER=$(date +%s) 148 SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE)) 149 if [ "$SECONDS_DELTA" -lt 4 ]; then 150 RET=1 151 else 152 RET=0 153 fi 154 wait 155 return $RET 156} 157 158test_syfs_timeout() 159{ 160 DEVPATH="$DIR"/"nope-$NAME"/loading 161 162 # Test failure when doing nothing (timeout works). 163 echo -n 2 >/sys/class/firmware/timeout 164 echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & 165 166 # Give the kernel some time to load the loading file, must be less 167 # than the timeout above. 168 sleep 1 169 if [ ! -f $DEVPATH ]; then 170 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 1 185 fi 186 187 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 188 echo "$0: firmware was not expected to match" >&2 189 exit 1 190 else 191 echo "$0: timeout works" 192 fi 193} 194 195run_sysfs_main_tests() 196{ 197 test_syfs_timeout 198 # Put timeout high enough for us to do work but not so long that failures 199 # slow down this test too much. 200 echo 4 >/sys/class/firmware/timeout 201 202 # Load this script instead of the desired firmware. 203 load_fw "$NAME" "$0" 204 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 205 echo "$0: firmware was not expected to match" >&2 206 exit 1 207 else 208 echo "$0: firmware comparison works" 209 fi 210 211 # Do a proper load, which should work correctly. 212 load_fw "$NAME" "$FW" 213 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 214 echo "$0: firmware was not loaded" >&2 215 exit 1 216 else 217 echo "$0: fallback mechanism works" 218 fi 219 220 load_fw_cancel "nope-$NAME" "$FW" 221 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 222 echo "$0: firmware was expected to be cancelled" >&2 223 exit 1 224 else 225 echo "$0: cancelling fallback mechanism works" 226 fi 227 228 set +e 229 load_fw_fallback_with_child "nope-signal-$NAME" "$FW" 230 if [ "$?" -eq 0 ]; then 231 echo "$0: SIGCHLD on sync ignored as expected" >&2 232 else 233 echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2 234 exit 1 235 fi 236 set -e 237} 238 239run_sysfs_custom_load_tests() 240{ 241 if load_fw_custom "$NAME" "$FW" ; then 242 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 243 echo "$0: firmware was not loaded" >&2 244 exit 1 245 else 246 echo "$0: custom fallback loading mechanism works" 247 fi 248 fi 249 250 if load_fw_custom "$NAME" "$FW" ; then 251 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then 252 echo "$0: firmware was not loaded" >&2 253 exit 1 254 else 255 echo "$0: custom fallback loading mechanism works" 256 fi 257 fi 258 259 if load_fw_custom_cancel "nope-$NAME" "$FW" ; then 260 if diff -q "$FW" /dev/test_firmware >/dev/null ; then 261 echo "$0: firmware was expected to be cancelled" >&2 262 exit 1 263 else 264 echo "$0: cancelling custom fallback mechanism works" 265 fi 266 fi 267} 268 269if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then 270 run_sysfs_main_tests 271fi 272 273run_sysfs_custom_load_tests 274 275exit 0 276