Merge tag 'gpio-fixes-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio fixes from Bartosz Golaszewski:

 - fix locking context with shared GPIOs in gpio-tegra

 - fix IRQ domain leak in error path in gpio-davinci

 - fix returning a potentially uninitialized integer in
   gpiochip_set_multiple()

 - use raw spinlock in gpio-eic-sprd and gpio-sch to address locking
   context issues

 - bail out of probe() if registering the GPIO chip fails in gpio-mlxbf3

 - fix varible type for storing the "ngpios" property in gpio-pisosr

 - fix out-of-bounds pin access in GPIO ACPI

 - make GPIO ACPI core only trigger interrupts on boot that are marked
   as ActiveBoth

 - fix kerneldoc in gpio-tb10x

 - reference the real software node of the cs5535 GPIO controller in
   Geode board file

* tag 'gpio-fixes-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpio: davinci: fix IRQ domain leak on devm_kzalloc failure
  gpio: tegra: do not call pinctrl for GPIO direction
  gpio: tb10x: fix struct tb10x_gpio kernel-doc
  gpiolib: initialize return value in gpiochip_set_multiple()
  x86/platform/geode: reference the real node of the cs5535 GPIO controller
  gpio: eic-sprd: use raw_spinlock_t in the irq startup path
  gpio: sch: use raw_spinlock_t in the irq startup path
  gpiolib: acpi: Prevent out-of-bounds pin access in OperationRegion handler
  gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  gpio: mlxbf3: fail probe if gpiochip registration fails
  gpio: pisosr: Read "ngpios" as u32
  gpiolib: acpi: Only trigger ActiveBoth interrupts on boot
This commit is contained in:
Linus Torvalds
2026-06-25 09:33:23 -07:00
11 changed files with 87 additions and 64 deletions

View File

@@ -3026,7 +3026,7 @@ config GEODE_COMMON
config ALIX
bool "PCEngines ALIX System Support (LED setup)"
select GPIOLIB
depends on GPIO_CS5535=y
select GEODE_COMMON
help
This option enables system support for the PCEngines ALIX.
@@ -3034,21 +3034,21 @@ config ALIX
ALIX2/3/6 boards. However, other system specific setup should
get added here.
Note: You must still enable the drivers for GPIO and LED support
(GPIO_CS5535 & LEDS_GPIO) to actually use the LEDs
Note: You must still enable the drivers for LED support (LEDS_GPIO)
to actually use the LEDs
Note: You have to set alix.force=1 for boards with Award BIOS.
config NET5501
bool "Soekris Engineering net5501 System Support (LEDS, GPIO, etc)"
select GPIOLIB
depends on GPIO_CS5535=y
select GEODE_COMMON
help
This option enables system support for the Soekris Engineering net5501.
config GEOS
bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)"
select GPIOLIB
depends on GPIO_CS5535=y
select GEODE_COMMON
depends on DMI
help

View File

@@ -9,15 +9,12 @@
#include <linux/gpio/property.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/mfd/cs5535.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "geode-common.h"
static const struct software_node geode_gpiochip_node = {
.name = "cs5535-gpio",
};
static const struct property_entry geode_gpio_keys_props[] = {
PROPERTY_ENTRY_U32("poll-interval", 20),
{ }
@@ -44,7 +41,6 @@ static const struct software_node geode_restart_key_node = {
};
static const struct software_node *geode_gpio_keys_swnodes[] __initconst = {
&geode_gpiochip_node,
&geode_gpio_keys_node,
&geode_restart_key_node,
NULL
@@ -66,7 +62,7 @@ int __init geode_create_restart_key(unsigned int pin)
struct platform_device *pd;
int err;
geode_restart_gpio_ref = SOFTWARE_NODE_REFERENCE(&geode_gpiochip_node,
geode_restart_gpio_ref = SOFTWARE_NODE_REFERENCE(&cs5535_gpio_swnode,
pin, GPIO_ACTIVE_LOW);
err = software_node_register_node_group(geode_gpio_keys_swnodes);
@@ -143,7 +139,7 @@ int __init geode_create_leds(const char *label, const struct geode_led *leds,
goto err_free_names;
}
gpio_refs[i] = SOFTWARE_NODE_REFERENCE(&geode_gpiochip_node,
gpio_refs[i] = SOFTWARE_NODE_REFERENCE(&cs5535_gpio_swnode,
leds[i].pin,
GPIO_ACTIVE_LOW);
props[i * 3 + 0] =
@@ -188,3 +184,5 @@ int __init geode_create_leds(const char *label, const struct geode_led *leds,
kfree(swnodes);
return err;
}
MODULE_IMPORT_NS("CS5535");

View File

@@ -568,8 +568,10 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
sizeof(struct
davinci_gpio_irq_data),
GFP_KERNEL);
if (!irqdata)
if (!irqdata) {
irq_domain_remove(chips->irq_domain);
return -ENOMEM;
}
irqdata->regs = g;
irqdata->bank_num = bank;

View File

@@ -95,7 +95,7 @@ struct sprd_eic {
struct notifier_block irq_nb;
void __iomem *base[SPRD_EIC_MAX_BANK];
enum sprd_eic_type type;
spinlock_t lock;
raw_spinlock_t lock;
int irq;
};
@@ -149,7 +149,7 @@ static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset,
unsigned long flags;
u32 tmp;
spin_lock_irqsave(&sprd_eic->lock, flags);
raw_spin_lock_irqsave(&sprd_eic->lock, flags);
tmp = readl_relaxed(base + reg);
if (val)
@@ -158,7 +158,7 @@ static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset,
tmp &= ~BIT(SPRD_EIC_BIT(offset));
writel_relaxed(tmp, base + reg);
spin_unlock_irqrestore(&sprd_eic->lock, flags);
raw_spin_unlock_irqrestore(&sprd_eic->lock, flags);
}
static int sprd_eic_read(struct gpio_chip *chip, unsigned int offset, u16 reg)
@@ -628,7 +628,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
if (!sprd_eic)
return -ENOMEM;
spin_lock_init(&sprd_eic->lock);
raw_spin_lock_init(&sprd_eic->lock);
sprd_eic->type = pdata->type;
sprd_eic->irq = platform_get_irq(pdev, 0);

View File

@@ -255,7 +255,8 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev)
ret = devm_gpiochip_add_data(dev, gc, gs);
if (ret)
dev_err_probe(dev, ret, "Failed adding memory mapped gpiochip\n");
return dev_err_probe(dev, ret,
"Failed adding memory mapped gpiochip\n");
return 0;
}

