Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash -efu
0002 # SPDX-License-Identifier: GPL-2.0
0003 
0004 #exit status
0005 #0: success
0006 #1: fail
0007 #4: skip test - including run as non-root user
0008 
0009 BASE=${0%/*}
0010 DEBUGFS=
0011 GPIO_DEBUGFS=
0012 dev_type="cdev"
0013 module="gpio-mockup"
0014 verbose=
0015 full_test=
0016 random=
0017 uapi_opt=
0018 active_opt=
0019 bias_opt=
0020 line_set_pid=
0021 
0022 # Kselftest return codes
0023 ksft_fail=1
0024 ksft_skip=4
0025 
0026 usage()
0027 {
0028         echo "Usage:"
0029         echo "$0 [-frv] [-t type]"
0030         echo "-f:  full test (minimal set run by default)"
0031         echo "-r:  test random lines as well as fence posts"
0032         echo "-t:  interface type:"
0033         echo "      cdev (character device ABI) - default"
0034         echo "      cdev_v1 (deprecated character device ABI)"
0035         echo "      sysfs (deprecated SYSFS ABI)"
0036         echo "-v:  verbose progress reporting"
0037         exit $ksft_fail
0038 }
0039 
0040 skip()
0041 {
0042         echo "$*" >&2
0043         echo "GPIO $module test SKIP"
0044         exit $ksft_skip
0045 }
0046 
0047 prerequisite()
0048 {
0049         [ $(id -u) -eq 0 ] || skip "must be run as root"
0050 
0051         DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ')
0052         [ -d "$DEBUGFS" ] || skip "debugfs is not mounted"
0053 
0054         GPIO_DEBUGFS=$DEBUGFS/$module
0055 }
0056 
0057 remove_module()
0058 {
0059         modprobe -r -q $module
0060 }
0061 
0062 cleanup()
0063 {
0064         set +e
0065         release_line
0066         remove_module
0067         jobs -p | xargs -r kill > /dev/null 2>&1
0068 }
0069 
0070 fail()
0071 {
0072         echo "test failed: $*" >&2
0073         echo "GPIO $module test FAIL"
0074         exit $ksft_fail
0075 }
0076 
0077 try_insert_module()
0078 {
0079         modprobe -q $module "$1" || fail "insert $module failed with error $?"
0080 }
0081 
0082 log()
0083 {
0084         [ -z "$verbose" ] || echo "$*"
0085 }
0086 
0087 # The following line helpers, release_Line, get_line and set_line, all
0088 # make use of the global $chip and $offset variables.
0089 #
0090 # This implementation drives the GPIO character device (cdev) uAPI.
0091 # Other implementations may override these to test different uAPIs.
0092 
0093 # Release any resources related to the line
0094 release_line()
0095 {
0096         [ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true
0097         line_set_pid=
0098 }
0099 
0100 # Read the current value of the line
0101 get_line()
0102 {
0103         release_line
0104 
0105         local cdev_opts=${uapi_opt}${active_opt}
0106         $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset
0107         echo $?
0108 }
0109 
0110 # Set the state of the line
0111 #
0112 # Changes to line configuration are provided as parameters.
0113 # The line is assumed to be an output if the line value 0 or 1 is
0114 # specified, else an input.
0115 set_line()
0116 {
0117         local val=
0118 
0119         release_line
0120 
0121         # parse config options...
0122         for option in $*; do
0123                 case $option in
0124                 active-low)
0125                         active_opt="-l "
0126                         ;;
0127                 active-high)
0128                         active_opt=
0129                         ;;
0130                 bias-none)
0131                         bias_opt=
0132                         ;;
0133                 pull-down)
0134                         bias_opt="-bpull-down "
0135                         ;;
0136                 pull-up)
0137                         bias_opt="-bpull-up "
0138                         ;;
0139                 0)
0140                         val=0
0141                         ;;
0142                 1)
0143                         val=1
0144                         ;;
0145                 esac
0146         done
0147 
0148         local cdev_opts=${uapi_opt}${active_opt}
0149         if [ "$val" ]; then
0150                 $BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset &
0151                 # failure to set is detected by reading mockup and toggling values
0152                 line_set_pid=$!
0153                 # allow for gpio-mockup-cdev to launch and request line
0154                 # (there is limited value in checking if line has been requested)
0155                 sleep 0.01
0156         elif [ "$bias_opt" ]; then
0157                 cdev_opts=${cdev_opts}${bias_opt}
0158                 $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true
0159         fi
0160 }
0161 
0162 assert_line()
0163 {
0164         local val
0165         # don't need any retry here as set_mock allows for propagation
0166         val=$(get_line)
0167         [ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected"
0168 }
0169 
0170 # The following mockup helpers all make use of the $mock_line
0171 assert_mock()
0172 {
0173         local backoff_wait=10
0174         local retry=0
0175         local val
0176         # retry allows for set propagation from uAPI to mockup
0177         while true; do
0178                 val=$(< $mock_line)
0179                 [ "$val" = "$1" ] && break
0180                 retry=$((retry + 1))
0181                 [ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected"
0182                 sleep $(printf "%0.2f" $((backoff_wait))e-3)
0183                 backoff_wait=$((backoff_wait * 2))
0184         done
0185 }
0186 
0187 set_mock()
0188 {
0189         echo "$1" > $mock_line
0190         # allow for set propagation - so we won't be in a race with set_line
0191         assert_mock "$1"
0192 }
0193 
0194 # test the functionality of a line
0195 #
0196 # The line is set from the mockup side and is read from the userspace side
0197 # (input), and is set from the userspace side and is read from the mockup side
0198 # (output).
0199 #
0200 # Setting the mockup pull using the userspace interface bias settings is
0201 # tested where supported by the userspace interface (cdev).
0202 test_line()
0203 {
0204         chip=$1
0205         offset=$2
0206         log "test_line $chip $offset"
0207         mock_line=$GPIO_DEBUGFS/$chip/$offset
0208         [ -e "$mock_line" ] || fail "missing line $chip:$offset"
0209 
0210         # test input active-high
0211         set_mock 1
0212         set_line input active-high
0213         assert_line 1
0214         set_mock 0
0215         assert_line 0
0216         set_mock 1
0217         assert_line 1
0218 
0219         if [ "$full_test" ]; then
0220                 if [ "$dev_type" != "sysfs" ]; then
0221                         # test pulls
0222                         set_mock 0
0223                         set_line input pull-up
0224                         assert_line 1
0225                         set_mock 0
0226                         assert_line 0
0227 
0228                         set_mock 1
0229                         set_line input pull-down
0230                         assert_line 0
0231                         set_mock 1
0232                         assert_line 1
0233 
0234                         set_line bias-none
0235                 fi
0236 
0237                 # test input active-low
0238                 set_mock 0
0239                 set_line active-low
0240                 assert_line 1
0241                 set_mock 1
0242                 assert_line 0
0243                 set_mock 0
0244                 assert_line 1
0245 
0246                 # test output active-high
0247                 set_mock 1
0248                 set_line active-high 0
0249                 assert_mock 0
0250                 set_line 1
0251                 assert_mock 1
0252                 set_line 0
0253                 assert_mock 0
0254         fi
0255 
0256         # test output active-low
0257         set_mock 0
0258         set_line active-low 0
0259         assert_mock 1
0260         set_line 1
0261         assert_mock 0
0262         set_line 0
0263         assert_mock 1
0264 
0265         release_line
0266 }
0267 
0268 test_no_line()
0269 {
0270         log test_no_line "$*"
0271         [ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2"
0272 }
0273 
0274 # Load the module and check that the expected number of gpiochips, with the
0275 # expected number of lines, are created and are functional.
0276 #
0277 # $1 is the gpio_mockup_ranges parameter for the module
0278 # The remaining parameters are the number of lines, n, expected for each of
0279 # the gpiochips expected to be created.
0280 #
0281 # For each gpiochip the fence post lines, 0 and n-1, are tested, and the
0282 # line on the far side of the fence post, n, is tested to not exist.
0283 #
0284 # If the $random flag is set then a random line in the middle of the
0285 # gpiochip is tested as well.
0286 insmod_test()
0287 {
0288         local ranges=
0289         local gc=
0290         local width=
0291 
0292         [ "${1:-}" ] || fail "missing ranges"
0293         ranges=$1 ; shift
0294         try_insert_module "gpio_mockup_ranges=$ranges"
0295         log "GPIO $module test with ranges: <$ranges>:"
0296         # e.g. /sys/kernel/debug/gpio-mockup/gpiochip1
0297         gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort)
0298         for chip in $gpiochip; do
0299                 gc=${chip##*/}
0300                 [ "${1:-}" ] || fail "unexpected chip - $gc"
0301                 width=$1 ; shift
0302                 test_line $gc 0
0303                 if [ "$random" -a $width -gt 2 ]; then
0304                         test_line $gc $((RANDOM % ($width - 2) + 1))
0305                 fi
0306                 test_line $gc $(($width - 1))
0307                 test_no_line $gc $width
0308         done
0309         [ "${1:-}" ] && fail "missing expected chip of width $1"
0310         remove_module || fail "failed to remove module with error $?"
0311 }
0312 
0313 while getopts ":frvt:" opt; do
0314         case $opt in
0315         f)
0316                 full_test=true
0317                 ;;
0318         r)
0319                 random=true
0320                 ;;
0321         t)
0322                 dev_type=$OPTARG
0323                 ;;
0324         v)
0325                 verbose=true
0326                 ;;
0327         *)
0328                 usage
0329                 ;;
0330         esac
0331 done
0332 shift $((OPTIND - 1))
0333 
0334 [ "${1:-}" ] && fail "unknown argument '$1'"
0335 
0336 prerequisite
0337 
0338 trap 'exit $ksft_fail' SIGTERM SIGINT
0339 trap cleanup EXIT
0340 
0341 case "$dev_type" in
0342 sysfs)
0343         source $BASE/gpio-mockup-sysfs.sh
0344         echo "WARNING: gpio sysfs ABI is deprecated."
0345         ;;
0346 cdev_v1)
0347         echo "WARNING: gpio cdev ABI v1 is deprecated."
0348         uapi_opt="-u1 "
0349         ;;
0350 cdev)
0351         ;;
0352 *)
0353         fail "unknown interface type: $dev_type"
0354         ;;
0355 esac
0356 
0357 remove_module || fail "can't remove existing $module module"
0358 
0359 # manual gpio allocation tests fail if a physical chip already exists
0360 [ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0"
0361 
0362 echo "1.  Module load tests"
0363 echo "1.1.  dynamic allocation of gpio"
0364 insmod_test "-1,32" 32
0365 insmod_test "-1,23,-1,32" 23 32
0366 insmod_test "-1,23,-1,26,-1,32" 23 26 32
0367 if [ "$full_test" ]; then
0368         echo "1.2.  manual allocation of gpio"
0369         insmod_test "0,32" 32
0370         insmod_test "0,32,32,60" 32 28
0371         insmod_test "0,32,40,64,64,96" 32 24 32
0372         echo "1.3.  dynamic and manual allocation of gpio"
0373         insmod_test "-1,32,32,62" 32 30
0374         insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32
0375         insmod_test "-1,32,32,60,-1,29" 32 28 29
0376         insmod_test "-1,32,40,64,-1,5" 32 24 5
0377         insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31
0378 fi
0379 echo "2.  Module load error tests"
0380 echo "2.1 gpio overflow"
0381 # Currently: The max number of gpio(1024) is defined in arm architecture.
0382 insmod_test "-1,1024"
0383 if [ "$full_test" ]; then
0384         echo "2.2 no lines defined"
0385         insmod_test "0,0"
0386         echo "2.3 ignore range overlap"
0387         insmod_test "0,32,0,1" 32
0388         insmod_test "0,32,1,5" 32
0389         insmod_test "0,32,30,35" 32
0390         insmod_test "0,32,31,32" 32
0391         insmod_test "10,32,30,35" 22
0392         insmod_test "10,32,9,14" 22
0393         insmod_test "0,32,20,21,40,56" 32 16
0394         insmod_test "0,32,32,64,32,40" 32 32
0395         insmod_test "0,32,32,64,36,37" 32 32
0396         insmod_test "0,32,35,64,34,36" 32 29
0397         insmod_test "0,30,35,64,35,45" 30 29
0398         insmod_test "0,32,40,56,30,33" 32 16
0399         insmod_test "0,32,40,56,30,41" 32 16
0400         insmod_test "0,32,40,56,39,45" 32 16
0401 fi
0402 
0403 echo "GPIO $module test PASS"