xref: /openbmc/linux/tools/testing/selftests/firmware/fw_fallback.sh (revision 3eb66e91a25497065c5322b1268cbc3953642227)
129a1c00cSLuis R. Rodriguez#!/bin/bash
2b2441318SGreg Kroah-Hartman# SPDX-License-Identifier: GPL-2.0
3823b0221SLuis R. Rodriguez# This validates that the kernel will fall back to using the fallback mechanism
4823b0221SLuis R. Rodriguez# to load firmware it can't find on disk itself. We must request a firmware
5823b0221SLuis R. Rodriguez# that the kernel won't find, and any installed helper (e.g. udev) also
6823b0221SLuis R. Rodriguez# won't find so that we can do the load ourself manually.
7823b0221SLuis R. Rodriguezset -e
8823b0221SLuis R. Rodriguez
9f5a61451SLuis R. RodriguezTEST_REQS_FW_SYSFS_FALLBACK="yes"
10f5a61451SLuis R. RodriguezTEST_REQS_FW_SET_CUSTOM_PATH="no"
1129a1c00cSLuis R. RodriguezTEST_DIR=$(dirname $0)
1229a1c00cSLuis R. Rodriguezsource $TEST_DIR/fw_lib.sh
13823b0221SLuis R. Rodriguez
1429a1c00cSLuis R. Rodriguezcheck_mods
15f5a61451SLuis R. Rodriguezcheck_setup
16f5a61451SLuis R. Rodriguezverify_reqs
17f5a61451SLuis R. Rodriguezsetup_tmp_file
18823b0221SLuis R. Rodriguez
19f5a61451SLuis R. Rodrigueztrap "test_finish" EXIT
20823b0221SLuis R. Rodriguez
21823b0221SLuis R. Rodriguezload_fw()
22823b0221SLuis R. Rodriguez{
23823b0221SLuis R. Rodriguez	local name="$1"
24823b0221SLuis R. Rodriguez	local file="$2"
25823b0221SLuis R. Rodriguez
26823b0221SLuis R. Rodriguez	# This will block until our load (below) has finished.
27823b0221SLuis R. Rodriguez	echo -n "$name" >"$DIR"/trigger_request &
28823b0221SLuis R. Rodriguez
29823b0221SLuis R. Rodriguez	# Give kernel a chance to react.
30823b0221SLuis R. Rodriguez	local timeout=10
31823b0221SLuis R. Rodriguez	while [ ! -e "$DIR"/"$name"/loading ]; do
32823b0221SLuis R. Rodriguez		sleep 0.1
33823b0221SLuis R. Rodriguez		timeout=$(( $timeout - 1 ))
34823b0221SLuis R. Rodriguez		if [ "$timeout" -eq 0 ]; then
35823b0221SLuis R. Rodriguez			echo "$0: firmware interface never appeared" >&2
36823b0221SLuis R. Rodriguez			exit 1
37823b0221SLuis R. Rodriguez		fi
38823b0221SLuis R. Rodriguez	done
39823b0221SLuis R. Rodriguez
40823b0221SLuis R. Rodriguez	echo 1 >"$DIR"/"$name"/loading
41823b0221SLuis R. Rodriguez	cat "$file" >"$DIR"/"$name"/data
42823b0221SLuis R. Rodriguez	echo 0 >"$DIR"/"$name"/loading
43823b0221SLuis R. Rodriguez
44823b0221SLuis R. Rodriguez	# Wait for request to finish.
45823b0221SLuis R. Rodriguez	wait
46823b0221SLuis R. Rodriguez}
47823b0221SLuis R. Rodriguez
48eb67bc3fSLuis R. Rodriguezload_fw_cancel()
49eb67bc3fSLuis R. Rodriguez{
50eb67bc3fSLuis R. Rodriguez	local name="$1"
51eb67bc3fSLuis R. Rodriguez	local file="$2"
52eb67bc3fSLuis R. Rodriguez
53eb67bc3fSLuis R. Rodriguez	# This will block until our load (below) has finished.
54eb67bc3fSLuis R. Rodriguez	echo -n "$name" >"$DIR"/trigger_request 2>/dev/null &
55eb67bc3fSLuis R. Rodriguez
56eb67bc3fSLuis R. Rodriguez	# Give kernel a chance to react.
57eb67bc3fSLuis R. Rodriguez	local timeout=10
58eb67bc3fSLuis R. Rodriguez	while [ ! -e "$DIR"/"$name"/loading ]; do
59eb67bc3fSLuis R. Rodriguez		sleep 0.1
60eb67bc3fSLuis R. Rodriguez		timeout=$(( $timeout - 1 ))
61eb67bc3fSLuis R. Rodriguez		if [ "$timeout" -eq 0 ]; then
62eb67bc3fSLuis R. Rodriguez			echo "$0: firmware interface never appeared" >&2
63eb67bc3fSLuis R. Rodriguez			exit 1
64eb67bc3fSLuis R. Rodriguez		fi
65eb67bc3fSLuis R. Rodriguez	done
66eb67bc3fSLuis R. Rodriguez
67eb67bc3fSLuis R. Rodriguez	echo -1 >"$DIR"/"$name"/loading
68eb67bc3fSLuis R. Rodriguez
69eb67bc3fSLuis R. Rodriguez	# Wait for request to finish.
70eb67bc3fSLuis R. Rodriguez	wait
71eb67bc3fSLuis R. Rodriguez}
72eb67bc3fSLuis R. Rodriguez
73061132d2SLuis R. Rodriguezload_fw_custom()
74061132d2SLuis R. Rodriguez{
75c3e0d179SAmit Pundir	if [ ! -e "$DIR"/trigger_custom_fallback ]; then
76c3e0d179SAmit Pundir		echo "$0: custom fallback trigger not present, ignoring test" >&2
77*a6a9be92SShuah Khan (Samsung OSG)		exit $ksft_skip
78c3e0d179SAmit Pundir	fi
79c3e0d179SAmit Pundir
80061132d2SLuis R. Rodriguez	local name="$1"
81061132d2SLuis R. Rodriguez	local file="$2"
82061132d2SLuis R. Rodriguez
83061132d2SLuis R. Rodriguez	echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
84061132d2SLuis R. Rodriguez
85061132d2SLuis R. Rodriguez	# Give kernel a chance to react.
86061132d2SLuis R. Rodriguez	local timeout=10
87061132d2SLuis R. Rodriguez	while [ ! -e "$DIR"/"$name"/loading ]; do
88061132d2SLuis R. Rodriguez		sleep 0.1
89061132d2SLuis R. Rodriguez		timeout=$(( $timeout - 1 ))
90061132d2SLuis R. Rodriguez		if [ "$timeout" -eq 0 ]; then
91061132d2SLuis R. Rodriguez			echo "$0: firmware interface never appeared" >&2
92061132d2SLuis R. Rodriguez			exit 1
93061132d2SLuis R. Rodriguez		fi
94061132d2SLuis R. Rodriguez	done
95061132d2SLuis R. Rodriguez
96061132d2SLuis R. Rodriguez	echo 1 >"$DIR"/"$name"/loading
97061132d2SLuis R. Rodriguez	cat "$file" >"$DIR"/"$name"/data
98061132d2SLuis R. Rodriguez	echo 0 >"$DIR"/"$name"/loading
99061132d2SLuis R. Rodriguez
100061132d2SLuis R. Rodriguez	# Wait for request to finish.
101061132d2SLuis R. Rodriguez	wait
102c3e0d179SAmit Pundir	return 0
103061132d2SLuis R. Rodriguez}
104061132d2SLuis R. Rodriguez
105061132d2SLuis R. Rodriguez
106061132d2SLuis R. Rodriguezload_fw_custom_cancel()
107061132d2SLuis R. Rodriguez{
108c3e0d179SAmit Pundir	if [ ! -e "$DIR"/trigger_custom_fallback ]; then
109c3e0d179SAmit Pundir		echo "$0: canceling custom fallback trigger not present, ignoring test" >&2
110*a6a9be92SShuah Khan (Samsung OSG)		exit $ksft_skip
111c3e0d179SAmit Pundir	fi
112c3e0d179SAmit Pundir
113061132d2SLuis R. Rodriguez	local name="$1"
114061132d2SLuis R. Rodriguez	local file="$2"
115061132d2SLuis R. Rodriguez
116061132d2SLuis R. Rodriguez	echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
117061132d2SLuis R. Rodriguez
118061132d2SLuis R. Rodriguez	# Give kernel a chance to react.
119061132d2SLuis R. Rodriguez	local timeout=10
120061132d2SLuis R. Rodriguez	while [ ! -e "$DIR"/"$name"/loading ]; do
121061132d2SLuis R. Rodriguez		sleep 0.1
122061132d2SLuis R. Rodriguez		timeout=$(( $timeout - 1 ))
123061132d2SLuis R. Rodriguez		if [ "$timeout" -eq 0 ]; then
124061132d2SLuis R. Rodriguez			echo "$0: firmware interface never appeared" >&2
125061132d2SLuis R. Rodriguez			exit 1
126061132d2SLuis R. Rodriguez		fi
127061132d2SLuis R. Rodriguez	done
128061132d2SLuis R. Rodriguez
129061132d2SLuis R. Rodriguez	echo -1 >"$DIR"/"$name"/loading
130061132d2SLuis R. Rodriguez
131061132d2SLuis R. Rodriguez	# Wait for request to finish.
132061132d2SLuis R. Rodriguez	wait
133c3e0d179SAmit Pundir	return 0
134061132d2SLuis R. Rodriguez}
135061132d2SLuis R. Rodriguez
1360d1f417eSLuis R. Rodriguezload_fw_fallback_with_child()
1370d1f417eSLuis R. Rodriguez{
1380d1f417eSLuis R. Rodriguez	local name="$1"
1390d1f417eSLuis R. Rodriguez	local file="$2"
1400d1f417eSLuis R. Rodriguez
1410d1f417eSLuis R. Rodriguez	# This is the value already set but we want to be explicit
1420d1f417eSLuis R. Rodriguez	echo 4 >/sys/class/firmware/timeout
1430d1f417eSLuis R. Rodriguez
1440d1f417eSLuis R. Rodriguez	sleep 1 &
1450d1f417eSLuis R. Rodriguez	SECONDS_BEFORE=$(date +%s)
1460d1f417eSLuis R. Rodriguez	echo -n "$name" >"$DIR"/trigger_request 2>/dev/null
1470d1f417eSLuis R. Rodriguez	SECONDS_AFTER=$(date +%s)
1480d1f417eSLuis R. Rodriguez	SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE))
1490d1f417eSLuis R. Rodriguez	if [ "$SECONDS_DELTA" -lt 4 ]; then
1500d1f417eSLuis R. Rodriguez		RET=1
1510d1f417eSLuis R. Rodriguez	else
1520d1f417eSLuis R. Rodriguez		RET=0
1530d1f417eSLuis R. Rodriguez	fi
1540d1f417eSLuis R. Rodriguez	wait
1550d1f417eSLuis R. Rodriguez	return $RET
1560d1f417eSLuis R. Rodriguez}
157061132d2SLuis R. Rodriguez
158881c23deSLuis R. Rodrigueztest_syfs_timeout()
159881c23deSLuis R. Rodriguez{
160823b0221SLuis R. Rodriguez	DEVPATH="$DIR"/"nope-$NAME"/loading
161823b0221SLuis R. Rodriguez
162823b0221SLuis R. Rodriguez	# Test failure when doing nothing (timeout works).
163823b0221SLuis R. Rodriguez	echo -n 2 >/sys/class/firmware/timeout
164823b0221SLuis R. Rodriguez	echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null &
165823b0221SLuis R. Rodriguez
166823b0221SLuis R. Rodriguez	# Give the kernel some time to load the loading file, must be less
167823b0221SLuis R. Rodriguez	# than the timeout above.
168823b0221SLuis R. Rodriguez	sleep 1
169823b0221SLuis R. Rodriguez	if [ ! -f $DEVPATH ]; then
170823b0221SLuis R. Rodriguez		echo "$0: fallback mechanism immediately cancelled"
171823b0221SLuis R. Rodriguez		echo ""
172823b0221SLuis R. Rodriguez		echo "The file never appeared: $DEVPATH"
173823b0221SLuis R. Rodriguez		echo ""
174823b0221SLuis R. Rodriguez		echo "This might be a distribution udev rule setup by your distribution"
175823b0221SLuis R. Rodriguez		echo "to immediately cancel all fallback requests, this must be"
176823b0221SLuis R. Rodriguez		echo "removed before running these tests. To confirm look for"
177823b0221SLuis R. Rodriguez		echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"
178823b0221SLuis R. Rodriguez		echo "and see if you have something like this:"
179823b0221SLuis R. Rodriguez		echo ""
180823b0221SLuis R. Rodriguez		echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""
181823b0221SLuis R. Rodriguez		echo ""
182823b0221SLuis R. Rodriguez		echo "If you do remove this file or comment out this line before"
183823b0221SLuis R. Rodriguez		echo "proceeding with these tests."
184823b0221SLuis R. Rodriguez		exit 1
185823b0221SLuis R. Rodriguez	fi
186823b0221SLuis R. Rodriguez
187823b0221SLuis R. Rodriguez	if diff -q "$FW" /dev/test_firmware >/dev/null ; then
188823b0221SLuis R. Rodriguez		echo "$0: firmware was not expected to match" >&2
189823b0221SLuis R. Rodriguez		exit 1
190823b0221SLuis R. Rodriguez	else
191823b0221SLuis R. Rodriguez		echo "$0: timeout works"
192823b0221SLuis R. Rodriguez	fi
193881c23deSLuis R. Rodriguez}
194881c23deSLuis R. Rodriguez
19559106c81SLuis R. Rodriguezrun_sysfs_main_tests()
19659106c81SLuis R. Rodriguez{
197881c23deSLuis R. Rodriguez	test_syfs_timeout
198823b0221SLuis R. Rodriguez	# Put timeout high enough for us to do work but not so long that failures
199823b0221SLuis R. Rodriguez	# slow down this test too much.
200823b0221SLuis R. Rodriguez	echo 4 >/sys/class/firmware/timeout
201823b0221SLuis R. Rodriguez
202823b0221SLuis R. Rodriguez	# Load this script instead of the desired firmware.
203823b0221SLuis R. Rodriguez	load_fw "$NAME" "$0"
204823b0221SLuis R. Rodriguez	if diff -q "$FW" /dev/test_firmware >/dev/null ; then
205823b0221SLuis R. Rodriguez		echo "$0: firmware was not expected to match" >&2
206823b0221SLuis R. Rodriguez		exit 1
207823b0221SLuis R. Rodriguez	else
208823b0221SLuis R. Rodriguez		echo "$0: firmware comparison works"
209823b0221SLuis R. Rodriguez	fi
210823b0221SLuis R. Rodriguez
211823b0221SLuis R. Rodriguez	# Do a proper load, which should work correctly.
212823b0221SLuis R. Rodriguez	load_fw "$NAME" "$FW"
213823b0221SLuis R. Rodriguez	if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
214823b0221SLuis R. Rodriguez		echo "$0: firmware was not loaded" >&2
215823b0221SLuis R. Rodriguez		exit 1
216823b0221SLuis R. Rodriguez	else
217823b0221SLuis R. Rodriguez		echo "$0: fallback mechanism works"
218eb67bc3fSLuis R. Rodriguez	fi
219823b0221SLuis R. Rodriguez
220eb67bc3fSLuis R. Rodriguez	load_fw_cancel "nope-$NAME" "$FW"
221eb67bc3fSLuis R. Rodriguez	if diff -q "$FW" /dev/test_firmware >/dev/null ; then
222eb67bc3fSLuis R. Rodriguez		echo "$0: firmware was expected to be cancelled" >&2
223eb67bc3fSLuis R. Rodriguez		exit 1
224eb67bc3fSLuis R. Rodriguez	else
225eb67bc3fSLuis R. Rodriguez		echo "$0: cancelling fallback mechanism works"
226823b0221SLuis R. Rodriguez	fi
227823b0221SLuis R. Rodriguez
22859106c81SLuis R. Rodriguez	set +e
22959106c81SLuis R. Rodriguez	load_fw_fallback_with_child "nope-signal-$NAME" "$FW"
23059106c81SLuis R. Rodriguez	if [ "$?" -eq 0 ]; then
23159106c81SLuis R. Rodriguez		echo "$0: SIGCHLD on sync ignored as expected" >&2
23259106c81SLuis R. Rodriguez	else
23359106c81SLuis R. Rodriguez		echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2
23459106c81SLuis R. Rodriguez		exit 1
23559106c81SLuis R. Rodriguez	fi
23659106c81SLuis R. Rodriguez	set -e
23759106c81SLuis R. Rodriguez}
23859106c81SLuis R. Rodriguez
23982bdf495SLuis R. Rodriguezrun_sysfs_custom_load_tests()
24082bdf495SLuis R. Rodriguez{
2419952db75SLuis R. Rodriguez	RANDOM_FILE_PATH=$(setup_random_file)
2429952db75SLuis R. Rodriguez	RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
2439952db75SLuis R. Rodriguez	if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
2449952db75SLuis R. Rodriguez		if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
24582bdf495SLuis R. Rodriguez			echo "$0: firmware was not loaded" >&2
24682bdf495SLuis R. Rodriguez			exit 1
24782bdf495SLuis R. Rodriguez		else
24882bdf495SLuis R. Rodriguez			echo "$0: custom fallback loading mechanism works"
24982bdf495SLuis R. Rodriguez		fi
25082bdf495SLuis R. Rodriguez	fi
25159106c81SLuis R. Rodriguez
2529952db75SLuis R. Rodriguez	RANDOM_FILE_PATH=$(setup_random_file)
2539952db75SLuis R. Rodriguez	RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
2549952db75SLuis R. Rodriguez	if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
2559952db75SLuis R. Rodriguez		if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
256061132d2SLuis R. Rodriguez			echo "$0: firmware was not loaded" >&2
257061132d2SLuis R. Rodriguez			exit 1
258061132d2SLuis R. Rodriguez		else
259061132d2SLuis R. Rodriguez			echo "$0: custom fallback loading mechanism works"
260061132d2SLuis R. Rodriguez		fi
261c3e0d179SAmit Pundir	fi
262061132d2SLuis R. Rodriguez
2639952db75SLuis R. Rodriguez	RANDOM_FILE_REAL="$RANDOM_FILE_PATH"
2649952db75SLuis R. Rodriguez	FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake)
2659952db75SLuis R. Rodriguez	FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)"
2669952db75SLuis R. Rodriguez
2679952db75SLuis R. Rodriguez	if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then
2689952db75SLuis R. Rodriguez		if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
269061132d2SLuis R. Rodriguez			echo "$0: firmware was expected to be cancelled" >&2
270061132d2SLuis R. Rodriguez			exit 1
271061132d2SLuis R. Rodriguez		else
272061132d2SLuis R. Rodriguez			echo "$0: cancelling custom fallback mechanism works"
273061132d2SLuis R. Rodriguez		fi
274c3e0d179SAmit Pundir	fi
27582bdf495SLuis R. Rodriguez}
27682bdf495SLuis R. Rodriguez
277ef557787SLuis R. Rodriguezif [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then
27882bdf495SLuis R. Rodriguez	run_sysfs_main_tests
279ef557787SLuis R. Rodriguezfi
280ef557787SLuis R. Rodriguez
28182bdf495SLuis R. Rodriguezrun_sysfs_custom_load_tests
282061132d2SLuis R. Rodriguez
283823b0221SLuis R. Rodriguezexit 0
284