Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 # This validates that the kernel will fall back to using the fallback mechanism
0004 # to load firmware it can't find on disk itself. We must request a firmware
0005 # that the kernel won't find, and any installed helper (e.g. udev) also
0006 # won't find so that we can do the load ourself manually.
0007 set -e
0008 
0009 TEST_REQS_FW_SYSFS_FALLBACK="yes"
0010 TEST_REQS_FW_SET_CUSTOM_PATH="no"
0011 TEST_DIR=$(dirname $0)
0012 source $TEST_DIR/fw_lib.sh
0013 
0014 check_mods
0015 check_setup
0016 verify_reqs
0017 setup_tmp_file
0018 
0019 trap "test_finish" EXIT
0020 
0021 load_fw()
0022 {
0023         local name="$1"
0024         local file="$2"
0025 
0026         # This will block until our load (below) has finished.
0027         echo -n "$name" >"$DIR"/trigger_request &
0028 
0029         # Give kernel a chance to react.
0030         local timeout=10
0031         while [ ! -e "$DIR"/"$name"/loading ]; do
0032                 sleep 0.1
0033                 timeout=$(( $timeout - 1 ))
0034                 if [ "$timeout" -eq 0 ]; then
0035                         echo "$0: firmware interface never appeared" >&2
0036                         exit 1
0037                 fi
0038         done
0039 
0040         echo 1 >"$DIR"/"$name"/loading
0041         cat "$file" >"$DIR"/"$name"/data
0042         echo 0 >"$DIR"/"$name"/loading
0043 
0044         # Wait for request to finish.
0045         wait
0046 }
0047 
0048 load_fw_cancel()
0049 {
0050         local name="$1"
0051         local file="$2"
0052 
0053         # This will block until our load (below) has finished.
0054         echo -n "$name" >"$DIR"/trigger_request 2>/dev/null &
0055 
0056         # Give kernel a chance to react.
0057         local timeout=10
0058         while [ ! -e "$DIR"/"$name"/loading ]; do
0059                 sleep 0.1
0060                 timeout=$(( $timeout - 1 ))
0061                 if [ "$timeout" -eq 0 ]; then
0062                         echo "$0: firmware interface never appeared" >&2
0063                         exit 1
0064                 fi
0065         done
0066 
0067         echo -1 >"$DIR"/"$name"/loading
0068 
0069         # Wait for request to finish.
0070         wait
0071 }
0072 
0073 load_fw_custom()
0074 {
0075         if [ ! -e "$DIR"/trigger_custom_fallback ]; then
0076                 echo "$0: custom fallback trigger not present, ignoring test" >&2
0077                 exit $ksft_skip
0078         fi
0079 
0080         local name="$1"
0081         local file="$2"
0082 
0083         echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
0084 
0085         # Give kernel a chance to react.
0086         local timeout=10
0087         while [ ! -e "$DIR"/"$name"/loading ]; do
0088                 sleep 0.1
0089                 timeout=$(( $timeout - 1 ))
0090                 if [ "$timeout" -eq 0 ]; then
0091                         echo "$0: firmware interface never appeared" >&2
0092                         exit 1
0093                 fi
0094         done
0095 
0096         echo 1 >"$DIR"/"$name"/loading
0097         cat "$file" >"$DIR"/"$name"/data
0098         echo 0 >"$DIR"/"$name"/loading
0099 
0100         # Wait for request to finish.
0101         wait
0102         return 0
0103 }
0104 
0105 
0106 load_fw_custom_cancel()
0107 {
0108         if [ ! -e "$DIR"/trigger_custom_fallback ]; then
0109                 echo "$0: canceling custom fallback trigger not present, ignoring test" >&2
0110                 exit $ksft_skip
0111         fi
0112 
0113         local name="$1"
0114         local file="$2"
0115 
0116         echo -n "$name" >"$DIR"/trigger_custom_fallback 2>/dev/null &
0117 
0118         # Give kernel a chance to react.
0119         local timeout=10
0120         while [ ! -e "$DIR"/"$name"/loading ]; do
0121                 sleep 0.1
0122                 timeout=$(( $timeout - 1 ))
0123                 if [ "$timeout" -eq 0 ]; then
0124                         echo "$0: firmware interface never appeared" >&2
0125                         exit 1
0126                 fi
0127         done
0128 
0129         echo -1 >"$DIR"/"$name"/loading
0130 
0131         # Wait for request to finish.
0132         wait
0133         return 0
0134 }
0135 
0136 load_fw_fallback_with_child()
0137 {
0138         local name="$1"
0139         local file="$2"
0140 
0141         # This is the value already set but we want to be explicit
0142         echo 4 >/sys/class/firmware/timeout
0143 
0144         sleep 1 &
0145         SECONDS_BEFORE=$(date +%s)
0146         echo -n "$name" >"$DIR"/trigger_request 2>/dev/null
0147         SECONDS_AFTER=$(date +%s)
0148         SECONDS_DELTA=$(($SECONDS_AFTER - $SECONDS_BEFORE))
0149         if [ "$SECONDS_DELTA" -lt 4 ]; then
0150                 RET=1
0151         else
0152                 RET=0
0153         fi
0154         wait
0155         return $RET
0156 }
0157 
0158 test_syfs_timeout()
0159 {
0160         DEVPATH="$DIR"/"nope-$NAME"/loading
0161 
0162         # Test failure when doing nothing (timeout works).
0163         echo -n 2 >/sys/class/firmware/timeout
0164         echo -n "nope-$NAME" >"$DIR"/trigger_request 2>/dev/null &
0165 
0166         # Give the kernel some time to load the loading file, must be less
0167         # than the timeout above.
0168         sleep 1
0169         if [ ! -f $DEVPATH ]; then
0170                 echo "$0: fallback mechanism immediately cancelled"
0171                 echo ""
0172                 echo "The file never appeared: $DEVPATH"
0173                 echo ""
0174                 echo "This might be a distribution udev rule setup by your distribution"
0175                 echo "to immediately cancel all fallback requests, this must be"
0176                 echo "removed before running these tests. To confirm look for"
0177                 echo "a firmware rule like /lib/udev/rules.d/50-firmware.rules"
0178                 echo "and see if you have something like this:"
0179                 echo ""
0180                 echo "SUBSYSTEM==\"firmware\", ACTION==\"add\", ATTR{loading}=\"-1\""
0181                 echo ""
0182                 echo "If you do remove this file or comment out this line before"
0183                 echo "proceeding with these tests."
0184                 exit 1
0185         fi
0186 
0187         if diff -q "$FW" /dev/test_firmware >/dev/null ; then
0188                 echo "$0: firmware was not expected to match" >&2
0189                 exit 1
0190         else
0191                 echo "$0: timeout works"
0192         fi
0193 }
0194 
0195 run_sysfs_main_tests()
0196 {
0197         test_syfs_timeout
0198         # Put timeout high enough for us to do work but not so long that failures
0199         # slow down this test too much.
0200         echo 4 >/sys/class/firmware/timeout
0201 
0202         # Load this script instead of the desired firmware.
0203         load_fw "$NAME" "$0"
0204         if diff -q "$FW" /dev/test_firmware >/dev/null ; then
0205                 echo "$0: firmware was not expected to match" >&2
0206                 exit 1
0207         else
0208                 echo "$0: firmware comparison works"
0209         fi
0210 
0211         # Do a proper load, which should work correctly.
0212         load_fw "$NAME" "$FW"
0213         if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
0214                 echo "$0: firmware was not loaded" >&2
0215                 exit 1
0216         else
0217                 echo "$0: fallback mechanism works"
0218         fi
0219 
0220         load_fw_cancel "nope-$NAME" "$FW"
0221         if diff -q "$FW" /dev/test_firmware >/dev/null ; then
0222                 echo "$0: firmware was expected to be cancelled" >&2
0223                 exit 1
0224         else
0225                 echo "$0: cancelling fallback mechanism works"
0226         fi
0227 
0228         set +e
0229         load_fw_fallback_with_child "nope-signal-$NAME" "$FW"
0230         if [ "$?" -eq 0 ]; then
0231                 echo "$0: SIGCHLD on sync ignored as expected" >&2
0232         else
0233                 echo "$0: error - sync firmware request cancelled due to SIGCHLD" >&2
0234                 exit 1
0235         fi
0236         set -e
0237 }
0238 
0239 run_sysfs_custom_load_tests()
0240 {
0241         RANDOM_FILE_PATH=$(setup_random_file)
0242         RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
0243         if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
0244                 if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
0245                         echo "$0: firmware was not loaded" >&2
0246                         exit 1
0247                 else
0248                         echo "$0: custom fallback loading mechanism works"
0249                 fi
0250         fi
0251 
0252         RANDOM_FILE_PATH=$(setup_random_file)
0253         RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
0254         if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
0255                 if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
0256                         echo "$0: firmware was not loaded" >&2
0257                         exit 1
0258                 else
0259                         echo "$0: custom fallback loading mechanism works"
0260                 fi
0261         fi
0262 
0263         RANDOM_FILE_REAL="$RANDOM_FILE_PATH"
0264         FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake)
0265         FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)"
0266 
0267         if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then
0268                 if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
0269                         echo "$0: firmware was expected to be cancelled" >&2
0270                         exit 1
0271                 else
0272                         echo "$0: cancelling custom fallback mechanism works"
0273                 fi
0274         fi
0275 }
0276 
0277 if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then
0278         run_sysfs_main_tests
0279 fi
0280 
0281 run_sysfs_custom_load_tests
0282 
0283 exit 0