Commit Graph

33 Commits

Author SHA1 Message Date
Bartosz Golaszewski
9d7697fabb gpio: shared: fix lockdep false positive by removing unneeded lock
By the time gpio_device_teardown_shared() is called, the parent device
is gone from the global list of GPIO devices and all outstanding SRCU
read-side critical sections have completed. That means that no
concurrent gpio_find_and_request() can call
gpio_shared_add_proxy_lookup() for this device at this time. There's
also no risk of the parent device being re-bound to the driver before
the unbinding completes (including the child devices).

Lockdep produces a false-positive report about a possible circular
dependency as it doesn't know the ordering guarantee. Not taking the
ref->lock in gpio_device_teardown_shared() silences it and is safe to do.

Cc: stable@vger.kernel.org
Fixes: ea513dd3c0 ("gpio: shared: make locking more fine-grained")
Reviewed-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260522-gpio-shared-deadlock-v1-2-76bca088f8c0@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-05-28 15:23:40 +02:00
Bartosz Golaszewski
a1b8366073 gpio: shared: fix deadlock on shared proxy's parent removal
Commit 710abda580 ("gpio: shared: call gpio_chip::of_xlate() if set")
used the mutex embedded in struct gpio_shared_entry to protect the
offset field which now can be modified after assignment. The critical
section however is too wide and introduced a potential deadlock on the
removal of the shared GPIO proxy's parent.

Make the critical section shorter - only protect the offset when it's
being read.

While at it: mention the fact that the entry lock is now also used to
protect against concurrent access to the offset field in the structure's
documentation.

Cc: stable@vger.kernel.org
Fixes: 710abda580 ("gpio: shared: call gpio_chip::of_xlate() if set")
Reviewed-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260522-gpio-shared-deadlock-v1-1-76bca088f8c0@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-05-28 15:23:39 +02:00
Bartosz Golaszewski
310a4a9cbb gpio: shared: shorten the critical section in gpiochip_setup_shared()
Commit 710abda580 ("gpio: shared: call gpio_chip::of_xlate() if set")
introduced a critical section around the adjustmenet of entry->offset.
However this may cause a deadlock if we create the auxiliary shared
proxy devices with this lock taken. We only need to protect
entry->offset while it's read/written so shorten the critical section
and release the lock before creating the proxy device as the field in
question is no longer accessed at this point.

Fixes: 710abda580 ("gpio: shared: call gpio_chip::of_xlate() if set")
Reported-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://patch.msgid.link/20260325-gpio-shared-deadlock-v1-1-e4e7a5319e95@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-03-30 09:51:15 +02:00
Bartosz Golaszewski
ec42a3a90a gpio: shared: handle pins shared by child nodes of devices
Shared GPIOs may be assigned to child nodes of device nodes which don't
themselves bind to any struct device. We need to pass the firmware node
that is the actual consumer to gpiolib-shared and compare against it
instead of unconditionally using the fwnode of the consumer device.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Closes: https://lore.kernel.org/all/921ba8ce-b18e-4a99-966d-c763d22081e2@nvidia.com/
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://patch.msgid.link/20260318-gpio-shared-xlate-v2-2-0ce34c707e81@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-03-23 09:54:24 +01:00
Bartosz Golaszewski
710abda580 gpio: shared: call gpio_chip::of_xlate() if set
OF-based GPIO controller drivers may provide a translation function that
calculates the real chip offset from whatever devicetree sources
provide. We need to take this into account in the shared GPIO management
and call of_xlate() if it's provided and adjust the entry->offset we
initially set when scanning the tree.

To that end: modify the shared GPIO API to take the GPIO chip as
argument on setup (to avoid having to rcu_dereference() it from the GPIO
device) and protect the access to entry->offset with the existing lock.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Closes: https://lore.kernel.org/all/921ba8ce-b18e-4a99-966d-c763d22081e2@nvidia.com/
Reviewed-by: Linus Walleij <linusw@kernel.org>
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://patch.msgid.link/20260318-gpio-shared-xlate-v2-1-0ce34c707e81@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-03-23 09:54:24 +01:00
Daniel J Blueman
32e0a7ad9c gpio: shared: fix memory leaks
On a Snapdragon X1 Elite laptop (Lenovo Yoga Slim 7x), kmemleak reports
three sets of:

