summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-25 09:33:23 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-25 09:33:23 -0700
commit962528fef90253aeded29cee20a9b6ff3595fed4 (patch)
tree69f2373365d74da31f90a8ba4aec7dd47fb80717 /drivers
parentec85be724c5c0c2cc392f5681b45da0403ea60ec (diff)
parent4e8eb6952aa6749726c6c3763ae0032a6332c24f (diff)
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
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/gpio-davinci.c4
-rw-r--r--drivers/gpio/gpio-eic-sprd.c8
-rw-r--r--drivers/gpio/gpio-mlxbf3.c3
-rw-r--r--drivers/gpio/gpio-pisosr.c4
-rw-r--r--drivers/gpio/gpio-sch.c32
-rw-r--r--drivers/gpio/gpio-tb10x.c1
-rw-r--r--drivers/gpio/gpio-tegra.c18
-rw-r--r--drivers/gpio/gpiolib-acpi-core.c57
-rw-r--r--drivers/gpio/gpiolib.c2
9 files changed, 77 insertions, 52 deletions
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 97780f27ce5b..270cd7c88812 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -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;
diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
index 50fafeda8d7e..3b7ebcf12fe7 100644
--- a/drivers/gpio/gpio-eic-sprd.c
+++ b/drivers/gpio/gpio-eic-sprd.c
@@ -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);
diff --git a/drivers/gpio/gpio-mlxbf3.c b/drivers/gpio/gpio-mlxbf3.c
index 4770578269ba..566326644a2c 100644
--- a/drivers/gpio/gpio-mlxbf3.c
+++ b/drivers/gpio/gpio-mlxbf3.c
@@ -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;
}
diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c
index 7ec6a46ed600..2732ea8c16b7 100644
--- a/drivers/gpio/gpio-pisosr.c
+++ b/drivers/gpio/gpio-pisosr.c
@@ -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;
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 966d16a6d515..5e361742a11a 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -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;
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 3c8fd322a713..705bfd80a8d0 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -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
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index df06b56a2ade..fa6c8ee92093 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -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,
diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index fbd6945726bf..220f0ac4204e 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -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;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 8a5ff78a1149..e5fb60111151 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -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);