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