unreferenced object 0xffff00080187f400 (size 1024):
  comm "swapper/0", pid 1, jiffies 4294667327
  hex dump (first 32 bytes):
    58 bd 70 01 08 00 ff ff 58 bd 70 01 08 00 ff ff  X.p.....X.p.....
    00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00  ................
  backtrace (crc 1665d1f8):
    kmemleak_alloc+0xf4/0x12c
    __kmalloc_cache_noprof+0x370/0x49c
    gpio_shared_make_ref+0x70/0x16c
    gpio_shared_of_traverse+0x4e8/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_init+0x34/0x1c4
    do_one_initcall+0x50/0x280
    kernel_init_freeable+0x290/0x33c
    kernel_init+0x28/0x14c
    ret_from_fork+0x10/0x20

unreferenced object 0xffff00080170c140 (size 8):
  comm "swapper/0", pid 1, jiffies 4294667327
  hex dump (first 8 bytes):
    72 65 73 65 74 00 00 00                          reset...
  backtrace (crc fc24536):
    kmemleak_alloc+0xf4/0x12c
    __kmalloc_node_track_caller_noprof+0x3c4/0x584
    kstrdup+0x4c/0xcc
    gpio_shared_make_ref+0x8c/0x16c
    gpio_shared_of_traverse+0x4e8/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_of_traverse+0x200/0x5f4
    gpio_shared_init+0x34/0x1c4
    do_one_initcall+0x50/0x280
    kernel_init_freeable+0x290/0x33c
    kernel_init+0x28/0x14c
    ret_from_fork+0x10/0x20

Fix this by decrementing the reference count of each list entry rather than
only the first.

Fix verified on the same laptop.

Fixes: a060b8c511 gpiolib: implement low-level, shared GPIO support
Signed-off-by: Daniel J Blueman <daniel@quora.org>
Link: https://patch.msgid.link/20260220093452.101655-1-daniel@quora.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-02-23 11:01:13 +01:00
Linus Torvalds
32a92f8c89 Convert more 'alloc_obj' cases to default GFP_KERNEL arguments
This converts some of the visually simpler cases that have been split
over multiple lines.  I only did the ones that are easy to verify the
resulting diff by having just that final GFP_KERNEL argument on the next
line.

Somebody should probably do a proper coccinelle script for this, but for
me the trivial script actually resulted in an assertion failure in the
middle of the script.  I probably had made it a bit _too_ trivial.

So after fighting that far a while I decided to just do some of the
syntactically simpler cases with variations of the previous 'sed'
scripts.

The more syntactically complex multi-line cases would mostly really want
whitespace cleanup anyway.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 20:03:00 -08:00
Linus Torvalds
323bbfcf1e Convert 'alloc_flex' family to use the new default GFP_KERNEL argument
This is the exact same thing as the 'alloc_obj()' version, only much
smaller because there are a lot fewer users of the *alloc_flex()
interface.

As with alloc_obj() version, this was done entirely with mindless brute
force, using the same script, except using 'flex' in the pattern rather
than 'objs*'.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 17:09:51 -08:00
Linus Torvalds
bf4afc53b7 Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
This was done entirely with mindless brute force, using

    git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
        xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'

to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.

Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.

For the same reason the 'flex' versions will be done as a separate
conversion.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 17:09:51 -08:00
Kees Cook
69050f8d6d treewide: Replace kmalloc with kmalloc_obj for non-scalar types
This is the result of running the Coccinelle script from
scripts/coccinelle/api/kmalloc_objs.cocci. The script is designed to
avoid scalar types (which need careful case-by-case checking), and
instead replace kmalloc-family calls that allocate struct or union
object instances:

