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