From 7a7baebd9f23ba4f24796775472b2fd00dcd95d9 Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Wed, 15 Jul 2026 13:23:08 +0530 Subject: [PATCH 1/6] gpio: sloppy-logic-analyzer: Fix memory leak in gpio_la_poll_probe() The memory allocated for priv->blob.data is not freed in the error paths that follow the fops_buf_size_set() call in gpio_la_poll_probe(), as well as in the remove function. Fix that by using device managed action to free the memory on remove. Fixes: 7828b7bbbf20 ("gpio: add sloppy logic analyzer using polling") Signed-off-by: Abdun Nihaal Reviewed-by: Wolfram Sang Link: https://patch.msgid.link/20260715075311.527753-1-nihaal@cse.iitm.ac.in Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-sloppy-logic-analyzer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c index 2bbd308ca08e..aa23b5779802 100644 --- a/drivers/gpio/gpio-sloppy-logic-analyzer.c +++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c @@ -160,6 +160,13 @@ static int fops_buf_size_get(void *data, u64 *val) return 0; } +static void fops_buf_release(void *data) +{ + struct gpio_la_poll_priv *priv = data; + + vfree(priv->blob.data); +} + static int fops_buf_size_set(void *data, u64 val) { struct gpio_la_poll_priv *priv = data; @@ -238,6 +245,9 @@ static int gpio_la_poll_probe(struct platform_device *pdev) return ret; fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE); + ret = devm_add_action_or_reset(dev, fops_buf_release, priv); + if (ret) + return ret; priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN); if (IS_ERR(priv->descs)) From e1cc8fa0fb9e5112d15f2c310b68ac316981c06c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 14 Jul 2026 00:30:53 +0100 Subject: [PATCH 2/6] gpiolib: tolerate gpio-hogs lacking a hogging state Commit d1d564ec4992 ("gpio: move hogs into GPIO core") made gpiochip_add_hog() return -EINVAL for hog nodes lacking any of the 'input', 'output-low' or 'output-high' properties. The error is propagated by gpiochip_hog_lines() and fails registration of the whole GPIO chip. The previous OF-specific implementation tolerated such nodes: of_parse_own_gpio() warned "no hogging state specified, bailing out" and of_gpiochip_add_hog() stopped processing the node without failing chip registration. Some boards deliberately ship hog nodes without a hogging state in their base devicetree and supply the state via overlay, e.g. the PCIe slot key selection hogs on the BananaPi R4 Pro added in commit e309fa232d12 ("arm64: dts: mediatek: mt7988a-bpi-r4pro: rework pcie gpio-hog handling"), as the polarity set in the base devicetree could not be overridden from an overlay. Booting such a board without an overlay applied now fails to register the gpiochip. On the BananaPi R4 Pro this means the MT7988A pinctrl device fails to probe, all peripherals including the console UART defer forever, and the board finally hangs when clk_disable_unused() gates the clocks of the UART still in use by earlycon: gpiochip_add_data_with_key: GPIOs 512..595 (pinctrl_moore) failed to register, -22 mt7988-pinctrl 1001f000.pinctrl: error -EINVAL: Failed to add gpio_chip ... clk: Disabling unused clocks (hangs) Restore the previous behaviour by warning about hog nodes lacking a hogging state and skipping them instead of failing the registration of the whole GPIO chip. Fixes: d1d564ec4992 ("gpio: move hogs into GPIO core") Cc: stable@vger.kernel.org Signed-off-by: Daniel Golle Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/4c67cf0839ccf57db35a826df6d8fc779531509a.1783974733.git.daniel@makrotopia.org Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e5fb60111151..c433a095907f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -999,14 +999,17 @@ int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode) if (ret < 0) return ret; - if (fwnode_property_present(fwnode, "input")) + if (fwnode_property_present(fwnode, "input")) { dflags |= GPIOD_IN; - else if (fwnode_property_present(fwnode, "output-low")) + } else if (fwnode_property_present(fwnode, "output-low")) { dflags |= GPIOD_OUT_LOW; - else if (fwnode_property_present(fwnode, "output-high")) + } else if (fwnode_property_present(fwnode, "output-high")) { dflags |= GPIOD_OUT_HIGH; - else - return -EINVAL; + } else { + gpiochip_warn(gc, "%pfwP: no hogging state specified, bailing out\n", + fwnode); + return 0; + } fwnode_property_read_string(fwnode, "line-name", &name); From 9dc325327babe7f159e84cbe9380a45342da0585 Mon Sep 17 00:00:00 2001 From: Mark Tomlinson Date: Thu, 9 Jul 2026 16:51:16 +1200 Subject: [PATCH 3/6] gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock Locking is disabled in the regmap config as this driver uses its own lock. This means that all calls to regmap functions (read or write) must hold the i2c_lock. The function pca953x_irq_bus_sync_unlock() did not do this, and it was therefore possible that multiple threads could cause an incorrect register to be read/written. A previous patch partly fixed this, but only protected the write to the interrupt mask register, and not the read from the direction register. Fixes: bfc6444b57dc ("gpio: pca953x: fix pca953x_irq_bus_sync_unlock race") Cc: stable@vger.kernel.org Signed-off-by: Mark Tomlinson Link: https://patch.msgid.link/20260709045116.2304246-1-mark.tomlinson@alliedtelesis.co.nz Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index f6b870b7b352..e03bf1b12091 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -604,20 +604,28 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long * return 0; } -static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) +static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc, + unsigned int off) { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); u8 bit = pca953x_get_bit_mask(chip, off); - guard(mutex)(&chip->i2c_lock); - if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE) return regmap_update_bits(chip->regmap, dirreg, bit, 0); return regmap_update_bits(chip->regmap, dirreg, bit, bit); } +static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off) +{ + struct pca953x_chip *chip = gpiochip_get_data(gc); + + guard(mutex)(&chip->i2c_lock); + + return pca953x_gpio_direction_input_unlocked(gc, off); +} + static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { @@ -855,9 +863,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) DECLARE_BITMAP(reg_direction, MAX_LINE); int level; + guard(mutex)(&chip->i2c_lock); + if (chip->driver_data & PCA_PCAL) { DECLARE_BITMAP(latched_inputs, MAX_LINE); - guard(mutex)(&chip->i2c_lock); /* Enable latch on edge-triggered interrupt-enabled inputs */ bitmap_or(latched_inputs, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio); @@ -879,7 +888,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) /* Look for any newly setup interrupt */ for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio) - pca953x_gpio_direction_input(&chip->gpio_chip, level); + pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level); mutex_unlock(&chip->irq_lock); } From 67ff4bf723c8bd1f1b10450fa3e8f55762418104 Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Fri, 24 Jul 2026 09:42:28 -0700 Subject: [PATCH 4/6] gpio: gpio-by-pinctrl: Apply initial value in direction output wrapper After successfully configuring gpio pin as output, set the requested initial output value via the existing gpio set wrapper, so that the pin is not left at its previous level. Fixes: 7671f4949a6c ("gpio: gpio-by-pinctrl: add pinctrl based generic GPIO driver") Signed-off-by: Alex Tran Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20260724-gpio-pinctrl-output-set-val-v2-1-cad55d025636@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-by-pinctrl.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-by-pinctrl.c b/drivers/gpio/gpio-by-pinctrl.c index 7d7c48ce5163..fb8440acb31d 100644 --- a/drivers/gpio/gpio-by-pinctrl.c +++ b/drivers/gpio/gpio-by-pinctrl.c @@ -27,12 +27,6 @@ static int pin_control_gpio_get_direction(struct gpio_chip *gc, unsigned int off return GPIO_LINE_DIRECTION_IN; } -static int pin_control_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int val) -{ - return pinctrl_gpio_direction_output(chip, offset); -} - static int pin_control_gpio_get(struct gpio_chip *chip, unsigned int offset) { unsigned long config; @@ -55,6 +49,18 @@ static int pin_control_gpio_set(struct gpio_chip *chip, unsigned int offset, return pinctrl_gpio_set_config(chip, offset, config); } +static int pin_control_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int val) +{ + int ret; + + ret = pinctrl_gpio_direction_output(chip, offset); + if (ret) + return ret; + + return pin_control_gpio_set(chip, offset, val); +} + static int pin_control_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; From d233087c19f6607ef926ac3f47d776e2406ffd1f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 27 Jul 2026 15:02:05 +0700 Subject: [PATCH 5/6] gpio: pca953x: fix cache_only and IRQ state on restore_context() failure When pca953x_restore_context() fails, cache_only is left disabled and the IRQ left enabled, even though register synchronization may not have completed successfully. Restore cache_only and disable the IRQ again on failure, matching the state set by pca953x_save_context(). Fixes: ec5bde62019b ("gpio: pca953x: Split pca953x_restore_context() and pca953x_save_context()") Fixes: 3e38f946062b ("gpio: pca953x: fix IRQ storm on system wake up") Cc: stable@vger.kernel.org Reviewed-by: Linus Walleij Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260727080205.16353-1-phucduc.bui@gmail.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index e03bf1b12091..aac9ea7520b6 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -1378,9 +1378,20 @@ static int pca953x_restore_context(struct pca953x_chip *chip) regcache_mark_dirty(chip->regmap); ret = pca953x_regcache_sync(chip); if (ret) - return ret; + goto err; - return regcache_sync(chip->regmap); + ret = regcache_sync(chip->regmap); + if (ret) + goto err; + + return 0; + +err: + if (chip->client->irq > 0) + disable_irq(chip->client->irq); + regcache_cache_only(chip->regmap, true); + + return ret; } static void pca953x_save_context(struct pca953x_chip *chip) From a02b8950d619123da64f69b70fe1dadef217dfe4 Mon Sep 17 00:00:00 2001 From: Junjie Cao Date: Thu, 23 Jul 2026 09:41:29 +0800 Subject: [PATCH 6/6] gpio: pch: use raw_spinlock_t for the register lock pch_irq_type() is registered as the irq_chip .irq_set_type callback and takes chip->spinlock with spin_lock_irqsave(). This callback is reached from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled. That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is an rtmutex-backed sleeping lock, so acquiring it there is invalid. This was confirmed on a PREEMPT_RT kernel with lockdep (PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP). A grounded PoC mirrored pch_irq_type()'s locking and drove it through the real genirq carrier irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e. the same __irq_set_trigger() edge that __setup_irq() takes for a requested IRQ. With the original spin_lock_irqsave() edge lockdep reported an invalid wait context, immediately followed by: BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60 rt_spin_lock+0x3a/0x1c0 repro_irq_set_type+0x64/0xa0 [pch_repro] __irq_set_trigger+0x69/0x140 irq_set_irq_type+0x78/0xd0 Switching the mirrored lock to raw_spinlock_t made both splats go away. Convert the register lock to raw_spinlock_t. The same lock also serializes the GPIO direction/value callbacks and the suspend/resume register save/restore, but all of those critical sections only perform MMIO register accesses (ioread32()/iowrite32()) and irq_set_handler_locked(); none of them contain sleepable operations. Keeping this register lock non-sleeping is therefore appropriate for the irqchip callbacks and does not change the GPIO-side locking contract. This is the same class of issue and fix as recently addressed for other GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use raw_spinlock_t in the irq startup path"). Fixes: 38eb18a6f92d ("gpio-pch: Support interrupt function") Cc: stable@vger.kernel.org Signed-off-by: Junjie Cao Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20260723014129.1129730-1-junjie.cao@intel.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pch.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 4ffa0955a9e3..07a5617b314b 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -96,7 +96,7 @@ struct pch_gpio { struct pch_gpio_reg_data pch_gpio_reg; int irq_base; enum pch_type_t ioh; - spinlock_t spinlock; + raw_spinlock_t spinlock; }; static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) @@ -105,7 +105,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) struct pch_gpio *chip = gpiochip_get_data(gpio); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) reg_val |= BIT(nr); @@ -113,7 +113,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->po); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -133,7 +133,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, u32 reg_val; unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) @@ -147,7 +147,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, pm |= BIT(nr); iowrite32(pm, &chip->reg->pm); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -158,12 +158,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) u32 pm; unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->pm); pm &= BIT(gpio_pins[chip->ioh]) - 1; pm &= ~BIT(nr); iowrite32(pm, &chip->reg->pm); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -265,7 +265,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) return 0; } - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); /* Set interrupt mode */ im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); @@ -277,7 +277,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) else if (type & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(d, handle_edge_irq); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -374,7 +374,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, chip->ioh = id->driver_data; chip->reg = chip->base; pci_set_drvdata(pdev, chip); - spin_lock_init(&chip->spinlock); + raw_spin_lock_init(&chip->spinlock); pch_gpio_setup(chip); ret = devm_gpiochip_add_data(dev, &chip->gpio, chip); @@ -407,9 +407,9 @@ static int pch_gpio_suspend(struct device *dev) struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); pch_gpio_save_reg_conf(chip); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -419,11 +419,11 @@ static int pch_gpio_resume(struct device *dev) struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); iowrite32(0x01, &chip->reg->reset); iowrite32(0x00, &chip->reg->reset); pch_gpio_restore_reg_conf(chip); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; }