Single allocations:	kmalloc(sizeof(TYPE), ...)
are replaced with:	kmalloc_obj(TYPE, ...)

Array allocations:	kmalloc_array(COUNT, sizeof(TYPE), ...)
are replaced with:	kmalloc_objs(TYPE, COUNT, ...)

Flex array allocations:	kmalloc(struct_size(PTR, FAM, COUNT), ...)
are replaced with:	kmalloc_flex(*PTR, FAM, COUNT, ...)

(where TYPE may also be *VAR)

The resulting allocations no longer return "void *", instead returning
"TYPE *".

Signed-off-by: Kees Cook <kees@kernel.org>
2026-02-21 01:02:28 -08:00
Linus Torvalds
d701782152 Merge tag 'gpio-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
 "There are two new drivers and some changes to GPIO core but mostly
  just GPIO driver updates across a wide array of files, adding support
  for new models as well as various refactoring changes. Nothing
  controversial and everything has spent a good measure of time in
  linux-next.

  GPIOLIB core:
   - shrink the GPIO bus driver stub code
   - rework software node support for "undefined" software nodes
   - provide and use devm_fwnode_gpiod_get_optional()
   - only compile the OF quirk for MT2701 when needed

  New drivers:
   - add the GPIO driver for ROHM bd72720
   - add the gpio-line-mux driver providing 1-to-many mapping for a
     single real GPIO

  Driver changes:
   - refactor gpio-pca9570: use lock guard, add missing headers, use
     devres consistently
   - add support for a new model (G7 Aspeed sgpiom) to the aspeed-sgpio
     driver along with some prerequisite refactoring
   - use device_get_match_data() where applicable and save some lines
   - add support for more models to gpio-cadence
   - add the compatible property to reset-gpio and use it in shared GPIO
     management
   - drop unnecessary use of irqd_get_trigger_type() in gpio-max77759
   - add support for a new variant to gpio-pca953x
   - extend build coverage with COMPILE_TEST for more drivers
   - constify configfs structures in gpio-sim and gpio-virtuser
   - add support for the K3 SoC to gpio-spacemit
   - implement the missing .get_direction() callback in gpio-max77620
   - add support for Tegra264 to gpio-tegra186
   - drop unneeded MODULE_ALIAS() from gpio-menz127

  DT bindings:
   - document support for the opencores GPIO controller in gpio-mmio
   - document new variants for gpio-pca953x

  Documentation:
   - extensively describe interrupt source detection for gpio-pca953x
     and add more models to the list of supported variants"

* tag 'gpio-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (59 commits)
  gpio: tegra186: Add support for Tegra264
  dt-bindings: gpio: Add Tegra264 support
  gpio: spacemit-k1: Use PDR for pin direction, not SDR/CDR
  gpio: max77620: Implement .get_direction() callback
  gpio: aspeed-sgpio: Support G7 Aspeed sgpiom controller
  dt-bindings: gpio: aspeed,sgpio: Support ast2700
  gpio: aspeed-sgpio: Convert IRQ functions to use llops callbacks
  gpio: aspeed-sgpio: Create llops to handle hardware access
  gpio: aspeed-sgpio: Remove unused bank name field
  gpio: aspeed-sgpio: Change the macro to support deferred probe
  regulator: bd71815: switch to devm_fwnode_gpiod_get_optional
  gpiolib: introduce devm_fwnode_gpiod_get_optional() wrapper
  gpio: mmio: Add compatible for opencores GPIO
  dt-bindings: gpio-mmio: Correct opencores GPIO
  gpio: pca9570: use lock guards
  gpio: pca9570: Don't use "proxy" headers
  gpio: pca9570: Use devm_mutex_init() for mutex initialization
  MAINTAINERS: Add ROHM BD72720 PMIC
  power: supply: bd71828-power: Support ROHM BD72720
  power: supply: bd71828: Support wider register addresses
  ...
