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.
89 if [ ! -e "$DIR"/trigger_custom_fallback
]; then
90 echo "$0: custom fallback trigger not present, ignoring test" >&2
97 echo -n "$name" >"$DIR"/trigger_custom_fallback
2>/dev
/null
&
99 # Give kernel a chance to react.
101 while [ ! -e "$DIR"/"$name"/loading
]; do
103 timeout
=$
(( $timeout - 1 ))
104 if [ "$timeout" -eq 0 ]; then
105 echo "$0: firmware interface never appeared" >&2
110 echo 1 >"$DIR"/"$name"/loading
111 cat "$file" >"$DIR"/"$name"/data
112 echo 0 >"$DIR"/"$name"/loading
114 # Wait for request to finish.
120 load_fw_custom_cancel
()
122 if [ ! -e "$DIR"/trigger_custom_fallback
]; then
123 echo "$0: canceling custom fallback trigger not present, ignoring test" >&2
130 echo -n "$name" >"$DIR"/trigger_custom_fallback
2>/dev
/null
&
132 # Give kernel a chance to react.
134 while [ ! -e "$DIR"/"$name"/loading
]; do
136 timeout
=$
(( $timeout - 1 ))
137 if [ "$timeout" -eq 0 ]; then
138 echo "$0: firmware interface never appeared" >&2
143 echo -1 >"$DIR"/"$name"/loading
145 # Wait for request to finish.
150 load_fw_fallback_with_child
()
155 # This is the value already set but we want to be explicit
156 echo 4 >/sys
/class
/firmware
/timeout
159 SECONDS_BEFORE
=$
(date +%s
)
160 echo -n "$name" >"$DIR"/trigger_request
2>/dev
/null
161 SECONDS_AFTER
=$
(date +%s
)
162 SECONDS_DELTA
=$
(($SECONDS_AFTER - $SECONDS_BEFORE))
163 if [ "$SECONDS_DELTA" -lt 4 ]; then
172 trap "test_finish" EXIT
174 # This is an unlikely real-world firmware content. :)
175 echo "ABCD0123" >"$FW"
176 NAME
=$
(basename "$FW")
180 DEVPATH
="$DIR"/"nope-$NAME"/loading
182 # Test failure when doing nothing (timeout works).
183 echo -n 2 >/sys
/class
/firmware
/timeout
184 echo -n "nope-$NAME" >"$DIR"/trigger_request
2>/dev
/null
&
186 # Give the kernel some time to load the loading file, must be less
187 # than the timeout above.
189 if [ ! -f $DEVPATH ]; then
190 echo "$0: fallback mechanism immediately cancelled"
192 echo "The file never appeared: $DEVPATH"
194 echo "This might be a distribution udev rule setup by your distribution"
195 echo "to immediately cancel all fallback requests, this must be"
196 echo "removed before running these tests. To confirm look for"
197 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"
198 echo "and see if you have something like this:"
200 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""
202 echo "If you do remove this file or comment out this line before"
203 echo "proceeding with these tests."
207 if diff -q "$FW" /dev
/test_firmware
>/dev
/null
; then
208 echo "$0: firmware was not expected to match" >&2
211 echo "$0: timeout works"
215 run_sysfs_main_tests
()
218 # Put timeout high enough for us to do work but not so long that failures
219 # slow down this test too much.
220 echo 4 >/sys
/class
/firmware
/timeout
222 # Load this script instead of the desired firmware.
224 if diff -q "$FW" /dev
/test_firmware
>/dev
/null
; then
225 echo "$0: firmware was not expected to match" >&2
228 echo "$0: firmware comparison works"
231 # Do a proper load, which should work correctly.
232 load_fw
"$NAME" "$FW"
233 if ! diff -q "$FW" /dev
/test_firmware
>/dev
/null
; then
234 echo "$0: firmware was not loaded" >&2
237 echo "$0: fallback mechanism works"
240 load_fw_cancel
"nope-$NAME" "$FW"
241 if diff -q "$FW" /dev
/test_firmware
>/dev
/null
; then
242 echo "$0: firmware was expected to be cancelled" >&2
245 echo "$0: cancelling fallback mechanism works"
249 load_fw_fallback_with_child
"nope-signal-$NAME" "$FW"
250 if [ "$?" -eq 0 ]; then
251 echo "$0: SIGCHLD on sync ignored as expected" >&2
253 echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2
259 run_sysfs_custom_load_tests
()
261 if load_fw_custom
"$NAME" "$FW" ; then
262 if ! diff -q "$FW" /dev
/test_firmware
>/dev
/null
; then
263 echo "$0: firmware was not loaded" >&2
266 echo "$0: custom fallback loading mechanism works"
270 if load_fw_custom
"$NAME" "$FW" ; then
271 if ! diff -q "$FW" /dev
/test_firmware
>/dev
/null
; then
272 echo "$0: firmware was not loaded" >&2
275 echo "$0: custom fallback loading mechanism works"
279 if load_fw_custom_cancel
"nope-$NAME" "$FW" ; then
280 if diff -q "$FW" /dev
/test_firmware
>/dev
/null
; then
281 echo "$0: firmware was expected to be cancelled" >&2
284 echo "$0: cancelling custom fallback mechanism works"
290 run_sysfs_custom_load_tests