Home | History | Annotate | Download | only in firmware
      1 #!/bin/bash
      2 # SPDX-License-Identifier: GPL-2.0
      3 # This validates that the kernel will load firmware out of its list of
      4 # firmware locations on disk. Since the user helper does similar work,
      5 # we reset the custom load directory to a location the user helper doesn't
      6 # know so we can be sure we're not accidentally testing the user helper.
      7 set -e
      8 
      9 TEST_REQS_FW_SYSFS_FALLBACK="no"
     10 TEST_REQS_FW_SET_CUSTOM_PATH="yes"
     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 if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
     22 	# Turn down the timeout so failures don't take so long.
     23 	echo 1 >/sys/class/firmware/timeout
     24 fi
     25 
     26 if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then
     27 	echo "$0: empty filename should not succeed" >&2
     28 	exit 1
     29 fi
     30 
     31 if [ ! -e "$DIR"/trigger_async_request ]; then
     32 	echo "$0: empty filename: async trigger not present, ignoring test" >&2
     33 	exit $ksft_skip
     34 else
     35 	if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then
     36 		echo "$0: empty filename should not succeed (async)" >&2
     37 		exit 1
     38 	fi
     39 fi
     40 
     41 # Request a firmware that doesn't exist, it should fail.
     42 if echo -n "nope-$NAME" >"$DIR"/trigger_request 2> /dev/null; then
     43 	echo "$0: firmware shouldn't have loaded" >&2
     44 	exit 1
     45 fi
     46 if diff -q "$FW" /dev/test_firmware >/dev/null ; then
     47 	echo "$0: firmware was not expected to match" >&2
     48 	exit 1
     49 else
     50 	if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
     51 		echo "$0: timeout works"
     52 	fi
     53 fi
     54 
     55 # This should succeed via kernel load or will fail after 1 second after
     56 # being handed over to the user helper, which won't find the fw either.
     57 if ! echo -n "$NAME" >"$DIR"/trigger_request ; then
     58 	echo "$0: could not trigger request" >&2
     59 	exit 1
     60 fi
     61 
     62 # Verify the contents are what we expect.
     63 if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
     64 	echo "$0: firmware was not loaded" >&2
     65 	exit 1
     66 else
     67 	echo "$0: filesystem loading works"
     68 fi
     69 
     70 # Try the asynchronous version too
     71 if [ ! -e "$DIR"/trigger_async_request ]; then
     72 	echo "$0: firmware loading: async trigger not present, ignoring test" >&2
     73 	exit $ksft_skip
     74 else
     75 	if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then
     76 		echo "$0: could not trigger async request" >&2
     77 		exit 1
     78 	fi
     79 
     80 	# Verify the contents are what we expect.
     81 	if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
     82 		echo "$0: firmware was not loaded (async)" >&2
     83 		exit 1
     84 	else
     85 		echo "$0: async filesystem loading works"
     86 	fi
     87 fi
     88 
     89 ### Batched requests tests
     90 test_config_present()
     91 {
     92 	if [ ! -f $DIR/reset ]; then
     93 		echo "Configuration triggers not present, ignoring test"
     94 		exit $ksft_skip
     95 	fi
     96 }
     97 
     98 # Defaults :
     99 #
    100 # send_uevent: 1
    101 # sync_direct: 0
    102 # name: test-firmware.bin
    103 # num_requests: 4
    104 config_reset()
    105 {
    106 	echo 1 >  $DIR/reset
    107 }
    108 
    109 release_all_firmware()
    110 {
    111 	echo 1 >  $DIR/release_all_firmware
    112 }
    113 
    114 config_set_name()
    115 {
    116 	echo -n $1 >  $DIR/config_name
    117 }
    118 
    119 config_set_sync_direct()
    120 {
    121 	echo 1 >  $DIR/config_sync_direct
    122 }
    123 
    124 config_unset_sync_direct()
    125 {
    126 	echo 0 >  $DIR/config_sync_direct
    127 }
    128 
    129 config_set_uevent()
    130 {
    131 	echo 1 >  $DIR/config_send_uevent
    132 }
    133 
    134 config_unset_uevent()
    135 {
    136 	echo 0 >  $DIR/config_send_uevent
    137 }
    138 
    139 config_trigger_sync()
    140 {
    141 	echo -n 1 > $DIR/trigger_batched_requests 2>/dev/null
    142 }
    143 
    144 config_trigger_async()
    145 {
    146 	echo -n 1 > $DIR/trigger_batched_requests_async 2> /dev/null
    147 }
    148 
    149 config_set_read_fw_idx()
    150 {
    151 	echo -n $1 > $DIR/config_read_fw_idx 2> /dev/null
    152 }
    153 
    154 read_firmwares()
    155 {
    156 	for i in $(seq 0 3); do
    157 		config_set_read_fw_idx $i
    158 		# Verify the contents are what we expect.
    159 		# -Z required for now -- check for yourself, md5sum
    160 		# on $FW and DIR/read_firmware will yield the same. Even
    161 		# cmp agrees, so something is off.
    162 		if ! diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then
    163 			echo "request #$i: firmware was not loaded" >&2
    164 			exit 1
    165 		fi
    166 	done
    167 }
    168 
    169 read_firmwares_expect_nofile()
    170 {
    171 	for i in $(seq 0 3); do
    172 		config_set_read_fw_idx $i
    173 		# Ensures contents differ
    174 		if diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then
    175 			echo "request $i: file was not expected to match" >&2
    176 			exit 1
    177 		fi
    178 	done
    179 }
    180 
    181 test_batched_request_firmware_nofile()
    182 {
    183 	echo -n "Batched request_firmware() nofile try #$1: "
    184 	config_reset
    185 	config_set_name nope-test-firmware.bin
    186 	config_trigger_sync
    187 	read_firmwares_expect_nofile
    188 	release_all_firmware
    189 	echo "OK"
    190 }
    191 
    192 test_batched_request_firmware_direct_nofile()
    193 {
    194 	echo -n "Batched request_firmware_direct() nofile try #$1: "
    195 	config_reset
    196 	config_set_name nope-test-firmware.bin
    197 	config_set_sync_direct
    198 	config_trigger_sync
    199 	release_all_firmware
    200 	echo "OK"
    201 }
    202 
    203 test_request_firmware_nowait_uevent_nofile()
    204 {
    205 	echo -n "Batched request_firmware_nowait(uevent=true) nofile try #$1: "
    206 	config_reset
    207 	config_set_name nope-test-firmware.bin
    208 	config_trigger_async
    209 	release_all_firmware
    210 	echo "OK"
    211 }
    212 
    213 test_wait_and_cancel_custom_load()
    214 {
    215 	if [ "$HAS_FW_LOADER_USER_HELPER" != "yes" ]; then
    216 		return
    217 	fi
    218 	local timeout=10
    219 	name=$1
    220 	while [ ! -e "$DIR"/"$name"/loading ]; do
    221 		sleep 0.1
    222 		timeout=$(( $timeout - 1 ))
    223 		if [ "$timeout" -eq 0 ]; then
    224 			echo "firmware interface never appeared:" >&2
    225 			echo "$DIR/$name/loading" >&2
    226 			exit 1
    227 		fi
    228 	done
    229 	echo -1 >"$DIR"/"$name"/loading
    230 }
    231 
    232 test_request_firmware_nowait_custom_nofile()
    233 {
    234 	echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: "
    235 	config_reset
    236 	config_unset_uevent
    237 	RANDOM_FILE_PATH=$(setup_random_file_fake)
    238 	RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
    239 	config_set_name $RANDOM_FILE
    240 	config_trigger_async &
    241 	test_wait_and_cancel_custom_load $RANDOM_FILE
    242 	wait
    243 	release_all_firmware
    244 	echo "OK"
    245 }
    246 
    247 test_batched_request_firmware()
    248 {
    249 	echo -n "Batched request_firmware() try #$1: "
    250 	config_reset
    251 	config_trigger_sync
    252 	read_firmwares
    253 	release_all_firmware
    254 	echo "OK"
    255 }
    256 
    257 test_batched_request_firmware_direct()
    258 {
    259 	echo -n "Batched request_firmware_direct() try #$1: "
    260 	config_reset
    261 	config_set_sync_direct
    262 	config_trigger_sync
    263 	release_all_firmware
    264 	echo "OK"
    265 }
    266 
    267 test_request_firmware_nowait_uevent()
    268 {
    269 	echo -n "Batched request_firmware_nowait(uevent=true) try #$1: "
    270 	config_reset
    271 	config_trigger_async
    272 	release_all_firmware
    273 	echo "OK"
    274 }
    275 
    276 test_request_firmware_nowait_custom()
    277 {
    278 	echo -n "Batched request_firmware_nowait(uevent=false) try #$1: "
    279 	config_reset
    280 	config_unset_uevent
    281 	RANDOM_FILE_PATH=$(setup_random_file)
    282 	RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
    283 	config_set_name $RANDOM_FILE
    284 	config_trigger_async
    285 	release_all_firmware
    286 	echo "OK"
    287 }
    288 
    289 # Only continue if batched request triggers are present on the
    290 # test-firmware driver
    291 test_config_present
    292 
    293 # test with the file present
    294 echo
    295 echo "Testing with the file present..."
    296 for i in $(seq 1 5); do
    297 	test_batched_request_firmware $i
    298 done
    299 
    300 for i in $(seq 1 5); do
    301 	test_batched_request_firmware_direct $i
    302 done
    303 
    304 for i in $(seq 1 5); do
    305 	test_request_firmware_nowait_uevent $i
    306 done
    307 
    308 for i in $(seq 1 5); do
    309 	test_request_firmware_nowait_custom $i
    310 done
    311 
    312 # Test for file not found, errors are expected, the failure would be
    313 # a hung task, which would require a hard reset.
    314 echo
    315 echo "Testing with the file missing..."
    316 for i in $(seq 1 5); do
    317 	test_batched_request_firmware_nofile $i
    318 done
    319 
    320 for i in $(seq 1 5); do
    321 	test_batched_request_firmware_direct_nofile $i
    322 done
    323 
    324 for i in $(seq 1 5); do
    325 	test_request_firmware_nowait_uevent_nofile $i
    326 done
    327 
    328 for i in $(seq 1 5); do
    329 	test_request_firmware_nowait_custom_nofile $i
    330 done
    331 
    332 exit 0
    333