2026-02-11 10:53:39 -08:00
Bartosz Golaszewski
4918cc0513 gpio: shared: propagate configuration to pinctrl
Just toggling the descriptor's "requested" flag is not enough. We need
to properly request it in order to potentially propagate any
configuration to pinctrl via the .request() callback.

We must not take the reference to the device at this point (the device
is not ready but we're also requesting the device's own descriptor) so
make the _commit() variants of request and free functions available to
GPIO core in order to use them instead of their regular counterparts.

This fixes an audio issue reported on one of the Qualcomm platforms.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reviewed-by: Linus Walleij <linusw@kernel.org>
Tested-by: Ravi Hothi <ravi.hothi@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260120154913.61991-1-bartosz.golaszewski@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-21 14:06:17 +01:00
Bartosz Golaszewski
568ea51e61 gpio: shared: use device_is_compatible() for reset-gpio
reset-gpio devices now can be identified with device_is_compatible() so
use it instead of checking the device name string.

Reviewed-by: Linus Walleij <linusw@kernel.org>
Link: https://lore.kernel.org/r/20260112093651.23639-1-bartosz.golaszewski@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-13 10:32:17 +01:00
Bartosz Golaszewski
d578b31856 gpio: shared: fix a false-positive sharing detection with reset-gpios
After scanning the devicetree, we remove all entries that have only one
reference, while creating GPIO shared proxies for the remaining, shared
entries. However: for the reset-gpio corner-case, we will have two
references for a "reset-gpios" pin that's not really shared. In this
case one will come from the actual consumer fwnode and the other from
the potential auxiliary reset-gpio device. This causes the GPIO core to
create unnecessary GPIO shared proxy devices for pins that are not
really shared.

Add a function that can detect this situation and remove entries that
have exactly two references but one of them is a reset-gpio.

Fixes: 7b78b26757 ("gpio: shared: handle the reset-gpios corner case")
Link: https://lore.kernel.org/r/20260108-gpio-shared-false-positive-v1-1-5dbf8d1b2f7d@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-09 09:56:46 +01:00
Bartosz Golaszewski
a80208072d gpio: shared: don't allocate the lookup table until we really need it
We allocate memory for the GPIO lookup table at the top of
gpio_shared_add_proxy_lookup() but we don't use it until the very end.
Depending on the timing, we may return earlier. Move the allocation
towards the end.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20260106-gpio-shared-fixes-v2-3-c7091d2f7581@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-07 09:31:14 +01:00
Bartosz Golaszewski
476e44d06f gpio: shared: fix a race condition
When matching the reset-gpio reference with the actual firmware node
consuming the GPIO, we also need to lock the structure associated with
the latter as it can change while we're doing it.

Due to triggering lockdep false-positives, we need to use a per-reference
lockdep class but accidentally, this also allows us to remove the
previous lockdep workaround for cleaner code.

Fixes: 49416483a9 ("gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib")
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Closes: https://lore.kernel.org/all/00107523-7737-4b92-a785-14ce4e93b8cb@samsung.com/
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20260106-gpio-shared-fixes-v2-2-c7091d2f7581@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-07 09:31:14 +01:00
Bartosz Golaszewski
0fe5063179 gpio: shared: assign the correct firmware node for reset-gpio use-case
When we defer probe due to unlucky timing of adding the lookup table, we
assign the matching firmware node to the shared reference for the future
probing. However, the fwnode we assign is wrong so fix it and assign the
one associated with the reset-gpio device.

Fixes: 49416483a9 ("gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib")
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Closes: https://lore.kernel.org/all/00107523-7737-4b92-a785-14ce4e93b8cb@samsung.com/
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20260106-gpio-shared-fixes-v2-1-c7091d2f7581@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-07 09:31:14 +01:00
Bartosz Golaszewski
49416483a9 gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib
We currently support sharing GPIOs between multiple devices whose drivers
use either the GPIOLIB API *OR* the reset control API but not both at
the same time.

