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: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/gpio/gpiolib-shared.c | 182 ++++++++++++++++++++++++++++++------------
1 file changed, 129 insertions(+), 53 deletions(-)
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index f589109590c7c6bc9c0c1828ea15ab9003846523..baf7e07a3bb887dab8155078666a15779e304409 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -76,6 +76,56 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node,
return NULL;
}
+static struct gpio_shared_ref *gpio_shared_make_ref(struct fwnode_handle *fwnode,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ char *con_id_cpy __free(kfree) = NULL;
+
+ struct gpio_shared_ref *ref __free(kfree) = kzalloc(sizeof(*ref), GFP_KERNEL);
+ if (!ref)
+ return NULL;
+
+ if (con_id) {
+ con_id_cpy = kstrdup(con_id, GFP_KERNEL);
+ if (!con_id_cpy)
+ return NULL;
+ }
+
+ ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL);
+ if (ref->dev_id < 0)
+ return NULL;
+
+ ref->flags = flags;
+ ref->con_id = no_free_ptr(con_id_cpy);
+ ref->fwnode = fwnode;
+ mutex_init(&ref->lock);
+
+ return no_free_ptr(ref);
+}
+
+static int gpio_shared_setup_reset_proxy(struct gpio_shared_entry *entry,
+ enum gpiod_flags flags)
+{
+ struct gpio_shared_ref *ref;
+
+ list_for_each_entry(ref, &entry->refs, list) {
+ if (!ref->fwnode && ref->con_id && strcmp(ref->con_id, "reset") == 0)
+ return 0;
+ }
+
+ ref = gpio_shared_make_ref(NULL, "reset", flags);
+ if (!ref)
+ return -ENOMEM;
+
+ list_add_tail(&ref->list, &entry->refs);
+
+ pr_debug("Created a secondary shared GPIO reference for potential reset-gpio device for GPIO %u at %s\n",
+ entry->offset, fwnode_get_name(entry->fwnode));
+
+ return 0;
+}
+
/* Handle all special nodes that we should ignore. */
static bool gpio_shared_of_node_ignore(struct device_node *node)
{
@@ -106,6 +156,7 @@ static int gpio_shared_of_traverse(struct device_node *curr)
size_t con_id_len, suffix_len;
struct fwnode_handle *fwnode;
struct of_phandle_args args;
+ struct gpio_shared_ref *ref;
struct property *prop;
unsigned int offset;
const char *suffix;
@@ -138,6 +189,7 @@ static int gpio_shared_of_traverse(struct device_node *curr)
for (i = 0; i < count; i++) {
struct device_node *np __free(device_node) = NULL;
+ char *con_id __free(kfree) = NULL;
ret = of_parse_phandle_with_args(curr, prop->name,
"#gpio-cells", i,
@@ -182,15 +234,6 @@ static int gpio_shared_of_traverse(struct device_node *curr)
list_add_tail(&entry->list, &gpio_shared_list);
}
- struct gpio_shared_ref *ref __free(kfree) =
- kzalloc(sizeof(*ref), GFP_KERNEL);
- if (!ref)
- return -ENOMEM;
-
- ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr));
- ref->flags = args.args[1];
- mutex_init(&ref->lock);
-
if (strends(prop->name, "gpios"))
suffix = "-gpios";
else if (strends(prop->name, "gpio"))
@@ -202,27 +245,32 @@ static int gpio_shared_of_traverse(struct device_node *curr)
/* We only set con_id if there's actually one. */
if (strcmp(prop->name, "gpios") && strcmp(prop->name, "gpio")) {
- ref->con_id = kstrdup(prop->name, GFP_KERNEL);
- if (!ref->con_id)
+ con_id = kstrdup(prop->name, GFP_KERNEL);
+ if (!con_id)
return -ENOMEM;
- con_id_len = strlen(ref->con_id);
+ con_id_len = strlen(con_id);
suffix_len = strlen(suffix);
- ref->con_id[con_id_len - suffix_len] = '\0';
+ con_id[con_id_len - suffix_len] = '\0';
}
- ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL);
- if (ref->dev_id < 0) {
- kfree(ref->con_id);
+ ref = gpio_shared_make_ref(fwnode_handle_get(of_fwnode_handle(curr)),
+ con_id, args.args[1]);
+ if (!ref)
return -ENOMEM;
- }
if (!list_empty(&entry->refs))
pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
entry->offset, fwnode_get_name(entry->fwnode));
- list_add_tail(&no_free_ptr(ref)->list, &entry->refs);
+ list_add_tail(&ref->list, &entry->refs);
+
+ if (strcmp(prop->name, "reset-gpios") == 0) {
+ ret = gpio_shared_setup_reset_proxy(entry, args.args[1]);
+ if (ret)
+ return ret;
+ }
}
}
@@ -306,20 +354,16 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
struct fwnode_handle *reset_fwnode = dev_fwnode(consumer);
struct fwnode_reference_args ref_args, aux_args;
struct device *parent = consumer->parent;
+ struct gpio_shared_ref *real_ref;
bool match;
int ret;
+ lockdep_assert_held(&ref->lock);
+
/* The reset-gpio device must have a parent AND a firmware node. */
if (!parent || !reset_fwnode)
return false;
- /*
- * FIXME: use device_is_compatible() once the reset-gpio drivers gains
- * a compatible string which it currently does not have.
- */
- if (!strstarts(dev_name(consumer), "reset.gpio."))
- return false;
-
/*
* Parent of the reset-gpio auxiliary device is the GPIO chip whose
* fwnode we stored in the entry structure.
@@ -328,33 +372,56 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
return false;
/*
- * The device associated with the shared reference's firmware node is
- * the consumer of the reset control exposed by the reset-gpio device.
- * It must have a "reset-gpios" property that's referencing the entry's
- * firmware node.
- *
- * The reference args must agree between the real consumer and the
- * auxiliary reset-gpio device.
+ * Now we need to find the actual pin we want to assign to this
+ * reset-gpio device. To that end: iterate over the list of references
+ * of this entry and see if there's one, whose reset-gpios property's
+ * arguments match the ones from this consumer's node.
*/
- ret = fwnode_property_get_reference_args(ref->fwnode, "reset-gpios",
- NULL, 2, 0, &ref_args);
- if (ret)
- return false;
+ list_for_each_entry(real_ref, &entry->refs, list) {
+ if (!real_ref->fwnode)
+ continue;
+
+ /*
+ * The device associated with the shared reference's firmware
+ * node is the consumer of the reset control exposed by the
+ * reset-gpio device. It must have a "reset-gpios" property
+ * that's referencing the entry's firmware node.
+ *
+ * The reference args must agree between the real consumer and
+ * the auxiliary reset-gpio device.
+ */
+ ret = fwnode_property_get_reference_args(real_ref->fwnode,
+ "reset-gpios",
+ NULL, 2, 0, &ref_args);
+ if (ret)
+ continue;
+
+ ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios",
+ NULL, 2, 0, &aux_args);
+ if (ret) {
+ fwnode_handle_put(ref_args.fwnode);
+ continue;
+ }
+
+ match = ((ref_args.fwnode == entry->fwnode) &&
+ (aux_args.fwnode == entry->fwnode) &&
+ (ref_args.args[0] == aux_args.args[0]));
- ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios",
- NULL, 2, 0, &aux_args);
- if (ret) {
fwnode_handle_put(ref_args.fwnode);
- return false;
- }
+ fwnode_handle_put(aux_args.fwnode);
+
+ if (!match)
+ continue;
- match = ((ref_args.fwnode == entry->fwnode) &&
- (aux_args.fwnode == entry->fwnode) &&
- (ref_args.args[0] == aux_args.args[0]));
+ /*
+ * Reuse the fwnode of the real device, next time we'll use it
+ * in the normal path.
+ */
+ ref->fwnode = fwnode_handle_get(real_ref->fwnode);
+ return true;
+ }
- fwnode_handle_put(ref_args.fwnode);
- fwnode_handle_put(aux_args.fwnode);
- return match;
+ return false;
}
#else
static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
@@ -379,12 +446,20 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
list_for_each_entry(entry, &gpio_shared_list, list) {
list_for_each_entry(ref, &entry->refs, list) {
- if (!device_match_fwnode(consumer, ref->fwnode) &&
- !gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
- continue;
-
guard(mutex)(&ref->lock);
+ /*
+ * FIXME: use device_is_compatible() once the reset-gpio
+ * drivers gains a compatible string which it currently
+ * does not have.
+ */
+ if (!ref->fwnode && strstarts(dev_name(consumer), "reset.gpio.")) {
+ if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
+ continue;
+ } else if (!device_match_fwnode(consumer, ref->fwnode)) {
+ continue;
+ }
+
if ((!con_id && ref->con_id) || (con_id && !ref->con_id) ||
(con_id && ref->con_id && strcmp(con_id, ref->con_id) != 0))
continue;
@@ -471,8 +546,9 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
entry->offset, gpio_device_get_label(gdev));
list_for_each_entry(ref, &entry->refs, list) {
- pr_debug("Setting up a shared GPIO entry for %s\n",
- fwnode_get_name(ref->fwnode));
+ pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n",
+ fwnode_get_name(ref->fwnode) ?: "(no fwnode)",
+ ref->con_id ?: "(none)");
ret = gpio_shared_make_adev(gdev, entry, ref);
if (ret)
--
2.47.3
On Mon, Dec 22, 2025 at 11:01:28AM +0100, Bartosz Golaszewski wrote: > 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. We're seeing futher issues which bisect to this patch in today's next/pending-fixes on db845c: <1>[ 18.348426] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 ... <4>[ 18.799534] Call trace: <4>[ 18.799536] gpiod_direction_output_nonotify+0x14/0x194 (P) <4>[ 18.799541] gpiod_configure_flags+0xb0/0x364 <4>[ 18.799543] gpiod_find_and_request+0x144/0x504 <4>[ 18.832617] gpiod_get_index+0x58/0x90 <4>[ 18.836657] devm_gpiod_get_index+0x20/0xb0 <4>[ 18.841139] devm_gpiod_get_optional+0x18/0x34 <4>[ 18.845881] lt9611_probe+0x130/0x488 [lontium_lt9611] Some prior instances were fixed by: https://lore.kernel.org/all/20260106-gpio-shared-fixes-v2-0-c7091d2f7581@oss.qualcomm.com/ but that's only in next/master, not next/pending-fixes, and in any case the issue also appears in next/master which should include them. git bisect start # status: waiting for both good and bad commits # bad: [fc4e91c639c0af93d63c3d5bc0ee45515dd7504a] Add linux-next specific files for 20260108 git bisect bad fc4e91c639c0af93d63c3d5bc0ee45515dd7504a # status: waiting for good commit(s), bad commit known # bad: [53ebf42e14b480288f52fa86811bf68703fece4e] Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/misc/kernel.git git bisect bad 53ebf42e14b480288f52fa86811bf68703fece4e # status: waiting for good commit(s), bad commit known # good: [f0b9d8eb98dfee8d00419aa07543bdc2c1a44fb1] Merge tag 'nfsd-6.19-3' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux git bisect good f0b9d8eb98dfee8d00419aa07543bdc2c1a44fb1 # good: [a64e2a609fbd406cc424ba13bfcf1941c3b004ea] Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git git bisect good a64e2a609fbd406cc424ba13bfcf1941c3b004ea # good: [1d1d206d257d645c8e3b910d69a1d4b0105de146] Merge branch 'fixes' of git://linuxtv.org/media-ci/media-pending.git git bisect good 1d1d206d257d645c8e3b910d69a1d4b0105de146 # good: [fc6818ad09fcdcd3670755c8dbe9785561f8ef1e] Merge branch 'riscv-dt-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git git bisect good fc6818ad09fcdcd3670755c8dbe9785561f8ef1e # bad: [158eb9119b536341cf39b07c6f9408c15516f77e] Merge branch 'rust-fixes' of https://github.com/Rust-for-Linux/linux.git git bisect bad 158eb9119b536341cf39b07c6f9408c15516f77e # bad: [51018b3e4652074f726aea6cd66e89edcef34e76] Merge branch 'gpio/for-current' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git git bisect bad 51018b3e4652074f726aea6cd66e89edcef34e76 # bad: [014a17deb41201449f76df2b20c857a9c3294a7c] gpio: pca953x: handle short interrupt pulses on PCAL devices git bisect bad 014a17deb41201449f76df2b20c857a9c3294a7c # good: [cb0451e33be047fff7137f58d9996370e11fb344] gpio: shared: verify con_id when adding proxy lookup git bisect good cb0451e33be047fff7137f58d9996370e11fb344 # bad: [a7ac22d53d0990152b108c3f4fe30df45fcb0181] gpiolib: fix race condition for gdev->srcu git bisect bad a7ac22d53d0990152b108c3f4fe30df45fcb0181 # bad: [49416483a953662aa53c6d9bef651757d4a95ba5] gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib git bisect bad 49416483a953662aa53c6d9bef651757d4a95ba5 # first bad commit: [49416483a953662aa53c6d9bef651757d4a95ba5] gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib
On Thu, Jan 8, 2026 at 4:46 PM Mark Brown <broonie@kernel.org> wrote: > > On Mon, Dec 22, 2025 at 11:01:28AM +0100, Bartosz Golaszewski wrote: > > 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. > > We're seeing futher issues which bisect to this patch in today's > next/pending-fixes on db845c: > > <1>[ 18.348426] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 > > ... > > <4>[ 18.799534] Call trace: > <4>[ 18.799536] gpiod_direction_output_nonotify+0x14/0x194 (P) > <4>[ 18.799541] gpiod_configure_flags+0xb0/0x364 > <4>[ 18.799543] gpiod_find_and_request+0x144/0x504 > <4>[ 18.832617] gpiod_get_index+0x58/0x90 > <4>[ 18.836657] devm_gpiod_get_index+0x20/0xb0 > <4>[ 18.841139] devm_gpiod_get_optional+0x18/0x34 > <4>[ 18.845881] lt9611_probe+0x130/0x488 [lontium_lt9611] > > Some prior instances were fixed by: > > https://lore.kernel.org/all/20260106-gpio-shared-fixes-v2-0-c7091d2f7581@oss.qualcomm.com/ > > but that's only in next/master, not next/pending-fixes, and in any case > the issue also appears in next/master which should include them. > Does the following fix it by any chance? https://lore.kernel.org/all/20260108102314.18816-1-bartosz.golaszewski@oss.qualcomm.com Bart
On Thu, Jan 08, 2026 at 04:52:24PM +0100, Bartosz Golaszewski wrote: > On Thu, Jan 8, 2026 at 4:46 PM Mark Brown <broonie@kernel.org> wrote: > > We're seeing futher issues which bisect to this patch in today's > > next/pending-fixes on db845c: > Does the following fix it by any chance? > https://lore.kernel.org/all/20260108102314.18816-1-bartosz.golaszewski@oss.qualcomm.com Seems to, yes thanks.
On Thu, Jan 8, 2026 at 5:29 PM Mark Brown <broonie@kernel.org> wrote: > > On Thu, Jan 08, 2026 at 04:52:24PM +0100, Bartosz Golaszewski wrote: > > On Thu, Jan 8, 2026 at 4:46 PM Mark Brown <broonie@kernel.org> wrote: > > > > We're seeing futher issues which bisect to this patch in today's > > > next/pending-fixes on db845c: > > > Does the following fix it by any chance? > > > https://lore.kernel.org/all/20260108102314.18816-1-bartosz.golaszewski@oss.qualcomm.com > > Seems to, yes thanks. Good, sorry for the fallout. There's one more patch[1] that fixes the issue that actually caused so many people to be affected. If you could give it a spin as well and leave your T-b, that would be great. Thanks, Bartosz [1] https://lore.kernel.org/all/20260108-gpio-shared-false-positive-v1-1-5dbf8d1b2f7d@oss.qualcomm.com/
On 22.12.2025 11:01, Bartosz Golaszewski wrote:
> 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: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case")
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
This patch landed in linux-next as commit 49416483a953 ("gpio: shared:
allow sharing a reset-gpios pin between reset-gpio and gpiolib"). In my
tests I found that it breaks booting and triggers warnings on some of my
test boards. Reverting it on top of next-20260105 fixes those issues.
Let me know if I can help debugging this issue.
Here are relevant logs from my 3 test systems:
1. Samsung TM2e - arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts
exynos-dsi 13900000.dsi: [drm:samsung_dsim_host_attach] Attached s6e3hf2
device (lanes:4 bpp:24 mode-flags:0x6e0)
Unable to handle kernel NULL pointer dereference at virtual address
0000000000000000
Mem abort info:
...
Internal error: Oops: 0000000096000004 [#1] SMP
Modules linked in: brcmfmac(+) panel_samsung_s6e3ha2(+) brcmutil
backlight sha256 snd_soc_hdmi_codec cfg80211 phy_exynos5_usbdrd
snd_soc_tm2_wm5110 s5p_mfc typec snd_soc_wm5110 hci_uart btqca
s3fwrn5_i2c snd_soc_wm_adsp btbcm s3fwrn5 cs_dsp snd_soc_i2s nci
bluetooth snd_soc_arizona arizona_micsupp s5p_jpeg exynos_gsc
arizona_ldo1 nfc v4l2_mem2mem snd_soc_max98504 snd_soc_idma
snd_soc_s3c_dma videobuf2_dma_contig max77693_haptic snd_soc_core
ntc_thermistor ir_spi snd_compress videobuf2_memops ecdh_generic
panfrost snd_pcm_dmaengine ecc videobuf2_v4l2 drm_shmem_helper videodev
rfkill snd_pcm pwrseq_core gpu_sched gpio_shared_proxy videobuf2_common
mc snd_timer snd soundcore ipv6 libsha1
CPU: 5 UID: 0 PID: 241 Comm: systemd-udevd Not tainted 6.19.0-rc1+
#16358 PREEMPT
Hardware name: Samsung TM2E board (DT)
pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : gpiod_direction_input_nonotify+0x20/0x39c
lr : gpiod_configure_flags+0x23c/0x480
...
Call trace:
gpiod_direction_input_nonotify+0x20/0x39c (P)
gpiod_configure_flags+0x23c/0x480
gpiod_find_and_request+0x1a0/0x574
gpiod_get_index+0x58/0x84
devm_gpiod_get_index+0x20/0xb4
devm_gpiod_get_optional+0x18/0x30
samsung_dsim_host_attach+0x1c8/0x284
mipi_dsi_attach+0x30/0x54
s6e3ha2_probe+0x148/0x200 [panel_samsung_s6e3ha2]
mipi_dsi_drv_probe+0x20/0x2c
really_probe+0xbc/0x298
__driver_probe_device+0x78/0x12c
driver_probe_device+0xdc/0x164
__driver_attach+0x9c/0x1ac
bus_for_each_dev+0x74/0xd0
driver_attach+0x24/0x30
bus_add_driver+0xe4/0x208
driver_register+0x60/0x128
mipi_dsi_driver_register_full+0x5c/0x68
s6e3ha2_driver_init+0x20/0x1000 [panel_samsung_s6e3ha2]
do_one_initcall+0x64/0x308
do_init_module+0x58/0x23c
load_module+0x1b48/0x1dc4
init_module_from_file+0xd4/0xec
idempotent_init_module+0x188/0x280
__arm64_sys_finit_module+0x68/0xac
invoke_syscall+0x48/0x10c
el0_svc_common.constprop.0+0xc8/0xe8
do_el0_svc+0x20/0x2c
el0_svc+0x50/0x2e8
el0t_64_sync_handler+0xa0/0xe4
el0t_64_sync+0x198/0x19c
Code: a90153f3 aa0003f3 a9025bf5 a90363f7 (f9400014)
---[ end trace 0000000000000000 ]---
Kernel panic - not syncing: Oops: Fatal exception
SMP: stopping secondary CPUs
Kernel Offset: disabled
CPU features: 0x20c000,1061e001,00008000,0400421b
Memory Limit: none
---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
2. Raspberrry Pi 3B+ - arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts
reset_gpio reset.gpio.0: cannot find GPIO chip gpiolib_shared.proxy.4,
deferring
------------[ cut here ]------------
WARNING: drivers/gpio/gpiolib-shared.c:493 at
gpio_shared_add_proxy_lookup+0x15c/0x224, CPU#1: kworker/u16:1/40
Modules linked in: ecc reset_gpio snd gpio_shared_proxy(+)
raspberrypi_cpufreq(+) raspberrypi_hwmon rfkill soundcore pwrseq_core
bcm2835_thermal pwm_bcm2835 vchiq i2c_bcm2835 fuse dm_mod ipv6 libsha1
CPU: 1 UID: 0 PID: 40 Comm: kworker/u16:1 Not tainted
6.19.0-rc4-next-20260105+ #11963 PREEMPT
Hardware name: Raspberry Pi 3 Model B (DT)
Workqueue: events_unbound deferred_probe_work_func
pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : gpio_shared_add_proxy_lookup+0x15c/0x224
lr : gpio_shared_add_proxy_lookup+0x138/0x224
...
Call trace:
gpio_shared_add_proxy_lookup+0x15c/0x224 (P)
gpiod_find_and_request+0x200/0x574
gpiod_get_index+0x58/0x84
devm_gpiod_get_index+0x20/0xb4
devm_gpiod_get+0x18/0x24
reset_gpio_probe+0x4c/0x14c [reset_gpio]
auxiliary_bus_probe+0x44/0x90
really_probe+0xbc/0x298
__driver_probe_device+0x78/0x12c
driver_probe_device+0xdc/0x164
__device_attach_driver+0xb8/0x138
bus_for_each_drv+0x80/0xdc
__device_attach+0xa8/0x1b0
device_initial_probe+0x50/0x54
bus_probe_device+0x38/0xa8
deferred_probe_work_func+0x8c/0xc8
process_one_work+0x208/0x604
worker_thread+0x244/0x388
kthread+0x140/0x14c
ret_from_fork+0x10/0x20
irq event stamp: 82552
hardirqs last enabled at (82551): [<ffff8000813a1d60>]
__schedule+0xc08/0x1204
hardirqs last disabled at (82552): [<ffff800081397194>] el1_brk64+0x20/0x60
softirqs last enabled at (81674): [<ffff8000800c71b4>]
handle_softirqs+0x4c4/0x4dc
softirqs last disabled at (81665): [<ffff800080010674>]
__do_softirq+0x14/0x20
---[ end trace 0000000000000000 ]---
3. Khadas VIM3 -
arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dtb
BUG: sleeping function called from invalid context at
kernel/locking/mutex.c:591
in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 142, name:
kworker/u25:3
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
INFO: lockdep is turned off.
irq event stamp: 46379
hardirqs last enabled at (46379): [<ffff8000813acb24>]
_raw_spin_unlock_irqrestore+0x74/0x78
hardirqs last disabled at (46378): [<ffff8000813abf38>]
_raw_spin_lock_irqsave+0x84/0x88
softirqs last enabled at (46330): [<ffff8000800c71b4>]
handle_softirqs+0x4c4/0x4dc
softirqs last disabled at (46295): [<ffff800080010674>]
__do_softirq+0x14/0x20
CPU: 1 UID: 0 PID: 142 Comm: kworker/u25:3 Tainted: G C
6.19.0-rc4-next-20260105+ #11963 PREEMPT
Tainted: [C]=CRAP
Hardware name: Khadas VIM3 (DT)
Workqueue: events_unbound deferred_probe_work_func
Call trace:
show_stack+0x18/0x24 (C)
dump_stack_lvl+0x90/0xd0
dump_stack+0x18/0x24
__might_resched+0x144/0x248
__might_sleep+0x48/0x98
__mutex_lock+0x5c/0x894
mutex_lock_nested+0x24/0x30
pinctrl_get_device_gpio_range+0x44/0x128
pinctrl_gpio_set_config+0x40/0xdc
gpiochip_generic_config+0x28/0x3c
gpio_do_set_config+0xa8/0x194
gpiod_set_config+0x34/0xfc
gpio_shared_proxy_set_config+0x6c/0xfc [gpio_shared_proxy]
gpio_do_set_config+0xa8/0x194
gpiod_set_transitory+0x4c/0xf0
gpiod_configure_flags+0xa4/0x480
gpiod_find_and_request+0x1a0/0x574
gpiod_get_index+0x58/0x84
devm_gpiod_get_index+0x20/0xb4
devm_gpiod_get+0x18/0x24
mmc_pwrseq_emmc_probe+0x40/0xb8
platform_probe+0x5c/0xac
really_probe+0xbc/0x298
__driver_probe_device+0x78/0x12c
driver_probe_device+0xdc/0x164
__device_attach_driver+0xb8/0x138
bus_for_each_drv+0x80/0xdc
__device_attach+0xa8/0x1b0
> ---
> drivers/gpio/gpiolib-shared.c | 182 ++++++++++++++++++++++++++++++------------
> 1 file changed, 129 insertions(+), 53 deletions(-)
>
> diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
> index f589109590c7c6bc9c0c1828ea15ab9003846523..baf7e07a3bb887dab8155078666a15779e304409 100644
> --- a/drivers/gpio/gpiolib-shared.c
> +++ b/drivers/gpio/gpiolib-shared.c
> @@ -76,6 +76,56 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node,
> return NULL;
> }
>
> +static struct gpio_shared_ref *gpio_shared_make_ref(struct fwnode_handle *fwnode,
> + const char *con_id,
> + enum gpiod_flags flags)
> +{
> + char *con_id_cpy __free(kfree) = NULL;
> +
> + struct gpio_shared_ref *ref __free(kfree) = kzalloc(sizeof(*ref), GFP_KERNEL);
> + if (!ref)
> + return NULL;
> +
> + if (con_id) {
> + con_id_cpy = kstrdup(con_id, GFP_KERNEL);
> + if (!con_id_cpy)
> + return NULL;
> + }
> +
> + ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL);
> + if (ref->dev_id < 0)
> + return NULL;
> +
> + ref->flags = flags;
> + ref->con_id = no_free_ptr(con_id_cpy);
> + ref->fwnode = fwnode;
> + mutex_init(&ref->lock);
> +
> + return no_free_ptr(ref);
> +}
> +
> +static int gpio_shared_setup_reset_proxy(struct gpio_shared_entry *entry,
> + enum gpiod_flags flags)
> +{
> + struct gpio_shared_ref *ref;
> +
> + list_for_each_entry(ref, &entry->refs, list) {
> + if (!ref->fwnode && ref->con_id && strcmp(ref->con_id, "reset") == 0)
> + return 0;
> + }
> +
> + ref = gpio_shared_make_ref(NULL, "reset", flags);
> + if (!ref)
> + return -ENOMEM;
> +
> + list_add_tail(&ref->list, &entry->refs);
> +
> + pr_debug("Created a secondary shared GPIO reference for potential reset-gpio device for GPIO %u at %s\n",
> + entry->offset, fwnode_get_name(entry->fwnode));
> +
> + return 0;
> +}
> +
> /* Handle all special nodes that we should ignore. */
> static bool gpio_shared_of_node_ignore(struct device_node *node)
> {
> @@ -106,6 +156,7 @@ static int gpio_shared_of_traverse(struct device_node *curr)
> size_t con_id_len, suffix_len;
> struct fwnode_handle *fwnode;
> struct of_phandle_args args;
> + struct gpio_shared_ref *ref;
> struct property *prop;
> unsigned int offset;
> const char *suffix;
> @@ -138,6 +189,7 @@ static int gpio_shared_of_traverse(struct device_node *curr)
>
> for (i = 0; i < count; i++) {
> struct device_node *np __free(device_node) = NULL;
> + char *con_id __free(kfree) = NULL;
>
> ret = of_parse_phandle_with_args(curr, prop->name,
> "#gpio-cells", i,
> @@ -182,15 +234,6 @@ static int gpio_shared_of_traverse(struct device_node *curr)
> list_add_tail(&entry->list, &gpio_shared_list);
> }
>
> - struct gpio_shared_ref *ref __free(kfree) =
> - kzalloc(sizeof(*ref), GFP_KERNEL);
> - if (!ref)
> - return -ENOMEM;
> -
> - ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr));
> - ref->flags = args.args[1];
> - mutex_init(&ref->lock);
> -
> if (strends(prop->name, "gpios"))
> suffix = "-gpios";
> else if (strends(prop->name, "gpio"))
> @@ -202,27 +245,32 @@ static int gpio_shared_of_traverse(struct device_node *curr)
>
> /* We only set con_id if there's actually one. */
> if (strcmp(prop->name, "gpios") && strcmp(prop->name, "gpio")) {
> - ref->con_id = kstrdup(prop->name, GFP_KERNEL);
> - if (!ref->con_id)
> + con_id = kstrdup(prop->name, GFP_KERNEL);
> + if (!con_id)
> return -ENOMEM;
>
> - con_id_len = strlen(ref->con_id);
> + con_id_len = strlen(con_id);
> suffix_len = strlen(suffix);
>
> - ref->con_id[con_id_len - suffix_len] = '\0';
> + con_id[con_id_len - suffix_len] = '\0';
> }
>
> - ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL);
> - if (ref->dev_id < 0) {
> - kfree(ref->con_id);
> + ref = gpio_shared_make_ref(fwnode_handle_get(of_fwnode_handle(curr)),
> + con_id, args.args[1]);
> + if (!ref)
> return -ENOMEM;
> - }
>
> if (!list_empty(&entry->refs))
> pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
> entry->offset, fwnode_get_name(entry->fwnode));
>
> - list_add_tail(&no_free_ptr(ref)->list, &entry->refs);
> + list_add_tail(&ref->list, &entry->refs);
> +
> + if (strcmp(prop->name, "reset-gpios") == 0) {
> + ret = gpio_shared_setup_reset_proxy(entry, args.args[1]);
> + if (ret)
> + return ret;
> + }
> }
> }
>
> @@ -306,20 +354,16 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
> struct fwnode_handle *reset_fwnode = dev_fwnode(consumer);
> struct fwnode_reference_args ref_args, aux_args;
> struct device *parent = consumer->parent;
> + struct gpio_shared_ref *real_ref;
> bool match;
> int ret;
>
> + lockdep_assert_held(&ref->lock);
> +
> /* The reset-gpio device must have a parent AND a firmware node. */
> if (!parent || !reset_fwnode)
> return false;
>
> - /*
> - * FIXME: use device_is_compatible() once the reset-gpio drivers gains
> - * a compatible string which it currently does not have.
> - */
> - if (!strstarts(dev_name(consumer), "reset.gpio."))
> - return false;
> -
> /*
> * Parent of the reset-gpio auxiliary device is the GPIO chip whose
> * fwnode we stored in the entry structure.
> @@ -328,33 +372,56 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
> return false;
>
> /*
> - * The device associated with the shared reference's firmware node is
> - * the consumer of the reset control exposed by the reset-gpio device.
> - * It must have a "reset-gpios" property that's referencing the entry's
> - * firmware node.
> - *
> - * The reference args must agree between the real consumer and the
> - * auxiliary reset-gpio device.
> + * Now we need to find the actual pin we want to assign to this
> + * reset-gpio device. To that end: iterate over the list of references
> + * of this entry and see if there's one, whose reset-gpios property's
> + * arguments match the ones from this consumer's node.
> */
> - ret = fwnode_property_get_reference_args(ref->fwnode, "reset-gpios",
> - NULL, 2, 0, &ref_args);
> - if (ret)
> - return false;
> + list_for_each_entry(real_ref, &entry->refs, list) {
> + if (!real_ref->fwnode)
> + continue;
> +
> + /*
> + * The device associated with the shared reference's firmware
> + * node is the consumer of the reset control exposed by the
> + * reset-gpio device. It must have a "reset-gpios" property
> + * that's referencing the entry's firmware node.
> + *
> + * The reference args must agree between the real consumer and
> + * the auxiliary reset-gpio device.
> + */
> + ret = fwnode_property_get_reference_args(real_ref->fwnode,
> + "reset-gpios",
> + NULL, 2, 0, &ref_args);
> + if (ret)
> + continue;
> +
> + ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios",
> + NULL, 2, 0, &aux_args);
> + if (ret) {
> + fwnode_handle_put(ref_args.fwnode);
> + continue;
> + }
> +
> + match = ((ref_args.fwnode == entry->fwnode) &&
> + (aux_args.fwnode == entry->fwnode) &&
> + (ref_args.args[0] == aux_args.args[0]));
>
> - ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios",
> - NULL, 2, 0, &aux_args);
> - if (ret) {
> fwnode_handle_put(ref_args.fwnode);
> - return false;
> - }
> + fwnode_handle_put(aux_args.fwnode);
> +
> + if (!match)
> + continue;
>
> - match = ((ref_args.fwnode == entry->fwnode) &&
> - (aux_args.fwnode == entry->fwnode) &&
> - (ref_args.args[0] == aux_args.args[0]));
> + /*
> + * Reuse the fwnode of the real device, next time we'll use it
> + * in the normal path.
> + */
> + ref->fwnode = fwnode_handle_get(real_ref->fwnode);
> + return true;
> + }
>
> - fwnode_handle_put(ref_args.fwnode);
> - fwnode_handle_put(aux_args.fwnode);
> - return match;
> + return false;
> }
> #else
> static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
> @@ -379,12 +446,20 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
>
> list_for_each_entry(entry, &gpio_shared_list, list) {
> list_for_each_entry(ref, &entry->refs, list) {
> - if (!device_match_fwnode(consumer, ref->fwnode) &&
> - !gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
> - continue;
> -
> guard(mutex)(&ref->lock);
>
> + /*
> + * FIXME: use device_is_compatible() once the reset-gpio
> + * drivers gains a compatible string which it currently
> + * does not have.
> + */
> + if (!ref->fwnode && strstarts(dev_name(consumer), "reset.gpio.")) {
> + if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
> + continue;
> + } else if (!device_match_fwnode(consumer, ref->fwnode)) {
> + continue;
> + }
> +
> if ((!con_id && ref->con_id) || (con_id && !ref->con_id) ||
> (con_id && ref->con_id && strcmp(con_id, ref->con_id) != 0))
> continue;
> @@ -471,8 +546,9 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
> entry->offset, gpio_device_get_label(gdev));
>
> list_for_each_entry(ref, &entry->refs, list) {
> - pr_debug("Setting up a shared GPIO entry for %s\n",
> - fwnode_get_name(ref->fwnode));
> + pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n",
> + fwnode_get_name(ref->fwnode) ?: "(no fwnode)",
> + ref->con_id ?: "(none)");
>
> ret = gpio_shared_make_adev(gdev, entry, ref);
> if (ret)
>
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
On Mon, Jan 05, 2026 at 12:50:22PM +0100, Marek Szyprowski wrote:
> On 22.12.2025 11:01, Bartosz Golaszewski wrote:
> > 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.
> This patch landed in linux-next as commit 49416483a953 ("gpio: shared:
> allow sharing a reset-gpios pin between reset-gpio and gpiolib"). In my
> tests I found that it breaks booting and triggers warnings on some of my
> test boards. Reverting it on top of next-20260105 fixes those issues.
> Let me know if I can help debugging this issue.
Not sure if it's this specific patch (one of the bisects identified it,
but I'm seeing others going to the merge commit for the gpio fixes
branch) but I'm also seeing issues with gpios. pwrseq is affected on
several platforms after backtraces that look a lot like the one that
Marek is seeing on Raspberry Pi 3B+ (which I also see). This breaks at
least the WiFi:
[ 13.475670] platform wifi-pwrseq: deferred probe pending: pwrseq_simple: reset control not ready
Raspberry Pi 4:
https://lava.sirena.org.uk/scheduler/job/2335022#L1200
Toradax Mallow (TI K3):
https://lava.sirena.org.uk/scheduler/job/2335415#L1457
On Tue, Jan 6, 2026 at 1:21 PM Mark Brown <broonie@kernel.org> wrote:
>
> On Mon, Jan 05, 2026 at 12:50:22PM +0100, Marek Szyprowski wrote:
> > On 22.12.2025 11:01, Bartosz Golaszewski wrote:
> > > 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.
>
> > This patch landed in linux-next as commit 49416483a953 ("gpio: shared:
> > allow sharing a reset-gpios pin between reset-gpio and gpiolib"). In my
> > tests I found that it breaks booting and triggers warnings on some of my
> > test boards. Reverting it on top of next-20260105 fixes those issues.
> > Let me know if I can help debugging this issue.
>
> Not sure if it's this specific patch (one of the bisects identified it,
> but I'm seeing others going to the merge commit for the gpio fixes
> branch) but I'm also seeing issues with gpios. pwrseq is affected on
> several platforms after backtraces that look a lot like the one that
> Marek is seeing on Raspberry Pi 3B+ (which I also see). This breaks at
> least the WiFi:
>
> [ 13.475670] platform wifi-pwrseq: deferred probe pending: pwrseq_simple: reset control not ready
>
> Raspberry Pi 4:
>
> https://lava.sirena.org.uk/scheduler/job/2335022#L1200
>
> Toradax Mallow (TI K3):
>
> https://lava.sirena.org.uk/scheduler/job/2335415#L1457
Hi! These two should be fixed by the following series:
https://lore.kernel.org/all/20260106-gpio-shared-fixes-v2-0-c7091d2f7581@oss.qualcomm.com/
Could you please give it a try and possibly add your T-b?
Bart
On Mon, Jan 5, 2026 at 12:50 PM Marek Szyprowski
<m.szyprowski@samsung.com> wrote:
>
> On 22.12.2025 11:01, Bartosz Golaszewski wrote:
> > 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: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case")
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>
> This patch landed in linux-next as commit 49416483a953 ("gpio: shared:
> allow sharing a reset-gpios pin between reset-gpio and gpiolib"). In my
> tests I found that it breaks booting and triggers warnings on some of my
> test boards. Reverting it on top of next-20260105 fixes those issues.
> Let me know if I can help debugging this issue.
>
>
> Here are relevant logs from my 3 test systems:
>
Hi!
I've just sent out fixes for problems #2 and #3 with you in Cc. For #1
- are you sure this is really the commit that causes it? It doesn't
seem to have anything to do with shared GPIOs.
Bartosz
On Mon, Jan 5, 2026 at 12:50 PM Marek Szyprowski
<m.szyprowski@samsung.com> wrote:
>
> On 22.12.2025 11:01, Bartosz Golaszewski wrote:
> > 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: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case")
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>
> This patch landed in linux-next as commit 49416483a953 ("gpio: shared:
> allow sharing a reset-gpios pin between reset-gpio and gpiolib"). In my
> tests I found that it breaks booting and triggers warnings on some of my
> test boards. Reverting it on top of next-20260105 fixes those issues.
> Let me know if I can help debugging this issue.
>
>
> Here are relevant logs from my 3 test systems:
>
Thanks for the report.
Nice combo, it looks like these are three separate bugs...
>
> 1. Samsung TM2e - arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts
>
> exynos-dsi 13900000.dsi: [drm:samsung_dsim_host_attach] Attached s6e3hf2
> device (lanes:4 bpp:24 mode-flags:0x6e0)
> Unable to handle kernel NULL pointer dereference at virtual address
Could you use faddr2line to point me to the exact offending line? This
would speed up the debugging.
> 0000000000000000
> Mem abort info:
> ...
> Internal error: Oops: 0000000096000004 [#1] SMP
> Modules linked in: brcmfmac(+) panel_samsung_s6e3ha2(+) brcmutil
> backlight sha256 snd_soc_hdmi_codec cfg80211 phy_exynos5_usbdrd
> snd_soc_tm2_wm5110 s5p_mfc typec snd_soc_wm5110 hci_uart btqca
> s3fwrn5_i2c snd_soc_wm_adsp btbcm s3fwrn5 cs_dsp snd_soc_i2s nci
> bluetooth snd_soc_arizona arizona_micsupp s5p_jpeg exynos_gsc
> arizona_ldo1 nfc v4l2_mem2mem snd_soc_max98504 snd_soc_idma
> snd_soc_s3c_dma videobuf2_dma_contig max77693_haptic snd_soc_core
> ntc_thermistor ir_spi snd_compress videobuf2_memops ecdh_generic
> panfrost snd_pcm_dmaengine ecc videobuf2_v4l2 drm_shmem_helper videodev
> rfkill snd_pcm pwrseq_core gpu_sched gpio_shared_proxy videobuf2_common
> mc snd_timer snd soundcore ipv6 libsha1
> CPU: 5 UID: 0 PID: 241 Comm: systemd-udevd Not tainted 6.19.0-rc1+
> #16358 PREEMPT
> Hardware name: Samsung TM2E board (DT)
> pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> pc : gpiod_direction_input_nonotify+0x20/0x39c
> lr : gpiod_configure_flags+0x23c/0x480
> ...
> Call trace:
> gpiod_direction_input_nonotify+0x20/0x39c (P)
> gpiod_configure_flags+0x23c/0x480
> gpiod_find_and_request+0x1a0/0x574
> gpiod_get_index+0x58/0x84
> devm_gpiod_get_index+0x20/0xb4
> devm_gpiod_get_optional+0x18/0x30
> samsung_dsim_host_attach+0x1c8/0x284
> mipi_dsi_attach+0x30/0x54
> s6e3ha2_probe+0x148/0x200 [panel_samsung_s6e3ha2]
> mipi_dsi_drv_probe+0x20/0x2c
> really_probe+0xbc/0x298
> __driver_probe_device+0x78/0x12c
> driver_probe_device+0xdc/0x164
> __driver_attach+0x9c/0x1ac
> bus_for_each_dev+0x74/0xd0
> driver_attach+0x24/0x30
> bus_add_driver+0xe4/0x208
> driver_register+0x60/0x128
> mipi_dsi_driver_register_full+0x5c/0x68
> s6e3ha2_driver_init+0x20/0x1000 [panel_samsung_s6e3ha2]
> do_one_initcall+0x64/0x308
> do_init_module+0x58/0x23c
> load_module+0x1b48/0x1dc4
> init_module_from_file+0xd4/0xec
> idempotent_init_module+0x188/0x280
> __arm64_sys_finit_module+0x68/0xac
> invoke_syscall+0x48/0x10c
> el0_svc_common.constprop.0+0xc8/0xe8
> do_el0_svc+0x20/0x2c
> el0_svc+0x50/0x2e8
> el0t_64_sync_handler+0xa0/0xe4
> el0t_64_sync+0x198/0x19c
> Code: a90153f3 aa0003f3 a9025bf5 a90363f7 (f9400014)
> ---[ end trace 0000000000000000 ]---
> Kernel panic - not syncing: Oops: Fatal exception
> SMP: stopping secondary CPUs
> Kernel Offset: disabled
> CPU features: 0x20c000,1061e001,00008000,0400421b
> Memory Limit: none
> ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
>
>
> 2. Raspberrry Pi 3B+ - arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts
>
Could you please enable CONFIG_DEBUG_GPIO and post the entire kernel
log somewhere? Looks like there's invalid logic with creating the
proxies somewhere.
> reset_gpio reset.gpio.0: cannot find GPIO chip gpiolib_shared.proxy.4,
> deferring
> ------------[ cut here ]------------
> WARNING: drivers/gpio/gpiolib-shared.c:493 at
> gpio_shared_add_proxy_lookup+0x15c/0x224, CPU#1: kworker/u16:1/40
> Modules linked in: ecc reset_gpio snd gpio_shared_proxy(+)
> raspberrypi_cpufreq(+) raspberrypi_hwmon rfkill soundcore pwrseq_core
> bcm2835_thermal pwm_bcm2835 vchiq i2c_bcm2835 fuse dm_mod ipv6 libsha1
> CPU: 1 UID: 0 PID: 40 Comm: kworker/u16:1 Not tainted
> 6.19.0-rc4-next-20260105+ #11963 PREEMPT
> Hardware name: Raspberry Pi 3 Model B (DT)
> Workqueue: events_unbound deferred_probe_work_func
> pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> pc : gpio_shared_add_proxy_lookup+0x15c/0x224
> lr : gpio_shared_add_proxy_lookup+0x138/0x224
> ...
> Call trace:
> gpio_shared_add_proxy_lookup+0x15c/0x224 (P)
> gpiod_find_and_request+0x200/0x574
> gpiod_get_index+0x58/0x84
> devm_gpiod_get_index+0x20/0xb4
> devm_gpiod_get+0x18/0x24
> reset_gpio_probe+0x4c/0x14c [reset_gpio]
> auxiliary_bus_probe+0x44/0x90
> really_probe+0xbc/0x298
> __driver_probe_device+0x78/0x12c
> driver_probe_device+0xdc/0x164
> __device_attach_driver+0xb8/0x138
> bus_for_each_drv+0x80/0xdc
> __device_attach+0xa8/0x1b0
> device_initial_probe+0x50/0x54
> bus_probe_device+0x38/0xa8
> deferred_probe_work_func+0x8c/0xc8
> process_one_work+0x208/0x604
> worker_thread+0x244/0x388
> kthread+0x140/0x14c
> ret_from_fork+0x10/0x20
> irq event stamp: 82552
> hardirqs last enabled at (82551): [<ffff8000813a1d60>]
> __schedule+0xc08/0x1204
> hardirqs last disabled at (82552): [<ffff800081397194>] el1_brk64+0x20/0x60
> softirqs last enabled at (81674): [<ffff8000800c71b4>]
> handle_softirqs+0x4c4/0x4dc
> softirqs last disabled at (81665): [<ffff800080010674>]
> __do_softirq+0x14/0x20
> ---[ end trace 0000000000000000 ]---
>
>
> 3. Khadas VIM3 -
> arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dtb
>
> BUG: sleeping function called from invalid context at
> kernel/locking/mutex.c:591
Can you post the output of gpiodetect and gpioinfo? I believe this to
be a buggy GPIO driver which says the controller can't sleep but it
then uses sleeping pinctrl interfaces. We had a similar bug uncovered
by this series with qualcomm boards.
> in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 142, name:
> kworker/u25:3
> preempt_count: 1, expected: 0
> RCU nest depth: 0, expected: 0
> INFO: lockdep is turned off.
> irq event stamp: 46379
> hardirqs last enabled at (46379): [<ffff8000813acb24>]
> _raw_spin_unlock_irqrestore+0x74/0x78
> hardirqs last disabled at (46378): [<ffff8000813abf38>]
> _raw_spin_lock_irqsave+0x84/0x88
> softirqs last enabled at (46330): [<ffff8000800c71b4>]
> handle_softirqs+0x4c4/0x4dc
> softirqs last disabled at (46295): [<ffff800080010674>]
> __do_softirq+0x14/0x20
> CPU: 1 UID: 0 PID: 142 Comm: kworker/u25:3 Tainted: G C
> 6.19.0-rc4-next-20260105+ #11963 PREEMPT
> Tainted: [C]=CRAP
> Hardware name: Khadas VIM3 (DT)
> Workqueue: events_unbound deferred_probe_work_func
> Call trace:
> show_stack+0x18/0x24 (C)
> dump_stack_lvl+0x90/0xd0
> dump_stack+0x18/0x24
> __might_resched+0x144/0x248
> __might_sleep+0x48/0x98
> __mutex_lock+0x5c/0x894
> mutex_lock_nested+0x24/0x30
> pinctrl_get_device_gpio_range+0x44/0x128
> pinctrl_gpio_set_config+0x40/0xdc
> gpiochip_generic_config+0x28/0x3c
> gpio_do_set_config+0xa8/0x194
> gpiod_set_config+0x34/0xfc
> gpio_shared_proxy_set_config+0x6c/0xfc [gpio_shared_proxy]
> gpio_do_set_config+0xa8/0x194
> gpiod_set_transitory+0x4c/0xf0
> gpiod_configure_flags+0xa4/0x480
> gpiod_find_and_request+0x1a0/0x574
> gpiod_get_index+0x58/0x84
> devm_gpiod_get_index+0x20/0xb4
> devm_gpiod_get+0x18/0x24
> mmc_pwrseq_emmc_probe+0x40/0xb8
> platform_probe+0x5c/0xac
> really_probe+0xbc/0x298
> __driver_probe_device+0x78/0x12c
> driver_probe_device+0xdc/0x164
> __device_attach_driver+0xb8/0x138
> bus_for_each_drv+0x80/0xdc
> __device_attach+0xa8/0x1b0
>
Thanks in advance for the help!
Bart
On 05.01.2026 13:28, Bartosz Golaszewski wrote:
> On Mon, Jan 5, 2026 at 12:50 PM Marek Szyprowski
> <m.szyprowski@samsung.com> wrote:
>> On 22.12.2025 11:01, Bartosz Golaszewski wrote:
>>> 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: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case")
>>> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>> This patch landed in linux-next as commit 49416483a953 ("gpio: shared:
>> allow sharing a reset-gpios pin between reset-gpio and gpiolib"). In my
>> tests I found that it breaks booting and triggers warnings on some of my
>> test boards. Reverting it on top of next-20260105 fixes those issues.
>> Let me know if I can help debugging this issue.
>>
>>
>> Here are relevant logs from my 3 test systems:
>>
> Thanks for the report.
>
> Nice combo, it looks like these are three separate bugs...
>
>> 1. Samsung TM2e - arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts
>>
>> exynos-dsi 13900000.dsi: [drm:samsung_dsim_host_attach] Attached s6e3hf2
>> device (lanes:4 bpp:24 mode-flags:0x6e0)
>> Unable to handle kernel NULL pointer dereference at virtual address
> Could you use faddr2line to point me to the exact offending line? This
> would speed up the debugging.
I need some time to get that output, but this issue is caused by a
devm_gpiod_get_optional() call for a gpio that is not defined for that
board.
> > ...
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
On 05.01.2026 18:26, Marek Szyprowski wrote:
> On 05.01.2026 13:28, Bartosz Golaszewski wrote:
>> On Mon, Jan 5, 2026 at 12:50 PM Marek Szyprowski
>> <m.szyprowski@samsung.com> wrote:
>>> On 22.12.2025 11:01, Bartosz Golaszewski wrote:
>>>> 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: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner
>>>> case")
>>>> Signed-off-by: Bartosz Golaszewski
>>>> <bartosz.golaszewski@oss.qualcomm.com>
>>> This patch landed in linux-next as commit 49416483a953 ("gpio: shared:
>>> allow sharing a reset-gpios pin between reset-gpio and gpiolib"). In my
>>> tests I found that it breaks booting and triggers warnings on some
>>> of my
>>> test boards. Reverting it on top of next-20260105 fixes those issues.
>>> Let me know if I can help debugging this issue.
>>>
>>>
>>> Here are relevant logs from my 3 test systems:
>>>
>> Thanks for the report.
>>
>> Nice combo, it looks like these are three separate bugs...
>>
>>> 1. Samsung TM2e - arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts
>>>
>>> exynos-dsi 13900000.dsi: [drm:samsung_dsim_host_attach] Attached
>>> s6e3hf2
>>> device (lanes:4 bpp:24 mode-flags:0x6e0)
>>> Unable to handle kernel NULL pointer dereference at virtual address
>> Could you use faddr2line to point me to the exact offending line? This
>> would speed up the debugging.
>
> I need some time to get that output, but this issue is caused by a
> devm_gpiod_get_optional() call for a gpio that is not defined for that
> board.
>
I think that everything is in the call stack:
Call trace:
gpiod_direction_input_nonotify+0x20/0x39c (P)
gpiod_configure_flags+0x23c/0x480
gpiod_find_and_request+0x1a0/0x574
gpiod_get_index+0x58/0x84
devm_gpiod_get_index+0x20/0xb4
devm_gpiod_get_optional+0x18/0x30
samsung_dsim_host_attach+0x1c8/0x284
mipi_dsi_attach+0x30/0x54
s6e3ha2_probe+0x148/0x200 [panel_samsung_s6e3ha2]
...
The issue is in gpiod_direction_input_nonotify+0x20/0x39c:
$ grep gpiod_direction_input_nonotify System.map
ffff800080810360 T gpiod_direction_input_nonotify
$ aarch64-linux-gnu-addr2line -f -e vmlinux ffff800080810380
class_gpio_chip_guard_constructor
/home/m.szyprowski/dev/kernel/linux-next/drivers/gpio/gpiolib.h:231
IMHO it looks that gpiod_configure_flags() is called for NULL gpio_chip.
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
On Mon, Jan 5, 2026 at 7:16 PM Marek Szyprowski <m.szyprowski@samsung.com> wrote: > > >> > >>> 1. Samsung TM2e - arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts > >>> > >>> exynos-dsi 13900000.dsi: [drm:samsung_dsim_host_attach] Attached > >>> s6e3hf2 > >>> device (lanes:4 bpp:24 mode-flags:0x6e0) > >>> Unable to handle kernel NULL pointer dereference at virtual address > >> Could you use faddr2line to point me to the exact offending line? This > >> would speed up the debugging. > > > > I need some time to get that output, but this issue is caused by a > > devm_gpiod_get_optional() call for a gpio that is not defined for that > > board. > > > I think that everything is in the call stack: > > Call trace: > gpiod_direction_input_nonotify+0x20/0x39c (P) > gpiod_configure_flags+0x23c/0x480 > gpiod_find_and_request+0x1a0/0x574 > gpiod_get_index+0x58/0x84 > devm_gpiod_get_index+0x20/0xb4 > devm_gpiod_get_optional+0x18/0x30 > samsung_dsim_host_attach+0x1c8/0x284 > mipi_dsi_attach+0x30/0x54 > s6e3ha2_probe+0x148/0x200 [panel_samsung_s6e3ha2] > > ... > > > The issue is in gpiod_direction_input_nonotify+0x20/0x39c: > > $ grep gpiod_direction_input_nonotify System.map > ffff800080810360 T gpiod_direction_input_nonotify > > $ aarch64-linux-gnu-addr2line -f -e vmlinux ffff800080810380 > class_gpio_chip_guard_constructor > /home/m.szyprowski/dev/kernel/linux-next/drivers/gpio/gpiolib.h:231 > > IMHO it looks that gpiod_configure_flags() is called for NULL gpio_chip. > The whole point of this macro is to make sure the chip is not NULL. It dereferences gdev->chip under SRCU for that reason. Is it the descriptor (struct gpio_desc *desc) pointer passed to gpiod_direction_input_nonotify() that is NULL by any chance? It shouldn't be possible but I want to rule it out. Also: it doesn't really look like it has anything to do with shared GPIO management. I looked into the DTS and there are no shared GPIOs. Can you enable CONFIG_DEBUG_GPIO and post the entire kernel log just to make sure? Is the issue reproducible and goes away when that commit is reverted? Bartosz
© 2016 - 2026 Red Hat, Inc.