]>
Commit | Line | Data |
---|---|---|
0a8adf58 | 1 | #!/bin/sh |
b2441318 | 2 | # SPDX-License-Identifier: GPL-2.0 |
823b0221 | 3 | # This validates that the kernel will fall back to using the fallback mechanism |
0a8adf58 KC |
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. | |
7 | set -e | |
8 | ||
9 | modprobe test_firmware | |
10 | ||
11 | DIR=/sys/devices/virtual/misc/test_firmware | |
12 | ||
1d0fbb34 LR |
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) | |
17 | ||
18 | if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then | |
19 | OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) | |
20 | else | |
21 | echo "usermode helper disabled so ignoring test" | |
22 | exit 0 | |
23 | fi | |
0a8adf58 KC |
24 | |
25 | FWPATH=$(mktemp -d) | |
26 | FW="$FWPATH/test-firmware.bin" | |
27 | ||
28 | test_finish() | |
29 | { | |
30 | echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout | |
31 | rm -f "$FW" | |
32 | rmdir "$FWPATH" | |
33 | } | |
34 | ||
35 | load_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 | ||
eb67bc3f LR |
62 | load_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 | ||
061132d2 LR |
87 | load_fw_custom() |
88 | { | |
89 | local name="$1" | |
90 | local file="$2" | |
91 | ||
92 | echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & | |
93 | ||
94 | # Give kernel a chance to react. | |
95 | local timeout=10 | |
96 | while [ ! -e "$DIR"/"$name"/loading ]; do | |
97 | sleep 0.1 | |
98 | timeout=$(( $timeout - 1 )) | |
99 | if [ "$timeout" -eq 0 ]; then | |
100 | echo "$0: firmware interface never appeared" >&2 | |
101 | exit 1 | |
102 | fi | |
103 | done | |
104 | ||
105 | echo 1 >"$DIR"/"$name"/loading | |
106 | cat "$file" >"$DIR"/"$name"/data | |
107 | echo 0 >"$DIR"/"$name"/loading | |
108 | ||
109 | # Wait for request to finish. | |
110 | wait | |
111 | } | |
112 | ||
113 | ||
114 | load_fw_custom_cancel() | |
115 | { | |
116 | local name="$1" | |
117 | local file="$2" | |
118 | ||
119 | echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null & | |
120 | ||
121 | # Give kernel a chance to react. | |
122 | local timeout=10 | |
123 | while [ ! -e "$DIR"/"$name"/loading ]; do | |
124 | sleep 0.1 | |
125 | timeout=$(( $timeout - 1 )) | |
126 | if [ "$timeout" -eq 0 ]; then | |
127 | echo "$0: firmware interface never appeared" >&2 | |
128 | exit 1 | |
129 | fi | |
130 | done | |
131 | ||
132 | echo -1 >"$DIR"/"$name"/loading | |
133 | ||
134 | # Wait for request to finish. | |
135 | wait | |
136 | } | |
137 | ||
0d1f417e LR |
138 | load_fw_fallback_with_child() |
139 | { | |
140 | local name="$1" | |
141 | local file="$2" | |
142 | ||
143 | # This is the value already set but we want to be explicit | |
144 | echo 4 >/sys/class/firmware/timeout | |
145 | ||
146 | sleep 1 & | |
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 | |
152 | RET=1 | |
153 | else | |
154 | RET=0 | |
155 | fi | |
156 | wait | |
157 | return $RET | |
158 | } | |
061132d2 | 159 | |
0a8adf58 KC |
160 | trap "test_finish" EXIT |
161 | ||
162 | # This is an unlikely real-world firmware content. :) | |
163 | echo "ABCD0123" >"$FW" | |
164 | NAME=$(basename "$FW") | |
165 | ||
afb999cd LR |
166 | DEVPATH="$DIR"/"nope-$NAME"/loading |
167 | ||
0a8adf58 | 168 | # Test failure when doing nothing (timeout works). |
afb999cd LR |
169 | echo -n 2 >/sys/class/firmware/timeout |
170 | echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null & | |
171 | ||
172 | # Give the kernel some time to load the loading file, must be less | |
173 | # than the timeout above. | |
174 | sleep 1 | |
175 | if [ ! -f $DEVPATH ]; then | |
176 | echo "$0: fallback mechanism immediately cancelled" | |
177 | echo "" | |
178 | echo "The file never appeared: $DEVPATH" | |
179 | echo "" | |
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:" | |
185 | echo "" | |
186 | echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\"" | |
187 | echo "" | |
188 | echo "If you do remove this file or comment out this line before" | |
189 | echo "proceeding with these tests." | |
190 | exit 1 | |
191 | fi | |
192 | ||
0a8adf58 KC |
193 | if diff -q "$FW" /dev/test_firmware >/dev/null ; then |
194 | echo "$0: firmware was not expected to match" >&2 | |
195 | exit 1 | |
196 | else | |
197 | echo "$0: timeout works" | |
198 | fi | |
199 | ||
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 | |
203 | ||
204 | # Load this script instead of the desired firmware. | |
205 | load_fw "$NAME" "$0" | |
206 | if diff -q "$FW" /dev/test_firmware >/dev/null ; then | |
207 | echo "$0: firmware was not expected to match" >&2 | |
208 | exit 1 | |
209 | else | |
210 | echo "$0: firmware comparison works" | |
211 | fi | |
212 | ||
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 | |
217 | exit 1 | |
218 | else | |
823b0221 | 219 | echo "$0: fallback mechanism works" |
eb67bc3f | 220 | fi |
823b0221 | 221 | |
eb67bc3f LR |
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 | |
225 | exit 1 | |
226 | else | |
227 | echo "$0: cancelling fallback mechanism works" | |
0a8adf58 KC |
228 | fi |
229 | ||
061132d2 LR |
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 | |
233 | exit 1 | |
234 | else | |
235 | echo "$0: custom fallback loading mechanism works" | |
236 | fi | |
237 | ||
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 | |
241 | exit 1 | |
242 | else | |
243 | echo "$0: cancelling custom fallback mechanism works" | |
244 | fi | |
245 | ||
0d1f417e LR |
246 | set +e |
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 | |
250 | else | |
251 | echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2 | |
252 | exit 1 | |
253 | fi | |
254 | set -e | |
255 | ||
0a8adf58 | 256 | exit 0 |