linux/tools/testing/selftests/gpio/gpio-mockup.sh
<<
>>
Prefs
   1#!/bin/bash -efu
   2# SPDX-License-Identifier: GPL-2.0
   3
   4#exit status
   5#0: success
   6#1: fail
   7#4: skip test - including run as non-root user
   8
   9BASE=${0%/*}
  10DEBUGFS=
  11GPIO_DEBUGFS=
  12dev_type="cdev"
  13module="gpio-mockup"
  14verbose=
  15full_test=
  16random=
  17uapi_opt=
  18active_opt=
  19bias_opt=
  20line_set_pid=
  21
  22# Kselftest return codes
  23ksft_fail=1
  24ksft_skip=4
  25
  26usage()
  27{
  28        echo "Usage:"
  29        echo "$0 [-frv] [-t type]"
  30        echo "-f:  full test (minimal set run by default)"
  31        echo "-r:  test random lines as well as fence posts"
  32        echo "-t:  interface type:"
  33        echo "      cdev (character device ABI) - default"
  34        echo "      cdev_v1 (deprecated character device ABI)"
  35        echo "      sysfs (deprecated SYSFS ABI)"
  36        echo "-v:  verbose progress reporting"
  37        exit $ksft_fail
  38}
  39
  40skip()
  41{
  42        echo "$*" >&2
  43        echo "GPIO $module test SKIP"
  44        exit $ksft_skip
  45}
  46
  47prerequisite()
  48{
  49        [ $(id -u) -eq 0 ] || skip "must be run as root"
  50
  51        DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ')
  52        [ -d "$DEBUGFS" ] || skip "debugfs is not mounted"
  53
  54        GPIO_DEBUGFS=$DEBUGFS/$module
  55}
  56
  57remove_module()
  58{
  59        modprobe -r -q $module
  60}
  61
  62cleanup()
  63{
  64        set +e
  65        release_line
  66        remove_module
  67        jobs -p | xargs -r kill > /dev/null 2>&1
  68}
  69
  70fail()
  71{
  72        echo "test failed: $*" >&2
  73        echo "GPIO $module test FAIL"
  74        exit $ksft_fail
  75}
  76
  77try_insert_module()
  78{
  79        modprobe -q $module "$1" || fail "insert $module failed with error $?"
  80}
  81
  82log()
  83{
  84        [ -z "$verbose" ] || echo "$*"
  85}
  86
  87# The following line helpers, release_Line, get_line and set_line, all
  88# make use of the global $chip and $offset variables.
  89#
  90# This implementation drives the GPIO character device (cdev) uAPI.
  91# Other implementations may override these to test different uAPIs.
  92
  93# Release any resources related to the line
  94release_line()
  95{
  96        [ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true
  97        line_set_pid=
  98}
  99
 100# Read the current value of the line
 101get_line()
 102{
 103        release_line
 104
 105        local cdev_opts=${uapi_opt}${active_opt}
 106        $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset
 107        echo $?
 108}
 109
 110# Set the state of the line
 111#
 112# Changes to line configuration are provided as parameters.
 113# The line is assumed to be an output if the line value 0 or 1 is
 114# specified, else an input.
 115set_line()
 116{
 117        local val=
 118
 119        release_line
 120
 121        # parse config options...
 122        for option in $*; do
 123                case $option in
 124                active-low)
 125                        active_opt="-l "
 126                        ;;
 127                active-high)
 128                        active_opt=
 129                        ;;
 130                bias-none)
 131                        bias_opt=
 132                        ;;
 133                pull-down)
 134                        bias_opt="-bpull-down "
 135                        ;;
 136                pull-up)
 137                        bias_opt="-bpull-up "
 138                        ;;
 139                0)
 140                        val=0
 141                        ;;
 142                1)
 143                        val=1
 144                        ;;
 145                esac
 146        done
 147
 148        local cdev_opts=${uapi_opt}${active_opt}
 149        if [ "$val" ]; then
 150                $BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset &
 151                # failure to set is detected by reading mockup and toggling values
 152                line_set_pid=$!
 153                # allow for gpio-mockup-cdev to launch and request line
 154                # (there is limited value in checking if line has been requested)
 155                sleep 0.01
 156        elif [ "$bias_opt" ]; then
 157                cdev_opts=${cdev_opts}${bias_opt}
 158                $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true
 159        fi
 160}
 161
 162assert_line()
 163{
 164        local val
 165        # don't need any retry here as set_mock allows for propagation
 166        val=$(get_line)
 167        [ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected"
 168}
 169
 170# The following mockup helpers all make use of the $mock_line
 171assert_mock()
 172{
 173        local backoff_wait=10
 174        local retry=0
 175        local val
 176        # retry allows for set propagation from uAPI to mockup
 177        while true; do
 178                val=$(< $mock_line)
 179                [ "$val" = "$1" ] && break
 180                retry=$((retry + 1))
 181                [ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected"
 182                sleep $(printf "%0.2f" $((backoff_wait))e-3)
 183                backoff_wait=$((backoff_wait * 2))
 184        done
 185}
 186
 187set_mock()
 188{
 189        echo "$1" > $mock_line
 190        # allow for set propagation - so we won't be in a race with set_line
 191        assert_mock "$1"
 192}
 193
 194# test the functionality of a line
 195#
 196# The line is set from the mockup side and is read from the userspace side
 197# (input), and is set from the userspace side and is read from the mockup side
 198# (output).
 199#
 200# Setting the mockup pull using the userspace interface bias settings is
 201# tested where supported by the userspace interface (cdev).
 202test_line()
 203{
 204        chip=$1
 205        offset=$2
 206        log "test_line $chip $offset"
 207        mock_line=$GPIO_DEBUGFS/$chip/$offset
 208        [ -e "$mock_line" ] || fail "missing line $chip:$offset"
 209
 210        # test input active-high
 211        set_mock 1
 212        set_line input active-high
 213        assert_line 1
 214        set_mock 0
 215        assert_line 0
 216        set_mock 1
 217        assert_line 1
 218
 219        if [ "$full_test" ]; then
 220                if [ "$dev_type" != "sysfs" ]; then
 221                        # test pulls
 222                        set_mock 0
 223                        set_line input pull-up
 224                        assert_line 1
 225                        set_mock 0
 226                        assert_line 0
 227
 228                        set_mock 1
 229                        set_line input pull-down
 230                        assert_line 0
 231                        set_mock 1
 232                        assert_line 1
 233
 234                        set_line bias-none
 235                fi
 236
 237                # test input active-low
 238                set_mock 0
 239                set_line active-low
 240                assert_line 1
 241                set_mock 1
 242                assert_line 0
 243                set_mock 0
 244                assert_line 1
 245
 246                # test output active-high
 247                set_mock 1
 248                set_line active-high 0
 249                assert_mock 0
 250                set_line 1
 251                assert_mock 1
 252                set_line 0
 253                assert_mock 0
 254        fi
 255
 256        # test output active-low
 257        set_mock 0
 258        set_line active-low 0
 259        assert_mock 1
 260        set_line 1
 261        assert_mock 0
 262        set_line 0
 263        assert_mock 1
 264
 265        release_line
 266}
 267
 268test_no_line()
 269{
 270        log test_no_line "$*"
 271        [ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2"
 272}
 273
 274# Load the module and check that the expected number of gpiochips, with the
 275# expected number of lines, are created and are functional.
 276#
 277# $1 is the gpio_mockup_ranges parameter for the module
 278# The remaining parameters are the number of lines, n, expected for each of
 279# the gpiochips expected to be created.
 280#
 281# For each gpiochip the fence post lines, 0 and n-1, are tested, and the
 282# line on the far side of the fence post, n, is tested to not exist.
 283#
 284# If the $random flag is set then a random line in the middle of the
 285# gpiochip is tested as well.
 286insmod_test()
 287{
 288        local ranges=
 289        local gc=
 290        local width=
 291
 292        [ "${1:-}" ] || fail "missing ranges"
 293        ranges=$1 ; shift
 294        try_insert_module "gpio_mockup_ranges=$ranges"
 295        log "GPIO $module test with ranges: <$ranges>:"
 296        # e.g. /sys/kernel/debug/gpio-mockup/gpiochip1
 297        gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort)
 298        for chip in $gpiochip; do
 299                gc=${chip##*/}
 300                [ "${1:-}" ] || fail "unexpected chip - $gc"
 301                width=$1 ; shift
 302                test_line $gc 0
 303                if [ "$random" -a $width -gt 2 ]; then
 304                        test_line $gc $((RANDOM % ($width - 2) + 1))
 305                fi
 306                test_line $gc $(($width - 1))
 307                test_no_line $gc $width
 308        done
 309        [ "${1:-}" ] && fail "missing expected chip of width $1"
 310        remove_module || fail "failed to remove module with error $?"
 311}
 312
 313while getopts ":frvt:" opt; do
 314        case $opt in
 315        f)
 316                full_test=true
 317                ;;
 318        r)
 319                random=true
 320                ;;
 321        t)
 322                dev_type=$OPTARG
 323                ;;
 324        v)
 325                verbose=true
 326                ;;
 327        *)
 328                usage
 329                ;;
 330        esac
 331done
 332shift $((OPTIND - 1))
 333
 334[ "${1:-}" ] && fail "unknown argument '$1'"
 335
 336prerequisite
 337
 338trap 'exit $ksft_fail' SIGTERM SIGINT
 339trap cleanup EXIT
 340
 341case "$dev_type" in
 342sysfs)
 343        source $BASE/gpio-mockup-sysfs.sh
 344        echo "WARNING: gpio sysfs ABI is deprecated."
 345        ;;
 346cdev_v1)
 347        echo "WARNING: gpio cdev ABI v1 is deprecated."
 348        uapi_opt="-u1 "
 349        ;;
 350cdev)
 351        ;;
 352*)
 353        fail "unknown interface type: $dev_type"
 354        ;;
 355esac
 356
 357remove_module || fail "can't remove existing $module module"
 358
 359# manual gpio allocation tests fail if a physical chip already exists
 360[ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0"
 361
 362echo "1.  Module load tests"
 363echo "1.1.  dynamic allocation of gpio"
 364insmod_test "-1,32" 32
 365insmod_test "-1,23,-1,32" 23 32
 366insmod_test "-1,23,-1,26,-1,32" 23 26 32
 367if [ "$full_test" ]; then
 368        echo "1.2.  manual allocation of gpio"
 369        insmod_test "0,32" 32
 370        insmod_test "0,32,32,60" 32 28
 371        insmod_test "0,32,40,64,64,96" 32 24 32
 372        echo "1.3.  dynamic and manual allocation of gpio"
 373        insmod_test "-1,32,32,62" 32 30
 374        insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32
 375        insmod_test "-1,32,32,60,-1,29" 32 28 29
 376        insmod_test "-1,32,40,64,-1,5" 32 24 5
 377        insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31
 378fi
 379echo "2.  Module load error tests"
 380echo "2.1 gpio overflow"
 381# Currently: The max number of gpio(1024) is defined in arm architecture.
 382insmod_test "-1,1024"
 383if [ "$full_test" ]; then
 384        echo "2.2 no lines defined"
 385        insmod_test "0,0"
 386        echo "2.3 ignore range overlap"
 387        insmod_test "0,32,0,1" 32
 388        insmod_test "0,32,1,5" 32
 389        insmod_test "0,32,30,35" 32
 390        insmod_test "0,32,31,32" 32
 391        insmod_test "10,32,30,35" 22
 392        insmod_test "10,32,9,14" 22
 393        insmod_test "0,32,20,21,40,56" 32 16
 394        insmod_test "0,32,32,64,32,40" 32 32
 395        insmod_test "0,32,32,64,36,37" 32 32
 396        insmod_test "0,32,35,64,34,36" 32 29
 397        insmod_test "0,30,35,64,35,45" 30 29
 398        insmod_test "0,32,40,56,30,33" 32 16
 399        insmod_test "0,32,40,56,30,41" 32 16
 400        insmod_test "0,32,40,56,39,45" 32 16
 401fi
 402
 403echo "GPIO $module test PASS"
 404