There's an unlikely corner-case where a reset-gpios pin can be shared by
one driver using the GPIOLIB API and a second using the reset API. This
will currently not work as the reset-gpio consumers are not described in
firmware at the time of scanning so the shared GPIO just chooses one of
the proxies created for the consumers when the reset-gpio driver performs
the lookup. This can of course conflict in the case described above.

In order to fix it: if we deal with the "reset-gpios" pin that's shared
acconding to the firmware node setup, create a proxy for each described
consumer as well as another one for the potential reset-gpio device. To
that end: rework the matching to take this into account.

Fixes: 7b78b26757 ("gpio: shared: handle the reset-gpios corner case")
Link: https://lore.kernel.org/r/20251222-gpio-shared-reset-gpio-proxy-v1-3-8d4bba7d8c14@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-02 10:34:32 +01:00
Bartosz Golaszewski
cb0451e33b gpio: shared: verify con_id when adding proxy lookup
When matching the firmware node with the potential consumer, we
currently omit the con_id string. This can lead to false positives in
the unlikely case of the consumer having been assigned more than one
shared GPIO. Check the connector ID before proceeding.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Link: https://lore.kernel.org/r/20251222-gpio-shared-reset-gpio-proxy-v1-2-8d4bba7d8c14@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-01-02 10:34:31 +01:00
Bartosz Golaszewski
ea513dd3c0 gpio: shared: make locking more fine-grained
The global gpio_shared_lock has caused some issues when recursively
removing GPIO shared proxies. The thing is: we don't really need it.
Once created from an init-call, the shared GPIO data structures are
never removed, there's no need to protect the linked lists of entries
and references. All we need to protect is the shared GPIO descriptor
(which we already do with a per-entry mutex) and the auxiliary device
data in struct gpio_shared_ref.

Remove the global gpio_shared_lock and use a per-reference mutex to
protect shared references when adding/removing the auxiliary devices and
their GPIO lookup entries.

Link: https://lore.kernel.org/r/20251206-gpio-shared-teardown-fixes-v1-4-35ac458cfce1@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2025-12-09 07:16:45 +01:00
Bartosz Golaszewski
d382c765d0 gpio: shared: fix auxiliary device cleanup order
Dropping the last reference to the internal struct device should be the
last thing we do so delete the device first and then uninit it which
also involves the final put_device().

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Link: https://lore.kernel.org/r/20251206-gpio-shared-teardown-fixes-v1-3-35ac458cfce1@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2025-12-09 07:16:45 +01:00
Bartosz Golaszewski
c904a0d852 gpio: shared: check if a reference is populated before cleaning its resources
It's possible that not all proxy entries will be set up when the device
gets removed so check if they are before trying to dereference members
which are still NULL. This can happen if some consumers never requested
their shared GPIOs.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Link: https://lore.kernel.org/r/20251206-gpio-shared-teardown-fixes-v1-2-35ac458cfce1@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2025-12-09 07:16:45 +01:00
Bartosz Golaszewski
e2c4175b8d gpio: shared: fix NULL-pointer dereference in teardown path
We need to actually store the address of the GPIO lookup table in the
reference struct before we try to free it or - worse - dereference its
members.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Link: https://lore.kernel.org/r/20251206-gpio-shared-teardown-fixes-v1-1-35ac458cfce1@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2025-12-09 07:16:45 +01:00
Bartosz Golaszewski
9e7a40a284 gpio: shared: ignore disabled nodes when traversing the device-tree
Don't consider disabled devices when traversing the device-tree looking
for shared GPIOs. Even if they do share a phandle to a pin, they can
never be instantiated and request it.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Link: https://lore.kernel.org/r/20251203092309.34737-1-bartosz.golaszewski@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2025-12-09 07:14:53 +01:00
Bartosz Golaszewski
54a2df5afa gpio: shared: fix a deadlock
It's possible that the auxiliary proxy device we add when setting up the
GPIO controller exposing shared pins, will get matched and probed
immediately. The gpio-proxy-driver will then retrieve the shared
descriptor structure. That will cause a recursive mutex locking and
a deadlock because we're already holding the gpio_shared_lock in
gpio_device_setup_shared() and try to take it again in
devm_gpiod_shared_get() like this:

