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.
11 DIR=/sys/devices/virtual/misc/test_firmware
13 # CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/
14 # These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that
15 # as an indicator for CONFIG_FW_LOADER_USER_HELPER.
16 HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi)
18 if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
19 OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
21 echo "usermode helper disabled so ignoring test"
26 FW="$FWPATH/test-firmware.bin"
30 echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
40 # This will block until our load (below) has finished.
41 echo -n "$name" >"$DIR"/trigger_request &
43 # Give kernel a chance to react.
45 while [ ! -e "$DIR"/"$name"/loading ]; do
47 timeout=$(( $timeout - 1 ))
48 if [ "$timeout" -eq 0 ]; then
49 echo "$0: firmware interface never appeared" >&2
54 echo 1 >"$DIR"/"$name"/loading
55 cat "$file" >"$DIR"/"$name"/data
56 echo 0 >"$DIR"/"$name"/loading
58 # Wait for request to finish.
67 # This will block until our load (below) has finished.
68 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null &
70 # Give kernel a chance to react.
72 while [ ! -e "$DIR"/"$name"/loading ]; do
74 timeout=$(( $timeout - 1 ))
75 if [ "$timeout" -eq 0 ]; then
76 echo "$0: firmware interface never appeared" >&2
81 echo -1 >"$DIR"/"$name"/loading
83 # Wait for request to finish.
92 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
94 # Give kernel a chance to react.
96 while [ ! -e "$DIR"/"$name"/loading ]; do
98 timeout=$(( $timeout - 1 ))
99 if [ "$timeout" -eq 0 ]; then
100 echo "$0: firmware interface never appeared" >&2
105 echo 1 >"$DIR"/"$name"/loading
106 cat "$file" >"$DIR"/"$name"/data
107 echo 0 >"$DIR"/"$name"/loading
109 # Wait for request to finish.
114 load_fw_custom_cancel()
119 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
121 # Give kernel a chance to react.
123 while [ ! -e "$DIR"/"$name"/loading ]; do
125 timeout=$(( $timeout - 1 ))
126 if [ "$timeout" -eq 0 ]; then
127 echo "$0: firmware interface never appeared" >&2
132 echo -1 >"$DIR"/"$name"/loading
134 # Wait for request to finish.
138 load_fw_fallback_with_child()
143 # This is the value already set but we want to be explicit
144 echo 4 >/sys/class/firmware/timeout
147 SECONDS_BEFORE=$(date +%s)
148 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null
149 SECONDS_AFTER=$(date +%s)
150 SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE))
151 if [ "$SECONDS_DELTA" -lt 4 ]; then
160 trap "test_finish" EXIT
162 # This is an unlikely real-world firmware content. :)
163 echo "ABCD0123" >"$FW"
164 NAME=$(basename "$FW")
166 DEVPATH="$DIR"/"nope-$NAME"/loading
168 # Test failure when doing nothing (timeout works).
169 echo -n 2 >/sys/class/firmware/timeout
170 echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null &
172 # Give the kernel some time to load the loading file, must be less
173 # than the timeout above.
175 if [ ! -f $DEVPATH ]; then
176 echo "$0: fallback mechanism immediately cancelled"
178 echo "The file never appeared: $DEVPATH"
180 echo "This might be a distribution udev rule setup by your distribution"
181 echo "to immediately cancel all fallback requests, this must be"
182 echo "removed before running these tests. To confirm look for"
183 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"
184 echo "and see if you have something like this:"
186 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""
188 echo "If you do remove this file or comment out this line before"
189 echo "proceeding with these tests."
193 if diff -q "$FW" /dev/test_firmware >/dev/null ; then
194 echo "$0: firmware was not expected to match" >&2
197 echo "$0: timeout works"
200 # Put timeout high enough for us to do work but not so long that failures
201 # slow down this test too much.
202 echo 4 >/sys/class/firmware/timeout
204 # Load this script instead of the desired firmware.
206 if diff -q "$FW" /dev/test_firmware >/dev/null ; then
207 echo "$0: firmware was not expected to match" >&2
210 echo "$0: firmware comparison works"
213 # Do a proper load, which should work correctly.
214 load_fw "$NAME" "$FW"
215 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
216 echo "$0: firmware was not loaded" >&2
219 echo "$0: fallback mechanism works"
222 load_fw_cancel "nope-$NAME" "$FW"
223 if diff -q "$FW" /dev/test_firmware >/dev/null ; then
224 echo "$0: firmware was expected to be cancelled" >&2
227 echo "$0: cancelling fallback mechanism works"
230 load_fw_custom "$NAME" "$FW"
231 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
232 echo "$0: firmware was not loaded" >&2
235 echo "$0: custom fallback loading mechanism works"
238 load_fw_custom_cancel "nope-$NAME" "$FW"
239 if diff -q "$FW" /dev/test_firmware >/dev/null ; then
240 echo "$0: firmware was expected to be cancelled" >&2
243 echo "$0: cancelling custom fallback mechanism works"
247 load_fw_fallback_with_child "nope-signal-$NAME" "$FW"
248 if [ "$?" -eq 0 ]; then
249 echo "$0: SIGCHLD on sync ignored as expected" >&2
251 echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2