[RFD,2/3] selftest/gpio: add gpio test case
diff mbox

Message ID 1447491097-14799-3-git-send-email-bamvor.zhangjian@linaro.org
State New
Headers show

Commit Message

Bamvor Jian Zhang Nov. 14, 2015, 8:51 a.m. UTC
This test script try to do whitebox testing for gpio subsystem(
based on gpiolib). It manipulate gpio-mockup device through sysfs
provided and check the result from debugfs.

Test the following things:
1.  Add single, multi gpiochip with the checking of overlap.
2.  Test direction and output value for valid pin.
3.  Test dynamic allocation of gpio base.

Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
---
 tools/testing/selftests/Makefile     |   1 +
 tools/testing/selftests/gpio/gpio.sh | 238 +++++++++++++++++++++++++++++++++++
 2 files changed, 239 insertions(+)
 create mode 100755 tools/testing/selftests/gpio/gpio.sh

Comments

Linus Walleij Nov. 26, 2015, 9:50 a.m. UTC | #1
On Sat, Nov 14, 2015 at 9:51 AM, Bamvor Jian Zhang
<bamvor.zhangjian@linaro.org> wrote:

> This test script try to do whitebox testing for gpio subsystem(
> based on gpiolib). It manipulate gpio-mockup device through sysfs
> provided and check the result from debugfs.
>
> Test the following things:
> 1.  Add single, multi gpiochip with the checking of overlap.
> 2.  Test direction and output value for valid pin.
> 3.  Test dynamic allocation of gpio base.
>
> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>

I like what this test is doing, but at some point we will need tests
written in C.

The reason is that we are working on a character device for gpio,
and once we have that, we want to be able to run these tests using
the same program.

But maybe this suffice for the sysfs tests of the current ABI.

> +++ b/tools/testing/selftests/gpio/gpio.sh

Rename it gpio-mockup-sysfs.sh please.

> +#!/bin/bash
> +
> +module="gpio-mockup"

This is ABI so not changing, you can just encode it into the
program, but OK.

> +
> +SYSFS=
> +GPIO_SYSFS=
> +GPIO_DRV_SYSFS=
> +DEBUGFS=
> +GPIO_DEBUGFS=
> +
> +prerequisite()
> +{
> +       msg="skip all tests:"
> +
> +       if [ $UID != 0 ]; then
> +               echo $msg must be run as root >&2
> +               exit 0
> +       fi
> +
> +       SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
> +       if [ ! -d "$SYSFS" ]; then
> +               echo $msg sysfs is not mounted >&2
> +               exit 0
> +       fi
> +       GPIO_SYSFS=`echo $SYSFS/class/gpio`
> +       GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
> +
> +       DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
> +       if [ ! -d "$DEBUGFS" ]; then
> +               echo $msg debugfs is not mounted >&2
> +               exit 0
> +       fi
> +       GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
> +
> +}

Looks good.

> +insert_module()
> +{
> +       if modprobe -q $module $1; then
> +               echo -n ""
> +       else
> +               echo $msg insmod $module failed >&2
> +               exit 0
> +       fi
> +}
> +
> +remove_module()
> +{
> +       modprobe -r -q $module
> +}
> +
> +die()
> +{
> +       remove_module
> +       exit 1
> +}

So this inserting/removing modules work fine unless you want to
run the tests with the module compiled-in. We should support that
usecase too. So these functions must bail out silently if the module
is already loaded (compiled in).