[    4.298346] gpiolib_shared: GPIO 130 owned by f100000.pinctrl is shared by multiple consumers
[    4.307157] gpiolib_shared: Setting up a shared GPIO entry for speaker@0,3
[    4.314604]
[    4.316146] ============================================
[    4.321600] WARNING: possible recursive locking detected
[    4.327054] 6.18.0-rc7-next-20251125-g3f300d0674f6-dirty #3887 Not tainted
[    4.334115] --------------------------------------------
[    4.339566] kworker/u32:3/71 is trying to acquire lock:
[    4.344931] ffffda019ba71850 (gpio_shared_lock){+.+.}-{4:4}, at: devm_gpiod_shared_get+0x34/0x2e0
[    4.354057]
[    4.354057] but task is already holding lock:
[    4.360041] ffffda019ba71850 (gpio_shared_lock){+.+.}-{4:4}, at: gpio_device_setup_shared+0x30/0x268
[    4.369421]
[    4.369421] other info that might help us debug this:
[    4.376126]  Possible unsafe locking scenario:
[    4.376126]
[    4.382198]        CPU0
[    4.384711]        ----
[    4.387223]   lock(gpio_shared_lock);
[    4.390992]   lock(gpio_shared_lock);
[    4.394761]
[    4.394761]  *** DEADLOCK ***
[    4.394761]
[    4.400832]  May be due to missing lock nesting notation
[    4.400832]
[    4.407802] 5 locks held by kworker/u32:3/71:
[    4.412279]  #0: ffff000080020948 ((wq_completion)events_unbound){+.+.}-{0:0}, at: process_one_work+0x194/0x64c
[    4.422650]  #1: ffff800080963d60 (deferred_probe_work){+.+.}-{0:0}, at: process_one_work+0x1bc/0x64c
[    4.432117]  #2: ffff00008165c8f8 (&dev->mutex){....}-{4:4}, at: __device_attach+0x3c/0x198
[    4.440700]  #3: ffffda019ba71850 (gpio_shared_lock){+.+.}-{4:4}, at: gpio_device_setup_shared+0x30/0x268
[    4.450523]  #4: ffff0000810fe918 (&dev->mutex){....}-{4:4}, at: __device_attach+0x3c/0x198
[    4.459103]
[    4.459103] stack backtrace:
[    4.463581] CPU: 6 UID: 0 PID: 71 Comm: kworker/u32:3 Not tainted 6.18.0-rc7-next-20251125-g3f300d0674f6-dirty #3887 PREEMPT
[    4.463589] Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT)
[    4.463593] Workqueue: events_unbound deferred_probe_work_func
[    4.463602] Call trace:
[    4.463604]  show_stack+0x18/0x24 (C)
[    4.463617]  dump_stack_lvl+0x70/0x98
[    4.463627]  dump_stack+0x18/0x24
[    4.463636]  print_deadlock_bug+0x224/0x238
[    4.463643]  __lock_acquire+0xe4c/0x15f0
[    4.463648]  lock_acquire+0x1cc/0x344
[    4.463653]  __mutex_lock+0xb8/0x840
[    4.463661]  mutex_lock_nested+0x24/0x30
[    4.463667]  devm_gpiod_shared_get+0x34/0x2e0
[    4.463674]  gpio_shared_proxy_probe+0x18/0x138
[    4.463682]  auxiliary_bus_probe+0x40/0x78
[    4.463688]  really_probe+0xbc/0x2c0
[    4.463694]  __driver_probe_device+0x78/0x120
[    4.463701]  driver_probe_device+0x3c/0x160
[    4.463708]  __device_attach_driver+0xb8/0x140
[    4.463716]  bus_for_each_drv+0x88/0xe8
[    4.463723]  __device_attach+0xa0/0x198
[    4.463729]  device_initial_probe+0x14/0x20
[    4.463737]  bus_probe_device+0xb4/0xc0
[    4.463743]  device_add+0x578/0x76c
[    4.463747]  __auxiliary_device_add+0x40/0xac
[    4.463752]  gpio_device_setup_shared+0x1f8/0x268
[    4.463758]  gpiochip_add_data_with_key+0xdac/0x10ac
[    4.463763]  devm_gpiochip_add_data_with_key+0x30/0x80
[    4.463768]  msm_pinctrl_probe+0x4b0/0x5e0
[    4.463779]  sm8250_pinctrl_probe+0x18/0x40
[    4.463784]  platform_probe+0x5c/0xa4
[    4.463793]  really_probe+0xbc/0x2c0
[    4.463800]  __driver_probe_device+0x78/0x120
[    4.463807]  driver_probe_device+0x3c/0x160
[    4.463814]  __device_attach_driver+0xb8/0x140
[    4.463821]  bus_for_each_drv+0x88/0xe8
[    4.463827]  __device_attach+0xa0/0x198
[    4.463834]  device_initial_probe+0x14/0x20
[    4.463841]  bus_probe_device+0xb4/0xc0
[    4.463847]  deferred_probe_work_func+0x90/0xcc
[    4.463854]  process_one_work+0x214/0x64c
[    4.463860]  worker_thread+0x1bc/0x360
[    4.463866]  kthread+0x14c/0x220
[    4.463871]  ret_from_fork+0x10/0x20
[   77.265041] random: crng init done

