gpio: virtuser: new virtual testing driver for the GPIO API
Subsystems (2)
PATCH v10 1/1 gpio: virtuser: new virtual testing driver for the GPIO API
From: Bartosz Golaszewski <[email protected]>
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.
---
v9 -> v10:
- fix potential buffer overflow in gpio_virtuser_consumer_write() Link to v9: https://lore.kernel.org/lkml/[email protected]/
v8 -> v9:
- use debugfs instead of sysfs for more flexibility on attribute formats
- move the module back to drivers/gpio/
- extend Kconfig description
- minor tweaks and improvements across the driver
Link to v8: https://lore.kernel.org/linux-doc/[email protected]/
v7 -> v8:
- move the driver to drivers/misc/ as it's not a GPIO provider and so its place is not in drivers/gpio/
- rework the data structures to make them more compact using unions
- use correct string helpers for given use-cases
- drop dependency on the gpio/driver.h, string.h and kernel.h headers
- add a patch exporting to_ext_attribute() to be used by this driver
- various minor improvements suggested by Andy
Link to v7: https://lore.kernel.org/linux-gpio/[email protected]/
v6 -> v7:
- this is a complete rewrite of the original idea, the entire interface has changed so it warrants a new round of reviews
Link to v6: https://lore.kernel.org/linux-gpio/[email protected]/
v5 -> v6:
- initialize the flags temp variables at declaration and hopefully make Andy happy finally :)
v4 -> v5:
- add the gpio-consumer docs to the admin-guide/gpio/ index (reported by kernel test robot <[email protected]>)
v3 -> v4:
- fix the toggle value assignment
- use guard(mutex)() wherever we can return directly from the subsequent function call
- use skip_spaces() + strim() to avoid having to do a memmove() when stripping strings off whitespaces
- DON'T try to save a couple LOC in ifdefs if that makes them less readable (Andy :) )
v2 -> v3:
- use cleanup.h interfaces
- add some clarifying commets
- more minor code tweaks
RFC -> v2:
- add documentation
- fix various issues pointed out by Andy: use struct_size() where applicable, improve the logic when storing the 'live' property, improve log messages, remove commas in terminators, etc.
.../admin-guide/gpio/gpio-virtuser.rst | 177 ++ Documentation/admin-guide/gpio/index.rst | 1 + drivers/gpio/Kconfig | 12 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-virtuser.c | 1807 +++++++++++++++++ 5 files changed, 1998 insertions(+) create mode 100644 Documentation/admin-guide/gpio/gpio-virtuser.rst create mode 100644 drivers/gpio/gpio-virtuser.c
Documentation/admin-guide/gpio/gpio-virtuser.rst new file +177 -0
@@ -0,0 +1,177 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +Virtual GPIO Consumer +===================== + +The virtual GPIO Consumer module allows users to instantiate virtual devices +that request GPIOs and then control their behavior over debugfs. Virtual +consumer devices can be instantiated from device-tree or over configfs. + +A virtual consumer uses the driver-facing GPIO APIs and allows to cover it with +automated tests driven by user-space. The GPIOs are requested using +``gpiod_get_array()`` and so we support multiple GPIOs per connector ID. + +Creating GPIO consumers +----------------------- + +The gpio-consumer module registers a configfs subsystem called +``'gpio-virtuser'``. For details of the configfs filesystem, please refer to +the configfs documentation. + +The user can create a hierarchy of configfs groups and items as well as modify +values of exposed attributes. Once the consumer is instantiated, this hierarchy +will be translated to appropriate device properties. The general structure is: + +**Group:** ``/config/gpio-virtuser`` + +This is the top directory of the gpio-consumer configfs tree. + +**Group:** ``/config/gpio-consumer/example-name`` + +**Attribute:** ``/config/gpio-consumer/example-name/live`` + +**Attribute:** ``/config/gpio-consumer/example-name/dev_name`` + +This is a directory representing a GPIO consumer device. + +The read-only ``dev_name`` attribute exposes the name of the device as it will +appear in the system on the platform bus. This is useful for locating the +associated debugfs directory under +``/sys/kernel/debug/gpio-virtuser/$dev_name``. + +The ``'live'`` attribute allows to trigger the actual creation of the device +once it's fully configured. The accepted values are: ``'1'`` to enable the +virtual device and ``'0'`` to disable and tear it down. + +Creating GPIO lookup tables +--------------------------- + +Users can create a number of configfs groups under the device group: + +**Group:** ``/config/gpio-consumer/example-name/con_id`` + +The ``'con_id'`` directory represents a single GPIO lookup and its value maps +to the ``'con_id'`` argument of the ``gpiod_get()`` function. For example: +``con_id`` == ``'reset'`` maps to the ``reset-gpios`` device property. + +Users can assign a number of GPIOs to each lookup. Each GPIO is a sub-directory +with a user-defined name under the ``'con_id'`` group. + +**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/key`` + +**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/offset`` + +**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/drive`` + +**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/pull`` + +**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/active_low`` + +**Attribute:** ``/config/gpio-consumer/example-name/con_id/0/transitory`` + +This is a group describing a single GPIO in the ``con_id-gpios`` property. + +For virtual consumers created using configfs we use machine lookup tables so +this group can be considered as a mapping between the filesystem and the fields +of a single entry in ``'struct gpiod_lookup'``. + +The ``'key'`` attribute represents either the name of the chip this GPIO +belongs to or the GPIO line name. This depends on the value of the ``'offset'`` +attribute: if its value is >= 0, then ``'key'`` represents the label of the +chip to lookup while ``'offset'`` represents the offset of the line in that +chip. If ``'offset'`` is < 0, then ``'key'`` represents the name of the line. + +The remaining attributes map to the ``'flags'`` field of the GPIO lookup +struct. The first two take string values as arguments: + +**``'drive'``:** ``'push-pull'``, ``'open-drain'``, ``'open-source'`` +**``'pull'``:** ``'pull-up'``, ``'pull-down'``, ``'pull-disabled'``, ``'as-is'`` + +``'active_low'`` and ``'transitory'`` are boolean attributes. + +Activating GPIO consumers +------------------------- + +Once the confiuration is complete, the ``'live'`` attribute must be set to 1 in +order to instantiate the consumer. It can be set back to 0 to destroy the +virtual device. The module will synchronously wait for the new simulated device +to be successfully probed and if this doesn't happen, writing to ``'live'`` will +result in an error. + +Device-tree +----------- + +Virtual GPIO consumers can also be defined in device-tree. The compatible string +must be: ``"gpio-virtuser"`` with at least one property following the +standardized GPIO pattern. + +An example device-tree code defining a virtual GPIO consumer: + +.. code-block :: none + + gpio-virt-consumer { + compatible = "gpio-virtuser"; + + foo-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, <&gpio1 2 0>; + bar-gpios = <&gpio0 6 0>; + }; + +Controlling virtual GPIO consumers +---------------------------------- + +Once active, the device will export debugfs attributes for controlling GPIO +arrays as well as each requested GPIO line separately. Let's consider the +following device property: ``foo-gpios = <&gpio0 0 0>, <&gpio0 4 0>;``. + +The following debugfs attribute groups will be created: + +**Group:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/`` + +This is the group that will contain the attributes for the entire GPIO array. + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values`` + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values_atomic`` + +Both attributes allow to read and set arrays of GPIO values. User must pass +exactly the number of values that the array contains in the form of a string +containing zeroes and ones representing inactive and active GPIO states +respectively. In this example: ``echo 11 > values``. + +The ``values_atomic`` attribute works the same as ``values`` but the kernel +will execute the GPIO driver callbacks in interrupt context. + +**Group:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/`` + +This is a group that represents a single GPIO with ``$index`` being its offset +in the array. + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/consumer`` + +Allows to set and read the consumer label of the GPIO line. + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/debounce`` + +Allows to set and read the debounce period of the GPIO line. + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction`` + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction_atomic`` + +These two attributes allow to set the direction of the GPIO line. They accept +"input" and "output" as values. The atomic variant executes the driver callback +in interrupt context. + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/interrupts`` + +If the line is requested in input mode, writing ``1`` to this attribute will +make the module listen for edge interrupts on the GPIO. Writing ``0`` disables +the monitoring. Reading this attribute returns the current number of registered +interrupts (both edges). + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value`` + +**Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value_atomic`` + +Both attributes allow to read and set values of individual requested GPIO lines. +They accept the following values: ``1`` and ``0``.
Documentation/admin-guide/gpio/index.rst +1 -0
@@ -10,6 +10,7 @@ GPIO Character Device Userspace API <../../userspace-api/gpio/chardev> gpio-aggregator gpio-sim + gpio-virtuser Obsolete APIs <obsolete> .. only:: subproject and html
drivers/gpio/Kconfig +12 -0
@@ -1908,6 +1908,18 @@ config GPIO_SLOPPY_LOGIC_ANALYZER If this driver is built as a module it will be called 'gpio-sloppy-logic-analyzer'. +config GPIO_VIRTUSER + tristate "GPIO Virtual User Testing Module" + select DEBUG_FS + select CONFIGFS_FS + select IRQ_WORK + help + Say Y here to enable the configurable, configfs-based virtual GPIO + consumer testing driver. + + This driver is aimed as a helper in spotting any regressions in + hot-unplug handling in GPIOLIB. + endmenu endif
drivers/gpio/Makefile +1 -0
@@ -182,6 +182,7 @@ obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o +obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
drivers/gpio/gpio-virtuser.c new file +1807 -0
1,807 lines not on this page · raw message
Signature · 1 line
2.43.0
Bartosz Golaszewski
AppliedFrom: Bartosz Golaszewski <[email protected]>
Quoted 9 lines · Bartosz Golaszewski
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.
[...]
Applied, thanks!
[1/1] gpio: virtuser: new virtual testing driver for the GPIO API
commit: 91581c4b3f29e2e22aeb1a62e842d529ca638b2d
Best regards,
Signature · 1 line
Bartosz Golaszewski <[email protected]>