> +gpio_test()
> +{
> +       param=$1
> +       if [ X$2 != X ]; then
> +               invalid_pin=$2
> +       fi
> +       if [ X$param = X ]; then
> +               insert_module
> +       else
> +               insert_module "conf=$param"
> +       fi

As mentioned in the previous patch I'm suspicious about the parameters.
Let's just have one or two mock chips and cut down on the
parameterization.

> +       echo -n "GPIO $module test with base,ngpio configure<"
> +       if [ X$param = X ]; then
> +               echo "(default)>: ";
> +       else
> +               echo "$param>: "
> +       fi
> +       printf "%-10s %-5s %-5s\n" name base ngpio
> +       gpiochip=`ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
> +       if [ X"$gpiochip" = X ]; then
> +               echo "no gpiochip"
> +       else
> +               for chip in $gpiochip; do
> +                       name=`basename $chip`
> +                       base=`cat $chip/base`
> +                       ngpio=`cat $chip/ngpio`

This is nice, because it relies on the chip informing us about the
base and ngpio, meaning we can use a dynamic base, as pointed
out in the previous patch.

> +#test dynamic allocation of gpio
> +gpio_test "-1,32"
> +gpio_test "-1,32,32,16" 31
> +gpio_test "-1,32,40,16,-1,5" 38

I think these are the only tests we should have, really.

Using base 0 as some tests are doing is not going to work on
any system that already has a built-in GPIO (SoC) controller.
I think it is better to just use and test dynamic allocations.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bamvor Jian Zhang Nov. 26, 2015, 4:18 p.m. UTC | #2
Hi, Linus

On 11/26/2015 05:50 PM, Linus Walleij wrote:
> On Sat, Nov 14, 2015 at 9:51 AM, Bamvor Jian Zhang
> <bamvor.zhangjian@linaro.org> wrote:
> 
>> This test script try to do whitebox testing for gpio subsystem(
>> based on gpiolib). It manipulate gpio-mockup device through sysfs
>> provided and check the result from debugfs.
>>
>> Test the following things:
>> 1.  Add single, multi gpiochip with the checking of overlap.
>> 2.  Test direction and output value for valid pin.
>> 3.  Test dynamic allocation of gpio base.
>>
>> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
> 
> I like what this test is doing, but at some point we will need tests
> written in C.
> 
> The reason is that we are working on a character device for gpio,
> and once we have that, we want to be able to run these tests using
> the same program.
Understand, Written in c is easy to support both of them.
> But maybe this suffice for the sysfs tests of the current ABI.
Yeap.
> 
>> +++ b/tools/testing/selftests/gpio/gpio.sh
> 
> Rename it gpio-mockup-sysfs.sh please.
> 
>> +#!/bin/bash
>> +
>> +module="gpio-mockup"
> 
> This is ABI so not changing, you can just encode it into the
> program, but OK.
I was thinking if we could use this script to test gpio hardware
which support the 'standard' debugfs interface in gpiolib. It
rely on the feature that gpio could read back the output value.
I assume that lots of hw support this feature, if so, we could
use this script this gpio framework and gpio hw at the same
time.
> 
>> +
>> +SYSFS=
>> +GPIO_SYSFS=
>> +GPIO_DRV_SYSFS=
>> +DEBUGFS=
>> +GPIO_DEBUGFS=
>> +
>> +prerequisite()
>> +{
>> +       msg="skip all tests:"
>> +
>> +       if [ $UID != 0 ]; then
>> +               echo $msg must be run as root >&2
>> +               exit 0
>> +       fi
>> +
>> +       SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
>> +       if [ ! -d "$SYSFS" ]; then
>> +               echo $msg sysfs is not mounted >&2
>> +               exit 0
>> +       fi
>> +       GPIO_SYSFS=`echo $SYSFS/class/gpio`
>> +       GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
>> +
>> +       DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
>> +       if [ ! -d "$DEBUGFS" ]; then
>> +               echo $msg debugfs is not mounted >&2
>> +               exit 0
>> +       fi
>> +       GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
>> +
>> +}
> 
> Looks good.
> 
>> +insert_module()
>> +{
>> +       if modprobe -q $module $1; then
>> +               echo -n ""
>> +       else
>> +               echo $msg insmod $module failed >&2
>> +               exit 0
>> +       fi
>> +}
>> +
>> +remove_module()
>> +{
>> +       modprobe -r -q $module
>> +}
>> +
>> +die()
>> +{
>> +       remove_module
>> +       exit 1
>> +}
> 
> So this inserting/removing modules work fine unless you want to
> run the tests with the module compiled-in. We should support that
> usecase too. So these functions must bail out silently if the module
> is already loaded (compiled in).
Yeap, understand. I try to do this by passing the '-q' to modprobe.
"With this flag, modprobe won't print an error message if you try to
remove or insert a module it can't find (and isn't an alias or
install/remove command).".
> 
>> +gpio_test()
>> +{
>> +       param=$1
>> +       if [ X$2 != X ]; then
>> +               invalid_pin=$2
>> +       fi
>> +       if [ X$param = X ]; then
>> +               insert_module
>> +       else
>> +               insert_module "conf=$param"
>> +       fi
> 
> As mentioned in the previous patch I'm suspicious about the parameters.
> Let's just have one or two mock chips and cut down on the
> parameterization.
Maybe we could discuss it in the previous patch?
> 
>> +       echo -n "GPIO $module test with base,ngpio configure<"
>> +       if [ X$param = X ]; then
>> +               echo "(default)>: ";
>> +       else
>> +               echo "$param>: "
>> +       fi
>> +       printf "%-10s %-5s %-5s\n" name base ngpio
>> +       gpiochip=`ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
>> +       if [ X"$gpiochip" = X ]; then
>> +               echo "no gpiochip"
>> +       else
>> +               for chip in $gpiochip; do
>> +                       name=`basename $chip`
>> +                       base=`cat $chip/base`
>> +                       ngpio=`cat $chip/ngpio`
> 
> This is nice, because it relies on the chip informing us about the
> base and ngpio, meaning we can use a dynamic base, as pointed
> out in the previous patch.
yes.
>> +#test dynamic allocation of gpio
>> +gpio_test "-1,32"
>> +gpio_test "-1,32,32,16" 31
>> +gpio_test "-1,32,40,16,-1,5" 38
> 
> I think these are the only tests we should have, really.
Nope. If we only use the dynamic base, we could not test the corner
case in gpiochip_add_to_list. How about we mix the dynamic and
static base: insert a dynamic gpiochip and read back the base
allocated, then insert a static base to do the overlap test.
Is it make sense to you?
> 
> Using base 0 as some tests are doing is not going to work on
> any system that already has a built-in GPIO (SoC) controller.
> I think it is better to just use and test dynamic allocations.
Oh, yes. Insert base 0 without condition may fail in above case.
How about read back the current gpio range. And find out the
empty range to test? I could default to test the range in the
middle of the [0, MAX].

Regards

Bamvor
> 
> Yours,
> Linus Walleij
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index cfe1213..df0b81d 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -5,6 +5,7 @@  TARGETS += exec
 TARGETS += firmware
 TARGETS += ftrace
 TARGETS += futex
+TARGETS += gpio
 TARGETS += kcmp
 TARGETS += membarrier
 TARGETS += memfd
diff --git a/tools/testing/selftests/gpio/gpio.sh b/tools/testing/selftests/gpio/gpio.sh
new file mode 100755
index 0000000..05e109e
--- /dev/null
+++ b/tools/testing/selftests/gpio/gpio.sh
@@ -0,0 +1,238 @@ 
+#!/bin/bash
+
+module="gpio-mockup"
+
+SYSFS=
+GPIO_SYSFS=
+GPIO_DRV_SYSFS=
+DEBUGFS=
+GPIO_DEBUGFS=
+
+prerequisite()
+{
+	msg="skip all tests:"
+
+	if [ $UID != 0 ]; then
+		echo $msg must be run as root >&2
+		exit 0
+	fi
+
+	SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
+	if [ ! -d "$SYSFS" ]; then
+		echo $msg sysfs is not mounted >&2
+		exit 0
+	fi
+	GPIO_SYSFS=`echo $SYSFS/class/gpio`
+	GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
+
+	DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
+	if [ ! -d "$DEBUGFS" ]; then
+		echo $msg debugfs is not mounted >&2
+		exit 0
+	fi
+	GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
+
+}
+
+insert_module()
+{
+	if modprobe -q $module $1; then
+		echo -n ""
+	else
+		echo $msg insmod $module failed >&2
+		exit 0
+	fi
+}
+
+remove_module()
+{
+	modprobe -r -q $module
+}
+
+die()
+{
+	remove_module
+	exit 1
+}
+
+gpio_test()
+{
+	param=$1
+	if [ X$2 != X ]; then
+		invalid_pin=$2
+	fi
+	if [ X$param = X ]; then
+		insert_module
+	else
+		insert_module "conf=$param"
+	fi
+
+	echo -n "GPIO $module test with base,ngpio configure<"
+	if [ X$param = X ]; then
+		echo "(default)>: ";
+	else
+		echo "$param>: "
+	fi
+	printf "%-10s %-5s %-5s\n" name base ngpio
+	gpiochip=`ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
+	if [ X"$gpiochip" = X ]; then
+		echo "no gpiochip"
+	else
+		for chip in $gpiochip; do
+			name=`basename $chip`
+			base=`cat $chip/base`
+			ngpio=`cat $chip/ngpio`
+			printf "%-10s %-5s %-5s\n" $name $base $ngpio
+			if [ $ngpio = "0" ]; then
+				echo "number of gpio is zero is not allowed".
+			fi
+			test_one_pin $base
+			test_one_pin $(($base + $ngpio - 1))
+			test_one_pin $((( RANDOM % $ngpio )  + $base ))
+			if [ X$invalid_pin != X ]; then
+				test_one_pin_fail $invalid_pin
+			fi
+		done
+	fi
+	remove_module
+}
+
+gpio_test_fail()
+{
+	param=$1
+
+	insert_module "conf=$param"
+	echo -n "GPIO $module fail test with base,ngpio configure<$param>: "
+	gpiochip=`ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
+	if [ X"$gpiochip" = X ]; then
+		echo "successful"
+	else
+		echo "fail"
+		die
+	fi
+	remove_module
+}
+
+is_consistent()
+{
+	val=
+
+	active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low`
+	val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value`
+	dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction`
+
+	gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"`
+	dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'`
+	val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'`
+	if [ $val_debugfs = "lo" ]; then
+		val=0
+	elif [ $val_debugfs = "hi" ]; then
+		val=1
+	fi
+
+	if [ $active_low_sysfs = "1" ]; then
+		if [ $val = "0" ]; then
+			val="1"
+		else
+			val="0"
+		fi
+	fi
+
+	if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then
+		echo -n "."
+	else
+		echo "test fail, exit"
+		die
+	fi
+}
+
+test_pin_logic()
+{
+	nr=$1
+	direction=$2
+	active_low=$3
+	value=$4
+
+	echo $direction > $GPIO_SYSFS/gpio$nr/direction
+	echo $active_low > $GPIO_SYSFS/gpio$nr/active_low
+	if [ $direction = "out" ]; then
+		echo $value > $GPIO_SYSFS/gpio$nr/value
+	fi
+	is_consistent $nr
+}
+
+test_one_pin()
+{
+	nr=$1
+
+	echo -n "test pin<$nr>"
+
+	echo $nr > $GPIO_SYSFS/export 2>/dev/null
+
+	if [ X$? != X0 ]; then
+		echo "test GPIO pin $nr failed"
+		die
+	fi
+
+	#"Checking if the sysfs is consistent with debugfs: "
+	is_consistent $nr
+
+	#"Checking the logic of active_low: "
+	test_pin_logic $nr out 1 1
+	test_pin_logic $nr out 1 0
+	test_pin_logic $nr out 0 1
+	test_pin_logic $nr out 0 0
+
+	#"Checking the logic of direction: "
+	test_pin_logic $nr in 1 1
+	test_pin_logic $nr out 1 0
+	test_pin_logic $nr low 0 1
+	test_pin_logic $nr high 0 0
+
+	echo $nr > $GPIO_SYSFS/unexport
+
+	echo "successful"
+}
+
+test_one_pin_fail()
+{
+	nr=$1
+
+	echo $nr > $GPIO_SYSFS/export 2>/dev/null
+
+	if [ X$? != X0 ]; then
+		echo "test invalid pin $nr successful"
+	else
+		echo "test invalid pin $nr failed"
+		echo $nr > $GPIO_SYSFS/unexport 2>/dev/null
+		die
+	fi
+}
+
+prerequisite
+
+#basically
+gpio_test
+gpio_test "0,32" 33
+gpio_test "0,32,32,16" 50
+gpio_test "0,32,40,16,32,5" 38
+#test dynamic allocation of gpio
+gpio_test "-1,32"
+gpio_test "-1,32,32,16" 31
+gpio_test "-1,32,40,16,-1,5" 38
+#error test
+#zero number of gpio
+gpio_test_fail "0,0"
+#base conflict
+gpio_test_fail "0,32,0,1"
+#range overlap
+gpio_test_fail "0,32,30,5"
+gpio_test_fail "0,32,1,5"
+gpio_test_fail "10,32,9,5"
+gpio_test_fail "10,32,30,5"
+gpio_test_fail "0,32,40,16,39,5"
+gpio_test_fail "0,32,40,16,30,5"
+gpio_test_fail "0,32,40,16,30,11"
+gpio_test_fail "0,32,40,16,20,1"
+
+echo GPIO test PASS