Fortunately, at the time of creating of the auxiliary device, we already
know the correct entry so let's store it as the device's platform data.
We don't need to hold gpio_shared_lock in devm_gpiod_shared_get() as
we're not removing the entry or traversing the list anymore but we still
need to protect it from concurrent modification of its fields so add a
more fine-grained mutex.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Closes: https://lore.kernel.org/all/fimuvblfy2cmn7o4wzcxjzrux5mwhvlvyxfsgeqs6ore2xg75i@ax46d3sfmdux/
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20251128-gpio-shared-deadlock-v2-1-9f3ae8ddcb09@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-28 09:48:28 +01:00
Bartosz Golaszewski
114e594e6c gpio: shared: ignore GPIO hogs when traversing the device tree
GPIO hogs have a "gpios" property but it's not a phandle to a remote
node - it references the parent GPIO controller. We must not try to
parse it as a phandle.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Cosmin Tanislav <demonsingur@gmail.com>
Closes: https://lore.kernel.org/all/2d96e464-e17c-4ff5-9a08-b215b77da04f@gmail.com/
Link: https://lore.kernel.org/r/20251126-gpio-shared-fixes-v1-2-18309c0e87b5@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-28 09:29:14 +01:00
Bartosz Golaszewski
cfab6dc070 gpio: shared: ignore special __symbols__ node when traversing device tree
The __symbols__ node is a special, internal node and its properties must
not be considered when scanning the device-tree for shared GPIOs.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Closes: https://lore.kernel.org/all/0829a21c-f97d-41b6-90bc-2acaec42caab@nvidia.com/
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://lore.kernel.org/r/20251126-gpio-shared-fixes-v1-1-18309c0e87b5@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-28 09:29:14 +01:00
Bartosz Golaszewski
7b78b26757 gpio: shared: handle the reset-gpios corner case
There's an unexpected interaction between the reset-gpio driver and the
shared GPIO support. The reset-gpio device is an auxiliary device that's
created dynamically and fulfills a similar role to the gpio-shared-proxy
driver but is limited in scope to just supporting the "reset-gpios"
property.

The shared GPIO core code does not take into account that the machine
lookup entry we create when scanning the device-tree must connect the
reset-gpio device - that is the actual consumer of the GPIO and not the
consumer defined on the device tree, which in turn consumes the shared
reset control exposed by the reset-gpio device - to the GPIO controller.

