Skip to content

Commit 91581c4

Browse files
author
Bartosz Golaszewski
committed
gpio: virtuser: new virtual testing driver for the GPIO API
The GPIO subsystem used to have a serious problem with undefined behavior and use-after-free bugs on hot-unplug of GPIO chips. This can be considered a corner-case by some as most GPIO controllers are enabled early in the boot process and live until the system goes down but most GPIO drivers do allow unbind over sysfs, many are loadable modules that can be (force) unloaded and there are also GPIO devices that can be dynamically detached, for instance CP2112 which is a USB GPIO expender. Bugs can be triggered both from user-space as well as by in-kernel users. We have the means of testing it from user-space via the character device but the issues manifest themselves differently in the kernel. This is a proposition of adding a new virtual driver - a configurable GPIO consumer that can be configured over configfs (similarly to gpio-sim) or described on the device-tree. This driver is aimed as a helper in spotting any regressions in hot-unplug handling in GPIOLIB. Link: https://lore.kernel.org/r/20240708142912.120570-1-brgl@bgdev.pl Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
1 parent 8060be2 commit 91581c4

File tree

5 files changed

+1998
-0
lines changed

5 files changed

+1998
-0
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
.. SPDX-License-Identifier: GPL-2.0-only
2+
3+
Virtual GPIO Consumer
4+
=====================
5+
6+
The virtual GPIO Consumer module allows users to instantiate virtual devices
7+
that request GPIOs and then control their behavior over debugfs. Virtual
8+
consumer devices can be instantiated from device-tree or over configfs.
9+
10+
A virtual consumer uses the driver-facing GPIO APIs and allows to cover it with
11+
automated tests driven by user-space. The GPIOs are requested using
12+
``gpiod_get_array()`` and so we support multiple GPIOs per connector ID.
13+
14+
Creating GPIO consumers
15+
-----------------------
16+
17+
The gpio-consumer module registers a configfs subsystem called
18+
``'gpio-virtuser'``. For details of the configfs filesystem, please refer to
19+
the configfs documentation.
20+
21+
The user can create a hierarchy of configfs groups and items as well as modify
22+
values of exposed attributes. Once the consumer is instantiated, this hierarchy
23+
will be translated to appropriate device properties. The general structure is:
24+
25+
**Group:** ``/config/gpio-virtuser``
26+
27+
This is the top directory of the gpio-consumer configfs tree.
28+
29+
**Group:** ``/config/gpio-consumer/example-name``
30+
31+
**Attribute:** ``/config/gpio-consumer/example-name/live``
32+
33+
**Attribute:** ``/config/gpio-consumer/example-name/dev_name``
34+
35+
This is a directory representing a GPIO consumer device.
36+
37+
The read-only ``dev_name`` attribute exposes the name of the device as it will
38+
appear in the system on the platform bus. This is useful for locating the
39+
associated debugfs directory under
40+
``/sys/kernel/debug/gpio-virtuser/$dev_name``.
41+
42+
The ``'live'`` attribute allows to trigger the actual creation of the device
43+
once it's fully configured. The accepted values are: ``'1'`` to enable the
44+
virtual device and ``'0'`` to disable and tear it down.
45+
46+
Creating GPIO lookup tables
47+
---------------------------
48+
49+
Users can create a number of configfs groups under the device group:
50+
51+
**Group:** ``/config/gpio-consumer/example-name/con_id``
52+
53+
The ``'con_id'`` directory represents a single GPIO lookup and its value maps
54+
to the ``'con_id'`` argument of the ``gpiod_get()`` function. For example:
55+
``con_id`` == ``'reset'`` maps to the ``reset-gpios`` device property.
56+
57+
Users can assign a number of GPIOs to each lookup. Each GPIO is a sub-directory
58+
with a user-defined name under the ``'con_id'`` group.
59+
60+
**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/key``
61+
62+
**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/offset``
63+
64+
**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/drive``
65+
66+
**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/pull``
67+
68+
**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/active_low``
69+
70+
**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/transitory``
71+
72+
This is a group describing a single GPIO in the ``con_id-gpios`` property.
73+
74+
For virtual consumers created using configfs we use machine lookup tables so
75+
this group can be considered as a mapping between the filesystem and the fields
76+
of a single entry in ``'struct gpiod_lookup'``.
77+
78+
The ``'key'`` attribute represents either the name of the chip this GPIO
79+
belongs to or the GPIO line name. This depends on the value of the ``'offset'``
80+
attribute: if its value is >= 0, then ``'key'`` represents the label of the
81+
chip to lookup while ``'offset'`` represents the offset of the line in that
82+
chip. If ``'offset'`` is < 0, then ``'key'`` represents the name of the line.
83+
84+
The remaining attributes map to the ``'flags'`` field of the GPIO lookup
85+
struct. The first two take string values as arguments:
86+
87+
**``'drive'``:** ``'push-pull'``, ``'open-drain'``, ``'open-source'``
88+
**``'pull'``:** ``'pull-up'``, ``'pull-down'``, ``'pull-disabled'``, ``'as-is'``
89+
90+
``'active_low'`` and ``'transitory'`` are boolean attributes.
91+
92+
Activating GPIO consumers
93+
-------------------------
94+
95+
Once the confiuration is complete, the ``'live'`` attribute must be set to 1 in
96+
order to instantiate the consumer. It can be set back to 0 to destroy the
97+
virtual device. The module will synchronously wait for the new simulated device
98+
to be successfully probed and if this doesn't happen, writing to ``'live'`` will
99+
result in an error.
100+
101+
Device-tree
102+
-----------
103+
104+
Virtual GPIO consumers can also be defined in device-tree. The compatible string
105+
must be: ``"gpio-virtuser"`` with at least one property following the
106+
standardized GPIO pattern.
107+
108+
An example device-tree code defining a virtual GPIO consumer:
109+
110+
.. code-block :: none
111+
112+
gpio-virt-consumer {
113+
compatible = "gpio-virtuser";
114+
115+
foo-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, <&gpio1 2 0>;
116+
bar-gpios = <&gpio0 6 0>;
117+
};
118+
119+
Controlling virtual GPIO consumers
120+
----------------------------------
121+
122+
Once active, the device will export debugfs attributes for controlling GPIO
123+
arrays as well as each requested GPIO line separately. Let's consider the
124+
following device property: ``foo-gpios = <&gpio0 0 0>, <&gpio0 4 0>;``.
125+
126+
The following debugfs attribute groups will be created:
127+
128+
**Group:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/``
129+
130+
This is the group that will contain the attributes for the entire GPIO array.
131+
132+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values``
133+
134+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values_atomic``
135+
136+
Both attributes allow to read and set arrays of GPIO values. User must pass
137+
exactly the number of values that the array contains in the form of a string
138+
containing zeroes and ones representing inactive and active GPIO states
139+
respectively. In this example: ``echo 11 > values``.
140+
141+
The ``values_atomic`` attribute works the same as ``values`` but the kernel
142+
will execute the GPIO driver callbacks in interrupt context.
143+
144+
**Group:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/``
145+
146+
This is a group that represents a single GPIO with ``$index`` being its offset
147+
in the array.
148+
149+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/consumer``
150+
151+
Allows to set and read the consumer label of the GPIO line.
152+
153+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/debounce``
154+
155+
Allows to set and read the debounce period of the GPIO line.
156+
157+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction``
158+
159+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction_atomic``
160+
161+
These two attributes allow to set the direction of the GPIO line. They accept
162+
"input" and "output" as values. The atomic variant executes the driver callback
163+
in interrupt context.
164+
165+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/interrupts``
166+
167+
If the line is requested in input mode, writing ``1`` to this attribute will
168+
make the module listen for edge interrupts on the GPIO. Writing ``0`` disables
169+
the monitoring. Reading this attribute returns the current number of registered
170+
interrupts (both edges).
171+
172+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value``
173+
174+
**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value_atomic``
175+
176+
Both attributes allow to read and set values of individual requested GPIO lines.
177+
They accept the following values: ``1`` and ``0``.

Documentation/admin-guide/gpio/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ GPIO
1010
Character Device Userspace API <../../userspace-api/gpio/chardev>
1111
gpio-aggregator
1212
gpio-sim
13+
gpio-virtuser
1314
Obsolete APIs <obsolete>
1415

1516
.. only:: subproject and html

drivers/gpio/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,18 @@ config GPIO_SLOPPY_LOGIC_ANALYZER
19081908
If this driver is built as a module it will be called
19091909
'gpio-sloppy-logic-analyzer'.
19101910

1911+
config GPIO_VIRTUSER
1912+
tristate "GPIO Virtual User Testing Module"
1913+
select DEBUG_FS
1914+
select CONFIGFS_FS
1915+
select IRQ_WORK
1916+
help
1917+
Say Y here to enable the configurable, configfs-based virtual GPIO
1918+
consumer testing driver.
1919+
1920+
This driver is aimed as a helper in spotting any regressions in
1921+
hot-unplug handling in GPIOLIB.
1922+
19111923
endmenu
19121924

19131925
endif

drivers/gpio/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
182182
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
183183
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
184184
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
185+
obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o
185186
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
186187
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
187188
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o

0 commit comments

Comments
 (0)