From fcbc48dc650d2f58bfe19c4486830de0e9cad62e Mon Sep 17 00:00:00 2001 From: Ming Yu Date: Wed, 7 Oct 2026 17:20:50 +0800 Subject: [PATCH 01/10] gpio: nct6694: Mark the GPIO controller as sleeping The GPIO callbacks take a mutex and issue USB transfers, so this GPIO chip must not be used in atomic context. Change the can_sleep switch in struct gpio_chip to true. Fixes: 611a995e8ae1 ("gpio: Add Nuvoton NCT6694 GPIO support") Signed-off-by: Ming Yu Link: https://patch.msgid.link/20261007092102.3768818-2-a0282524688@gmail.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-nct6694.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c index a8607f0d9915..a38add1cde29 100644 --- a/drivers/gpio/gpio-nct6694.c +++ b/drivers/gpio/gpio-nct6694.c @@ -444,7 +444,7 @@ static int nct6694_gpio_probe(struct platform_device *pdev) data->gpio.set_config = nct6694_set_config; data->gpio.init_valid_mask = nct6694_init_valid_mask; data->gpio.base = -1; - data->gpio.can_sleep = false; + data->gpio.can_sleep = true; data->gpio.owner = THIS_MODULE; data->gpio.ngpio = NCT6694_NR_GPIO; From 52336337f1a01ad803c7f3ddb23f40222e9ad58d Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sun, 11 Oct 2026 18:33:33 -0400 Subject: [PATCH 02/10] tools: gpio: fix building from the top level with O= "make O= tools/gpio" fails: Makefile:27: /tools/build/Makefile.include: No such file or directory tools/Makefile clears srctree, and the gpio Makefile only works it out again when building_out_of_srctree is not set, which the top-level Makefile sets for O= builds. Also work out srctree when it is empty, as tools/bpf/Makefile does since commit a89b2cbf71d64 ("tools, bpf: Fix build for 'make -s tools/bpf O='"). Fixes: 4a6a6f5c4aeed ("tools: gpio: Use !building_out_of_srctree to determine srctree") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Sasha Levin Link: https://patch.msgid.link/20261011223358.2327625-5-sashal@kernel.org Signed-off-by: Bartosz Golaszewski --- tools/gpio/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 342e056c8c66..1cd7636b9cac 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -7,7 +7,13 @@ bindir ?= /usr/bin # isn't set and when invoked from selftests build, where srctree # is set to ".". building_out_of_srctree is undefined for in srctree # builds +ifeq ($(srctree),) +update_srctree := 1 +endif ifndef building_out_of_srctree +update_srctree := 1 +endif +ifeq ($(update_srctree),1) srctree := $(patsubst %/,%,$(dir $(CURDIR))) srctree := $(patsubst %/,%,$(dir $(srctree))) endif From bd22f7e63509fa758cf500d9af3e88a3d3df96be Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 14 Oct 2026 11:38:25 +0200 Subject: [PATCH 03/10] gpio: shared: fix use-after-free bug when adding shared proxies The GPIO lookup table can stay alive for longer than the kobject whose name string's address we're assigning to lookup->dev_id. Fix a potential UAF by duplicating the string. Cc: stable@vger.kernel.org Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support") Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20261014-gpio-shared-fwnode-lookup-v4-1-2253ad645fd6@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 5f9623e40b0f..6acfec73b734 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -450,7 +450,6 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle * const char *con_id, unsigned long lflags) { const char *dev_id = dev_name(consumer); - struct gpiod_lookup_table *lookup; struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; @@ -480,18 +479,22 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle * if (!key) return -ENOMEM; - lookup = kzalloc_flex(*lookup, table, 2); + struct gpiod_lookup_table *lookup __free(kfree) = + kzalloc_flex(*lookup, table, 2); if (!lookup) return -ENOMEM; pr_debug("Adding machine lookup entry for a shared GPIO for consumer %s, with key '%s' and con_id '%s'\n", dev_id, key, ref->con_id ?: "none"); - lookup->dev_id = dev_id; + lookup->dev_id = kstrdup(dev_id, GFP_KERNEL); + if (!lookup->dev_id) + return -ENOMEM; + lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0, ref->con_id, lflags); - ref->lookup = lookup; + ref->lookup = no_free_ptr(lookup); gpiod_add_lookup_table(ref->lookup); return 0; @@ -611,6 +614,7 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) if (ref->lookup) { gpiod_remove_lookup_table(ref->lookup); kfree(ref->lookup->table[0].key); + kfree(ref->lookup->dev_id); kfree(ref->lookup); ref->lookup = NULL; } From cf73c3fc03c43a8a86fd487c62390b4744eff9ec Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 14 Oct 2026 11:38:26 +0200 Subject: [PATCH 04/10] gpio: shared: gracefully handle no-device lookup of shared GPIOs We use platform lookup tables for shared GPIOs. This mechanism needs a struct device to work so fwnode-based lookup with no device associated currently causes a NULL-pointer deference. Adding this functionality will require a larger rework and it has never worked anyway so add a check that allows the kernel to gracefully handle this situation with an error ahead of implementing that functionality as a new feature. Cc: stable@vger.kernel.org Reported-by: Abel Vesa Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support") Link: https://patch.msgid.link/20261014-gpio-shared-fwnode-lookup-v4-2-2253ad645fd6@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 6acfec73b734..8c9ac9d93304 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -449,9 +449,14 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *fwnode, const char *con_id, unsigned long lflags) { - const char *dev_id = dev_name(consumer); struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; + const char *dev_id; + + if (!consumer) + return -EOPNOTSUPP; + + dev_id = dev_name(consumer); list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { From 851bb4a42991666f515040e95e6f40191da9e899 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 14 Oct 2026 10:44:02 +0200 Subject: [PATCH 05/10] gpio: kunit: fix GPIO device reference leak with __free() KUnit aborts the test thread immediately using kthread_exit() so the variable annotated with __free() never really goes out of scope and the associated callback is not called. Schedule a kunit action instead. Fixes: a05cfd98c5ec ("gpio: kunit: add test cases for software node hogs") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20261013-gpio-kunit-plat-lookup-v3-0-3907f913e964%40oss.qualcomm.com?part=1 Link: https://patch.msgid.link/20261014-gpio-kunit-autofree-leak-fix-v1-1-5bfa7be0eb1f@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-kunit.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-kunit.c b/drivers/gpio/gpiolib-kunit.c index e6cb43a8df5b..6a2c8b34f34b 100644 --- a/drivers/gpio/gpiolib-kunit.c +++ b/drivers/gpio/gpiolib-kunit.c @@ -28,6 +28,8 @@ #define GPIO_TEST_PROVIDER_NGPIO 4 +KUNIT_DEFINE_ACTION_WRAPPER(gpio_device_put_wrapper, gpio_device_put, struct gpio_device *); + /* * The test provider tracks per-line direction and value so that lines can be * driven as both inputs and outputs - this is needed to exercise input as well @@ -770,6 +772,7 @@ static void gpio_hog_assert(struct kunit *test, unsigned int offset, struct property_entry properties[2]; struct platform_device *pdev; struct fwnode_handle *fwnode; + struct gpio_device *gdev; struct gpio_desc *desc; bool bound = true; int ret; @@ -789,10 +792,12 @@ static void gpio_hog_assert(struct kunit *test, unsigned int offset, wait_for_device_probe(); /* The hog must have configured the line with the expected direction. */ - struct gpio_device *gdev __free(gpio_device_put) = - gpio_device_find_by_label(GPIO_CONSUMER_NAME); + gdev = gpio_device_find_by_label(GPIO_CONSUMER_NAME); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gdev); + ret = kunit_add_action_or_reset(test, gpio_device_put_wrapper, gdev); + KUNIT_ASSERT_EQ(test, ret, 0); + desc = gpio_device_get_desc(gdev, offset); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, desc); From c28846ca1ac6134881114d272314623c8433e372 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Thu, 15 Oct 2026 10:57:49 +0800 Subject: [PATCH 06/10] gpiolib: fix memory leak in gpiod_set_array_value_complex() on error paths A drive-by review by Sashiko reports that, after a failed call to gpiochip_set_multiple(), gpiod_set_array_value() returns abruptly, bypassing the freeing of possibly alloced bitmaps, potentially leaking memory. It is an unlikely error path, but is possible. Defer the return code check until after the bitmap_free() block. Fixes: 9b407312755f ("gpiolib: rework the wrapper around gpio_chip::set_multiple()") Reported-by: Sashiko Link: https://lore.kernel.org/linux-gpio/sashiko-outbox-168233@kernel.org/ Signed-off-by: Kent Gibson Link: https://patch.msgid.link/20261015025749.47039-1-warthog618@gmail.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 772c6f04f489..c0394c7d6279 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3954,16 +3954,17 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, } while ((i < array_size) && gpio_device_chip_cmp(desc_array[i]->gdev, guard.gc)); /* push collected bits to outputs */ - if (count != 0) { + ret = 0; + if (count != 0) ret = gpiochip_set_multiple(guard.gc, mask, bits); - if (ret) - return ret; - } if (mask != fastpath_mask) bitmap_free(mask); if (bits != fastpath_bits) bitmap_free(bits); + + if (ret) + return ret; } return 0; } From 38d44f78f041ffe60c8e2443b99434a199e7541d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 13 Oct 2026 14:01:09 +0800 Subject: [PATCH 07/10] gpio: mxc: fix race between chained IRQ handler install and probe completion mxc_update_irq_chained_handler() is called before the IRQ domain, the generic IRQ chip, and the port list entry are set up. If an interrupt arrives in that window: - mx3_gpio_irq_handler() calls generic_handle_domain_irq() with port->domain still NULL. - mx2_gpio_irq_handler() walks mxc_gpio_ports, but the port has not been added to the list yet. Additionally, if any of the subsequent probe steps (gpio_generic_chip_init(), devm_gpiochip_add_data(), irq_domain_create_legacy(), or mxc_gpio_init_gc()) fail, the error paths never unregister the chained handler, leaving a dangling handler that points at freed memory. Move the handler installation after all its dependencies are ready and after list_add_tail(), so the handler is never live while the data structures it touches are incomplete, and is never installed if probe fails. Fixes: 5f6d1998adeb ("gpio: mxc: release the parent IRQ in runtime suspend") Assisted-by: LLM Reviewed-by: Frank Li Signed-off-by: Peng Fan Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20261013-gpio-mxc-cleanup-v7-1-c4d769587d3e@nxp.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mxc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 7e2690d92df6..e05f276a50e8 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -474,8 +474,6 @@ static int mxc_gpio_probe(struct platform_device *pdev) } else port->mx_irq_handler = mx3_gpio_irq_handler; - mxc_update_irq_chained_handler(port, true); - config.dev = &pdev->dev; config.sz = 4; config.dat = port->base + GPIO_PSR; @@ -525,6 +523,8 @@ static int mxc_gpio_probe(struct platform_device *pdev) list_add_tail(&port->node, &mxc_gpio_ports); + mxc_update_irq_chained_handler(port, true); + platform_set_drvdata(pdev, port); pm_runtime_put_autosuspend(&pdev->dev); From b7719c575dec69146f6d537fd616b27083c0cf45 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 13 Oct 2026 14:01:10 +0800 Subject: [PATCH 08/10] gpio: mxc: fix both_edges bit operations gpio_set_irq_type() can be called concurrently for different pins on the same port. The IRQ core serializes per irq descriptor, but different pins have different descriptors, so on SMP systems two concurrent gpio_set_irq_type() calls for pins on the same port run without mutual exclusion. The read-modify-write of port->both_edges is performed outside the port-wide scoped_guard(gpio_generic_lock_irqsave) section, so concurrent updates for different pins can overwrite each other, causing missed interrupts or stuck IRQ lines on dual-edge triggered pins. The original uniprocessor MXC SoCs were not affected; the race became reachable on multi-core i.MX7 and i.MX8 SoCs that reuse this driver. Convert both_edges from u32 to unsigned long and use set_bit(), clear_bit(), and test_bit() to make the modifications atomic. Fixes: 910862ec092c ("mxc: emulate GPIO interrupt on both-edges") Reviewed-by: Frank Li Signed-off-by: Peng Fan Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20261013-gpio-mxc-cleanup-v7-2-c4d769587d3e@nxp.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mxc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index e05f276a50e8..7e17d7668980 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -7,6 +7,7 @@ // Authors: Daniel Mack, Juergen Beisert. // Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. +#include #include #include #include @@ -68,7 +69,7 @@ struct mxc_gpio_port { struct irq_domain *domain; struct gpio_generic_chip gen_gc; struct device *dev; - u32 both_edges; + unsigned long both_edges; struct mxc_gpio_reg_saved gpio_saved_reg; bool power_off; u32 wakeup_pads; @@ -168,7 +169,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) int edge; void __iomem *reg = port->base; - port->both_edges &= ~(1 << gpio_idx); + clear_bit(gpio_idx, &port->both_edges); switch (type) { case IRQ_TYPE_EDGE_RISING: edge = GPIO_INT_RISE_EDGE; @@ -188,7 +189,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) edge = GPIO_INT_HIGH_LEV; pr_debug("mxc: set GPIO %d to high trigger\n", gpio_idx); } - port->both_edges |= 1 << gpio_idx; + set_bit(gpio_idx, &port->both_edges); } break; case IRQ_TYPE_LEVEL_LOW: @@ -259,7 +260,7 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) while (irq_stat != 0) { int irqoffset = fls(irq_stat) - 1; - if (port->both_edges & (1 << irqoffset)) + if (test_bit(irqoffset, &port->both_edges)) mxc_flip_edge(port, irqoffset); generic_handle_domain_irq(port->domain, irqoffset); From 170aeff46fb54f41545c85a72aec525aebc79d44 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 13 Oct 2026 14:01:11 +0800 Subject: [PATCH 09/10] gpio: mxc: fix wakeup_pads bit operations gpio_set_wake_irq() can be called concurrently for different pins on the same port. The writer-vs-writer race is the concern: two concurrent gpio_set_wake_irq() calls for different pins on the same port both do a non-atomic read-modify-write on the same wakeup_pads word. The old |= and &= compile to separate load/modify/store instructions that can interleave, losing one CPU's update. assign_bit() uses an atomic RMW instruction, so concurrent writers to different bits in the same word are safe. The reader side (for_each_set_bit in noirq_suspend, wakeup_pads > 0) runs in noirq context where no concurrent writer can execute, so reader atomicity is not needed. wakeup_pads is a u32, while assign_bit() operates on unsigned long pointers. On 64-bit platforms, this causes an 8-byte read-modify-write on a 4-byte field, corrupting the adjacent is_pad_wakeup. So change wakeup_pads to unsigned long and reorder to avoid wasting words. And fix the enable/disable path unconditionally sets/clears the wakeup_pads bit even when enable_irq_wake()/disable_irq_wake() fails. Only update the bit on success. Fixes: f60c9eac54af ("gpio: mxc: enable pad wakeup on i.MX8x platforms") Assisted-by: LLM Reviewed-by: Frank Li Signed-off-by: Peng Fan Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20261013-gpio-mxc-cleanup-v7-3-c4d769587d3e@nxp.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mxc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 7e17d7668980..e3a80f17d041 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -72,8 +72,8 @@ struct mxc_gpio_port { unsigned long both_edges; struct mxc_gpio_reg_saved gpio_saved_reg; bool power_off; - u32 wakeup_pads; bool is_pad_wakeup; + unsigned long wakeup_pads; u32 pad_type[32]; const struct mxc_gpio_hwdata *hwdata; }; @@ -331,16 +331,18 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) ret = enable_irq_wake(port->irq_high); else ret = enable_irq_wake(port->irq); - port->wakeup_pads |= BIT(gpio_idx); } else { if (port->irq_high && (gpio_idx >= 16)) ret = disable_irq_wake(port->irq_high); else ret = disable_irq_wake(port->irq); - port->wakeup_pads &= ~BIT(gpio_idx); } + if (ret) + return ret; - return ret; + assign_bit(gpio_idx, &port->wakeup_pads, enable); + + return 0; } static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) From 205cccd06e545694754e1bf8d626ea96e742cd8a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 13 Oct 2026 14:01:12 +0800 Subject: [PATCH 10/10] gpio: mxc: fix race between gpiochip registration and IRQ domain setup devm_gpiochip_add_data() makes the GPIO chip visible to consumers immediately. Since the chip sets .to_irq = mxc_gpio_to_irq, which calls irq_find_mapping(port->domain, offset), any to_irq() call between gpiochip registration and IRQ domain creation will operate on a NULL domain. Fix by moving devm_gpiochip_add_data() after the IRQ domain and generic irq chip are fully initialized, ensuring port->domain and the irq chip handlers are ready before the chip becomes visible to consumers. Fixes: d37a65bb4663 ("gpio/mxc: Move Freescale MXC gpio driver to drivers/gpio") Signed-off-by: Peng Fan Reviewed-by: Linus Walleij Reviewed-by: Frank Li Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20261013-gpio-mxc-cleanup-v7-4-c4d769587d3e@nxp.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mxc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index e3a80f17d041..32ded7b548fb 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -500,10 +500,6 @@ static int mxc_gpio_probe(struct platform_device *pdev) else /* silence boot time warning */ port->gen_gc.gc.base = -1; - err = devm_gpiochip_add_data(&pdev->dev, &port->gen_gc.gc, port); - if (err) - goto out_bgio; - irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id()); if (irq_base < 0) { err = irq_base; @@ -524,6 +520,15 @@ static int mxc_gpio_probe(struct platform_device *pdev) if (err < 0) goto out_irqdomain_remove; + /* + * Register the GPIO chip last: devm_gpiochip_add_data() makes the + * chip visible to consumers immediately, so the IRQ domain and + * generic irq chip must be ready before any to_irq() call. + */ + err = devm_gpiochip_add_data(&pdev->dev, &port->gen_gc.gc, port); + if (err) + goto out_irqdomain_remove; + list_add_tail(&port->node, &mxc_gpio_ports); mxc_update_irq_chained_handler(port, true);