We also must not skip the gpio-shared-proxy driver as it's possible that
a shared GPIO may be used by one consumer as a reset-gpios going through
the reset-gpio device and another that uses GPIOLIB.

We need to make it a special case handled in gpiolib-shared.c. Add a new
function - gpio_shared_dev_is_reset_gpio() - whose role it is to verify
if a non-matching consumer of a shared pin is a reset-gpio device and
make sure it's the right one for this pin. To that end make sure that
its parent is the GPIO controller in question and that the fwnode we
identified as sharing the pin references that controller via the
"reset-gpios" property.

Only include that code if the reset-gpio driver is enabled.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Val Packett <val@packett.cool>
Closes: https://lore.kernel.org/all/3b5d9df5-934d-4591-8827-6c9573a6f7ba@packett.cool/
Tested-by: Val Packett <val@packett.cool>
Tested-by: Abel Vesa <abel.vesa@linaro.org>
Link: https://lore.kernel.org/r/20251125-gpiolib-shared-reset-gpio-fix-v2-1-4eb6fa41f1dd@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-27 09:21:12 +01:00
Bartosz Golaszewski
8ad236f8a4 gpio: shared: extend the ifdef guard to gpio_shared_find_entry()
While this function is supposed to be used by all scanning functions, so
far we only have a single one for OF trees. Once we add support for ACPI
and software nodes, we'll drop the CONFIG_OF guard around this routine
but in order to avoid build warnings, let's extend it to cover it in the
meantime.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202511180232.EItKeYjY-lkp@intel.com/
Link: https://lore.kernel.org/r/20251118-gpiolib-shared-of-guard-v1-1-e4ef149a2e0b@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-19 08:33:55 +01:00
Bartosz Golaszewski
01be904798 gpio: shared: fix a NULL-pointer dereference
The fact that CONFIG_OF is enabled does not mean that the device tree is
populated and that of_root points to a valid device node. Check if it's
NULL before trying to traverse the tree.

Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Mark Brown <broonie@kernel.org>
Closes: https://lore.kernel.org/all/dbe20642-9662-40af-a593-c1263baea73b@sirena.org.uk/
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20251118200459.13969-1-brgl@bgdev.pl
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-19 08:32:38 +01:00
Bartosz Golaszewski
82e71fe436 Merge tag 'gpio/shared-gpios-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git into gpio/for-next
Immutable branch between the GPIO, ASoC and regulator trees for v6.19-rc1

Add better support for GPIOs shared by multiple consumers.
2025-11-17 10:37:37 +01:00
Bartosz Golaszewski
eb374f764a gpio: provide gpiod_is_shared()
Provide an interface allowing consumers to check if a GPIO descriptor
represents a GPIO that can potentially be shared by multiple consumers
at the same time. This is exposed to allow subsystems that already
work around the limitations of the current non-exclusive GPIO handling
in some ways, to gradually convert to relying on the new shared GPIO
feature of GPIOLIB.

Extend the gpiolib-shared module to mark the GPIO shared proxy
descriptors with a flag checked by the new interface.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20251112-gpio-shared-v4-6-b51f97b1abd8@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-17 10:16:51 +01:00
Bartosz Golaszewski
a060b8c511 gpiolib: implement low-level, shared GPIO support
This module scans the device tree (for now only OF nodes are supported
but care is taken to make other fwnode implementations easy to
integrate) and determines which GPIO lines are shared by multiple users.
It stores that information in memory. When the GPIO chip exposing shared
lines is registered, the shared GPIO descriptors it exposes are marked
as shared and virtual "proxy" devices that mediate access to the shared
lines are created. When a consumer of a shared GPIO looks it up, its
fwnode lookup is redirected to a just-in-time machine lookup that points
to this proxy device.

This code can be compiled out on platforms which don't use shared GPIOs.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20251112-gpio-shared-v4-3-b51f97b1abd8@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
2025-11-17 10:16:51 +01:00