Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/firmware/fw_fallback.sh
26285 views
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.
7
set -e
8
9
TEST_REQS_FW_SYSFS_FALLBACK="yes"
10
TEST_REQS_FW_SET_CUSTOM_PATH="no"
11
TEST_DIR=$(dirname $0)
12
source $TEST_DIR/fw_lib.sh
13
14
check_mods
15
check_setup
16
verify_reqs
17
setup_tmp_file
18
19
trap "test_finish" EXIT
20
21
load_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
48
load_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
73
load_fw_custom()
74
{
75
if [ ! -e "$DIR"/trigger_custom_fallback ]; then
76
echo "$0: custom fallback trigger not present, ignoring test" >&2
77
exit $ksft_skip
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
106
load_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
exit $ksft_skip
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
136
load_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
158
test_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
195
run_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
239
run_sysfs_custom_load_tests()
240
{
241
RANDOM_FILE_PATH=$(setup_random_file)
242
RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
243
if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
244
if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
245
echo "$0: firmware was not loaded" >&2
246
exit 1
247
else
248
echo "$0: custom fallback loading mechanism works"
249
fi
250
fi
251
252
RANDOM_FILE_PATH=$(setup_random_file)
253
RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
254
if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
255
if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
256
echo "$0: firmware was not loaded" >&2
257
exit 1
258
else
259
echo "$0: custom fallback loading mechanism works"
260
fi
261
fi
262
263
RANDOM_FILE_REAL="$RANDOM_FILE_PATH"
264
FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake)
265
FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)"
266
267
if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then
268
if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
269
echo "$0: firmware was expected to be cancelled" >&2
270
exit 1
271
else
272
echo "$0: cancelling custom fallback mechanism works"
273
fi
274
fi
275
}
276
277
if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then
278
run_sysfs_main_tests
279
fi
280
281
run_sysfs_custom_load_tests
282
283
exit 0
284
285