View File

@@ -112,6 +112,7 @@ static int pisosr_gpio_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct pisosr_gpio *gpio;
u32 ngpios;
int ret;
gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
@@ -120,7 +121,8 @@ static int pisosr_gpio_probe(struct spi_device *spi)
gpio->chip = template_chip;
gpio->chip.parent = dev;
of_property_read_u16(dev->of_node, "ngpios", &gpio->chip.ngpio);
if (!of_property_read_u32(dev->of_node, "ngpios", &ngpios))
gpio->chip.ngpio = ngpios;
gpio->spi = spi;

View File

@@ -39,7 +39,7 @@
struct sch_gpio {
struct gpio_chip chip;
void __iomem *regs;
spinlock_t lock;
raw_spinlock_t lock;
unsigned short resume_base;
/* GPE handling */
@@ -104,9 +104,9 @@ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num)
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&sch->lock, flags);
raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GIO, 1);
spin_unlock_irqrestore(&sch->lock, flags);
raw_spin_unlock_irqrestore(&sch->lock, flags);
return 0;
}
@@ -122,9 +122,9 @@ static int sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val)
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&sch->lock, flags);
raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GLV, val);
spin_unlock_irqrestore(&sch->lock, flags);
raw_spin_unlock_irqrestore(&sch->lock, flags);
return 0;
}
@@ -135,9 +135,9 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num,
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&sch->lock, flags);
raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GIO, 0);
spin_unlock_irqrestore(&sch->lock, flags);
raw_spin_unlock_irqrestore(&sch->lock, flags);
/*
* according to the datasheet, writing to the level register has no
@@ -196,14 +196,14 @@ static int sch_irq_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
spin_lock_irqsave(&sch->lock, flags);
raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GTPE, rising);
sch_gpio_reg_set(sch, gpio_num, GTNE, falling);
irq_set_handler_locked(d, handle_edge_irq);
spin_unlock_irqrestore(&sch->lock, flags);
raw_spin_unlock_irqrestore(&sch->lock, flags);
return 0;
}
@@ -215,9 +215,9 @@ static void sch_irq_ack(struct irq_data *d)
irq_hw_number_t gpio_num = irqd_to_hwirq(d);
unsigned long flags;
spin_lock_irqsave(&sch->lock, flags);
raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GTS, 1);
spin_unlock_irqrestore(&sch->lock, flags);
raw_spin_unlock_irqrestore(&sch->lock, flags);
}
static void sch_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t gpio_num, int val)
@@ -225,9 +225,9 @@ static void sch_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t gpio_num,
struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&sch->lock, flags);
raw_spin_lock_irqsave(&sch->lock, flags);
sch_gpio_reg_set(sch, gpio_num, GGPE, val);
spin_unlock_irqrestore(&sch->lock, flags);
raw_spin_unlock_irqrestore(&sch->lock, flags);
}
static void sch_irq_mask(struct irq_data *d)
@@ -268,12 +268,12 @@ static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context)
int offset;
u32 ret;
spin_lock_irqsave(&sch->lock, flags);
raw_spin_lock_irqsave(&sch->lock, flags);
core_status = ioread32(sch->regs + CORE_BANK_OFFSET + GTS);
resume_status = ioread32(sch->regs + RESUME_BANK_OFFSET + GTS);
spin_unlock_irqrestore(&sch->lock, flags);
raw_spin_unlock_irqrestore(&sch->lock, flags);
pending = (resume_status << sch->resume_base) | core_status;
for_each_set_bit(offset, &pending, sch->chip.ngpio)
@@ -343,7 +343,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
sch->regs = regs;
spin_lock_init(&sch->lock);
raw_spin_lock_init(&sch->lock);
sch->chip = sch_gpio_chip;
sch->chip.label = dev_name(dev);
sch->chip.parent = dev;

View File

@@ -33,6 +33,7 @@
/**
* struct tb10x_gpio - TB10x GPIO controller structure
* @base: register base address
* @domain: IRQ domain of GPIO generated interrupts managed by this controller
* @irq: Interrupt line of parent interrupt controller

View File

@@ -172,18 +172,11 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
int ret;
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 0);
tegra_gpio_enable(tgi, offset);
ret = pinctrl_gpio_direction_input(chip, offset);
if (ret < 0)
dev_err(tgi->dev,
"Failed to set pinctrl input direction of GPIO %d: %d",
chip->base + offset, ret);
return ret;
return 0;
}
static int tegra_gpio_direction_output(struct gpio_chip *chip,
@@ -191,19 +184,12 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip,
int value)
{
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
int ret;
tegra_gpio_set(chip, offset, value);
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 1);
tegra_gpio_enable(tgi, offset);
ret = pinctrl_gpio_direction_output(chip, offset);
if (ret < 0)
dev_err(tgi->dev,
"Failed to set pinctrl output direction of GPIO %d: %d",
chip->base + offset, ret);
return ret;
return 0;
}
static int tegra_gpio_get_direction(struct gpio_chip *chip,

View File

@@ -229,12 +229,23 @@ static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
event->irq_requested = true;
/* Make sure we trigger the initial state of edge-triggered IRQs */
/*
* Make sure we trigger the initial state of ActiveBoth IRQs.
*
* According to the Microsoft GPIO documentation, triggering GPIO
* interrupts marked as ActiveBoth during initialization is correct
* as long as the associated GPIO line is already "asserted"
* (logic level low). We should not trigger edge-based GPIO
* interrupts not marked as ActiveBoth.
*
* See: https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/general-purpose-i-o--gpio-
* Section: "GPIO controllers and ActiveBoth interrupts"
*/
if (acpi_gpio_need_run_edge_events_on_boot() &&
(event->irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
((event->irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) ==
(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
value = gpiod_get_raw_value_cansleep(event->desc);
if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
if (value == 0)
event->handler(event->irq, event);
}
}
@@ -305,10 +316,17 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
unsigned int index,
const char *label)
{
int polarity = GPIO_ACTIVE_HIGH;
enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
unsigned int pin = agpio->pin_table[index];
enum gpiod_flags flags;
struct gpio_desc *desc;
unsigned int pin;
int polarity;
if (index >= agpio->pin_table_length)
return ERR_PTR(-EINVAL);
pin = agpio->pin_table[index];
polarity = GPIO_ACTIVE_HIGH;
flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
if (IS_ERR(desc))
@@ -322,7 +340,12 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
static bool acpi_gpio_irq_is_wake(struct device *parent,
const struct acpi_resource_gpio *agpio)
{
unsigned int pin = agpio->pin_table[0];
unsigned int pin;
if (agpio->pin_table_length == 0)
return false;
pin = agpio->pin_table[0];
if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
return false;
@@ -352,6 +375,9 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
if (!acpi_gpio_get_irq_resource(ares, &agpio))
return AE_OK;
if (agpio->pin_table_length == 0)
return AE_OK;
handle = ACPI_HANDLE(chip->parent);
pin = agpio->pin_table[0];
@@ -1072,10 +1098,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
struct gpio_chip *chip = achip->chip;
struct acpi_resource_gpio *agpio;
struct acpi_resource *ares;
u16 pin_index = address;
unsigned int length;
acpi_status status;
int length;
int i;
unsigned int i;
u16 pin_index;
status = acpi_buffer_to_resource(achip->conn_info.connection,
achip->conn_info.length, &ares);
@@ -1095,7 +1121,14 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
return AE_BAD_PARAMETER;
}
length = min(agpio->pin_table_length, pin_index + bits);
/* address represents GPIO pin index in connection table */
if (address >= agpio->pin_table_length) {
ACPI_FREE(ares);
return AE_BAD_PARAMETER;
}
pin_index = address;
length = min_t(unsigned int, agpio->pin_table_length, pin_index + bits);
for (i = pin_index; i < length; ++i) {
unsigned int pin = agpio->pin_table[i];
struct acpi_gpio_connection *conn;

View File

@@ -3803,7 +3803,7 @@ static int gpiochip_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
unsigned int i;
int ret;
int ret = 0;
lockdep_assert_held(&gc->gpiodev->srcu);