Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
fork
Configure Feed
Select the types of activity you want to include in your feed.
1#!/bin/sh
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
9modprobe test_firmware
10
11DIR=/sys/devices/virtual/misc/test_firmware
12
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.
16HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi)
17
18if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
19 OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
20else
21 echo "usermode helper disabled so ignoring test"
22 exit 0
23fi
24
25FWPATH=$(mktemp -d)
26FW="$FWPATH/test-firmware.bin"
27
28test_finish()
29{
30 echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
31 rm -f "$FW"
32 rmdir "$FWPATH"
33}
34
35load_fw()
36{
37 local name="$1"
38 local file="$2"
39
40 # This will block until our load (below) has finished.
41 echo -n "$name" >"$DIR"/trigger_request &
42
43 # Give kernel a chance to react.
44 local timeout=10
45 while [ ! -e "$DIR"/"$name"/loading ]; do
46 sleep 0.1
47 timeout=$(( $timeout - 1 ))
48 if [ "$timeout" -eq 0 ]; then
49 echo "$0: firmware interface never appeared" >&2
50 exit 1
51 fi
52 done
53
54 echo 1 >"$DIR"/"$name"/loading
55 cat "$file" >"$DIR"/"$name"/data
56 echo 0 >"$DIR"/"$name"/loading
57
58 # Wait for request to finish.
59 wait
60}
61
62load_fw_cancel()
63{
64 local name="$1"
65 local file="$2"
66
67 # This will block until our load (below) has finished.
68 echo -n "$name" >"$DIR"/trigger_request 2>/dev/null &
69
70 # Give kernel a chance to react.
71 local timeout=10
72 while [ ! -e "$DIR"/"$name"/loading ]; do
73 sleep 0.1
74 timeout=$(( $timeout - 1 ))
75 if [ "$timeout" -eq 0 ]; then
76 echo "$0: firmware interface never appeared" >&2
77 exit 1
78 fi
79 done
80
81 echo -1 >"$DIR"/"$name"/loading
82
83 # Wait for request to finish.
84 wait
85}
86
87load_fw_custom()
88{
89 if [ ! -e "$DIR"/trigger_custom_fallback ]; then
90 echo "$0: custom fallback trigger not present, ignoring test" >&2
91 return 1
92 fi
93
94 local name="$1"
95 local file="$2"
96
97 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
98
99 # Give kernel a chance to react.
100 local timeout=10
101 while [ ! -e "$DIR"/"$name"/loading ]; do
102 sleep 0.1
103 timeout=$(( $timeout - 1 ))
104 if [ "$timeout" -eq 0 ]; then
105 echo "$0: firmware interface never appeared" >&2
106 exit 1
107 fi
108 done
109
110 echo 1 >"$DIR"/"$name"/loading
111 cat "$file" >"$DIR"/"$name"/data
112 echo 0 >"$DIR"/"$name"/loading
113
114 # Wait for request to finish.
115 wait
116 return 0
117}
118
119
120load_fw_custom_cancel()
121{
122 if [ ! -e "$DIR"/trigger_custom_fallback ]; then
123 echo "$0: canceling custom fallback trigger not present, ignoring test" >&2
124 return 1
125 fi
126
127 local name="$1"
128 local file="$2"
129
130 echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
131
132 # Give kernel a chance to react.
133 local timeout=10
134 while [ ! -e "$DIR"/"$name"/loading ]; do
135 sleep 0.1
136 timeout=$(( $timeout - 1 ))
137 if [ "$timeout" -eq 0 ]; then
138 echo "$0: firmware interface never appeared" >&2
139 exit 1
140 fi
141 done
142
143 echo -1 >"$DIR"/"$name"/loading
144
145 # Wait for request to finish.
146 wait
147 return 0
148}
149
150load_fw_fallback_with_child()
151{
152 local name="$1"
153 local file="$2"
154
155 # This is the value already set but we want to be explicit
156 echo 4 >/sys/class/firmware/timeout
157
158 sleep 1 &
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
164 RET=1
165 else
166 RET=0
167 fi
168 wait
169 return $RET
170}
171
172trap "test_finish" EXIT
173
174# This is an unlikely real-world firmware content. :)
175echo "ABCD0123" >"$FW"
176NAME=$(basename "$FW")
177
178DEVPATH="$DIR"/"nope-$NAME"/loading
179
180# Test failure when doing nothing (timeout works).
181echo -n 2 >/sys/class/firmware/timeout
182echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null &
183
184# Give the kernel some time to load the loading file, must be less
185# than the timeout above.
186sleep 1
187if [ ! -f $DEVPATH ]; then
188 echo "$0: fallback mechanism immediately cancelled"
189 echo ""
190 echo "The file never appeared: $DEVPATH"
191 echo ""
192 echo "This might be a distribution udev rule setup by your distribution"
193 echo "to immediately cancel all fallback requests, this must be"
194 echo "removed before running these tests. To confirm look for"
195 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"
196 echo "and see if you have something like this:"
197 echo ""
198 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""
199 echo ""
200 echo "If you do remove this file or comment out this line before"
201 echo "proceeding with these tests."
202 exit 1
203fi
204
205if diff -q "$FW" /dev/test_firmware >/dev/null ; then
206 echo "$0: firmware was not expected to match" >&2
207 exit 1
208else
209 echo "$0: timeout works"
210fi
211
212# Put timeout high enough for us to do work but not so long that failures
213# slow down this test too much.
214echo 4 >/sys/class/firmware/timeout
215
216# Load this script instead of the desired firmware.
217load_fw "$NAME" "$0"
218if diff -q "$FW" /dev/test_firmware >/dev/null ; then
219 echo "$0: firmware was not expected to match" >&2
220 exit 1
221else
222 echo "$0: firmware comparison works"
223fi
224
225# Do a proper load, which should work correctly.
226load_fw "$NAME" "$FW"
227if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
228 echo "$0: firmware was not loaded" >&2
229 exit 1
230else
231 echo "$0: fallback mechanism works"
232fi
233
234load_fw_cancel "nope-$NAME" "$FW"
235if diff -q "$FW" /dev/test_firmware >/dev/null ; then
236 echo "$0: firmware was expected to be cancelled" >&2
237 exit 1
238else
239 echo "$0: cancelling fallback mechanism works"
240fi
241
242if load_fw_custom "$NAME" "$FW" ; then
243 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
244 echo "$0: firmware was not loaded" >&2
245 exit 1
246 else
247 echo "$0: custom fallback loading mechanism works"
248 fi
249fi
250
251if load_fw_custom_cancel "nope-$NAME" "$FW" ; then
252 if diff -q "$FW" /dev/test_firmware >/dev/null ; then
253 echo "$0: firmware was expected to be cancelled" >&2
254 exit 1
255 else
256 echo "$0: cancelling custom fallback mechanism works"
257 fi
258fi
259
260set +e
261load_fw_fallback_with_child "nope-signal-$NAME" "$FW"
262if [ "$?" -eq 0 ]; then
263 echo "$0: SIGCHLD on sync ignored as expected" >&2
264else
265 echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2
266 exit 1
267fi
268set -e
269
270exit 0