mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support
@ 2026-05-18  7:53 Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 01/12] gpiolib: acpi: Use snprintf() for ACPI event name formatting Marco Scardovi (scardracs)
                   ` (12 more replies)
  0 siblings, 13 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Good morning everyone,

This patch series took fairly a bit of time because, well, it ended up going a "bit"
out of hand. It improves style, robustness, resource safety, and modularity
of the ACPI GPIO subsystem. The massive gpiolib-acpi-core.c driver (previously
well over 1400 lines) has been significantly refactored, reducing its footprint
by separating concerns into distinct, dedicated modules for ACPI Operation Region
handling and ACPI Event/Interrupt processing.

Key changes and structure of the series:
1. Hardening & Correctness (Patches 1-4):
   - Style adjustments to match Linux Kernel coding standard.
   - Modernized parsing in quirks using standard sysfs/kstrto helpers.
   - Added robust bounds checking for ACPI GPIO resource pin ranges.
   - Fixed a critical memory resource leak in the OpRegion cleanup path.

2. ACPI Operation Region Modularization (Patches 5-9):
   - Declared shared data structures in the local header.
   - Exposed private-to-core registration helpers by making them non-static.
   - Extracted Operation Region handling logic to gpiolib-acpi-opregion.c.
   - Diverted callback registration to the new OpRegion module.
   - Removed the unused static emulation handlers from the core driver.

3. ACPI Event & Interrupt Handling Modularization (Patches 10-12):
   - Declared shared helper prototypes in the local header.
   - Extracted Event/Interrupt logic to gpiolib-acpi-events.c.
   - Fully decoupled static event handlers and event structures from the core.

Build correctness and functional behavior were validated on x86 virtual
platforms using virtme-ng under KASAN and kmemleak with successful boot,
execution, and zero resource leaks.

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>

Marco Scardovi (scardracs) (12):
  gpiolib: acpi: Fix style and formatting issues in core
  gpiolib: acpi: Modernize string parsing in quirks layer
  gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  gpiolib: acpi: Fix resource leak in OpRegion cleanup path
  gpiolib: acpi: Declare shared structures in gpiolib-acpi.h
  gpiolib: acpi: Expose core GPIO resource and OpRegion helpers
  gpiolib: acpi: Add dedicated Operation Region module
  gpiolib: acpi: Divert OpRegion registration callbacks from core
  gpiolib: acpi: Remove unused static address space emulation from core
  gpiolib: acpi: Declare shared event helpers in gpiolib-acpi.h
  gpiolib: acpi: Add dedicated ACPI GPIO events module
  gpiolib: acpi: Decouple Event and Interrupt handling from core

 drivers/gpio/Makefile                |   2 +-
 drivers/gpio/gpiolib-acpi-core.c     | 488 +--------------------------
 drivers/gpio/gpiolib-acpi-events.c   | 309 +++++++++++++++++
 drivers/gpio/gpiolib-acpi-opregion.c | 175 ++++++++++
 drivers/gpio/gpiolib-acpi-quirks.c   |  23 +-
 drivers/gpio/gpiolib-acpi.h          |  50 ++-
 6 files changed, 561 insertions(+), 486 deletions(-)
 create mode 100644 drivers/gpio/gpiolib-acpi-events.c
 create mode 100644 drivers/gpio/gpiolib-acpi-opregion.c

-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 01/12] gpiolib: acpi: Use snprintf() for ACPI event name formatting
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  8:07   ` Andy Shevchenko
  2026-05-18  7:53 ` [PATCH 02/12] gpiolib: acpi: Modernize string parsing in quirks layer Marco Scardovi (scardracs)
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Replace sprintf() with snprintf() when formatting ACPI GPIO
event names and fix minor formatting inconsistencies.

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index eb8a40cfb7a9..64040b098e91 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -372,9 +372,10 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
 
 	if (pin <= 255) {
 		char ev_name[8];
-		sprintf(ev_name, "_%c%02X",
-			agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
-			pin);
+
+		snprintf(ev_name, sizeof(ev_name), "_%c%02X",
+			 agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
+			 pin);
 		if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
 			handler = acpi_gpio_irq_handler;
 	}
@@ -645,7 +646,7 @@ __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
 }
 
 static int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
-				        struct acpi_gpio_info *info)
+					struct acpi_gpio_info *info)
 {
 	struct device *dev = &info->adev->dev;
 	enum gpiod_flags old = *flags;
@@ -1206,7 +1207,7 @@ static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
 						    NULL, achip);
 	if (ACPI_FAILURE(status))
 		dev_err(chip->parent,
-		        "Failed to install GPIO OpRegion handler\n");
+			"Failed to install GPIO OpRegion handler\n");
 }
 
 static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 02/12] gpiolib: acpi: Modernize string parsing in quirks layer
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 01/12] gpiolib: acpi: Use snprintf() for ACPI event name formatting Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  8:11   ` Andy Shevchenko
  2026-05-18  7:53 ` [PATCH 03/12] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-quirks.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-quirks.c b/drivers/gpio/gpiolib-acpi-quirks.c
index a0116f004975..761ef49b5314 100644
--- a/drivers/gpio/gpiolib-acpi-quirks.c
+++ b/drivers/gpio/gpiolib-acpi-quirks.c
@@ -24,14 +24,12 @@ MODULE_PARM_DESC(run_edge_events_on_boot,
 static char *ignore_wake;
 module_param(ignore_wake, charp, 0444);
 MODULE_PARM_DESC(ignore_wake,
-		 "controller@pin combos on which to ignore the ACPI wake flag "
-		 "ignore_wake=controller@pin[,controller@pin[,...]]");
+		 "controller@pin combos on which to ignore the ACPI wake flag ignore_wake=controller@pin[,controller@pin[,...]]");
 
 static char *ignore_interrupt;
 module_param(ignore_interrupt, charp, 0444);
 MODULE_PARM_DESC(ignore_interrupt,
-		 "controller@pin combos on which to ignore interrupt "
-		 "ignore_interrupt=controller@pin[,controller@pin[,...]]");
+		 "controller@pin combos on which to ignore interrupt ignore_interrupt=controller@pin[,controller@pin[,...]]");
 
 /*
  * For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
@@ -75,7 +73,6 @@ bool acpi_gpio_in_ignore_list(enum acpi_gpio_ignore_list list,
 {
 	const char *ignore_list, *controller, *pin_str;
 	unsigned int pin;
-	char *endp;
 	int len;
 
 	switch (list) {
@@ -98,8 +95,20 @@ bool acpi_gpio_in_ignore_list(enum acpi_gpio_ignore_list list,
 		len = pin_str - controller;
 		if (len == strlen(controller_in) &&
 		    strncmp(controller, controller_in, len) == 0) {
-			pin = simple_strtoul(pin_str + 1, &endp, 10);
-			if (*endp != 0 && *endp != ',')
+			char pin_buf[16];
+			size_t pin_len = 0;
+			const char *p = pin_str + 1;
+
+			while (*p && *p != ',') {
+				if (pin_len < sizeof(pin_buf) - 1)
+					pin_buf[pin_len++] = *p;
+				else
+					goto err;
+				p++;
+			}
+			pin_buf[pin_len] = '\0';
+
+			if (kstrtouint(pin_buf, 10, &pin))
 				goto err;
 
 			if (pin == pin_in)
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 03/12] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 01/12] gpiolib: acpi: Use snprintf() for ACPI event name formatting Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 02/12] gpiolib: acpi: Modernize string parsing in quirks layer Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18 10:33   ` Mika Westerberg
  2026-05-18  7:53 ` [PATCH 04/12] gpiolib: acpi: Fix resource leak in OpRegion cleanup path Marco Scardovi (scardracs)
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 64040b098e91..90bda2d7da57 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -322,9 +322,14 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
 {
 	int polarity = GPIO_ACTIVE_HIGH;
 	enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
-	unsigned int pin = agpio->pin_table[index];
+	unsigned int pin;
 	struct gpio_desc *desc;
 
+	if (index >= agpio->pin_table_length)
+		return ERR_PTR(-EINVAL);
+
+	pin = agpio->pin_table[index];
+
 	desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
 	if (IS_ERR(desc))
 		return desc;
@@ -337,7 +342,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;
@@ -367,6 +377,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];
 
@@ -1111,6 +1124,11 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 		return AE_BAD_PARAMETER;
 	}
 
+	if (pin_index >= agpio->pin_table_length) {
+		ACPI_FREE(ares);
+		return AE_BAD_PARAMETER;
+	}
+
 	length = min(agpio->pin_table_length, pin_index + bits);
 	for (i = pin_index; i < length; ++i) {
 		unsigned int pin = agpio->pin_table[i];
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 04/12] gpiolib: acpi: Fix resource leak in OpRegion cleanup path
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (2 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 03/12] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 05/12] gpiolib: acpi: Declare shared structures in gpiolib-acpi.h Marco Scardovi (scardracs)
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 90bda2d7da57..4c8cd2038aa1 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -1240,7 +1240,6 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
 	if (ACPI_FAILURE(status)) {
 		dev_err(chip->parent,
 			"Failed to remove GPIO OpRegion handler\n");
-		return;
 	}
 
 	list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 05/12] gpiolib: acpi: Declare shared structures in gpiolib-acpi.h
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (3 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 04/12] gpiolib: acpi: Fix resource leak in OpRegion cleanup path Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  8:21   ` Andy Shevchenko
  2026-05-18  7:53 ` [PATCH 06/12] gpiolib: acpi: Expose core GPIO resource and OpRegion helpers Marco Scardovi (scardracs)
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 43 --------------------------------
 drivers/gpio/gpiolib-acpi.h      | 39 +++++++++++++++++++++++++++--
 2 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 4c8cd2038aa1..7217ec5c7fae 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -23,50 +23,7 @@
 #include "gpiolib.h"
 #include "gpiolib-acpi.h"
 
-/**
- * struct acpi_gpio_event - ACPI GPIO event handler data
- *
- * @node:	  list-entry of the events list of the struct acpi_gpio_chip
- * @handle:	  handle of ACPI method to execute when the IRQ triggers
- * @handler:	  handler function to pass to request_irq() when requesting the IRQ
- * @pin:	  GPIO pin number on the struct gpio_chip
- * @irq:	  Linux IRQ number for the event, for request_irq() / free_irq()
- * @irqflags:	  flags to pass to request_irq() when requesting the IRQ
- * @irq_is_wake:  If the ACPI flags indicate the IRQ is a wakeup source
- * @irq_requested:True if request_irq() has been done
- * @desc:	  struct gpio_desc for the GPIO pin for this event
- */
-struct acpi_gpio_event {
-	struct list_head node;
-	acpi_handle handle;
-	irq_handler_t handler;
-	unsigned int pin;
-	unsigned int irq;
-	unsigned long irqflags;
-	bool irq_is_wake;
-	bool irq_requested;
-	struct gpio_desc *desc;
-};
 
-struct acpi_gpio_connection {
-	struct list_head node;
-	unsigned int pin;
-	struct gpio_desc *desc;
-};
-
-struct acpi_gpio_chip {
-	/*
-	 * ACPICA requires that the first field of the context parameter
-	 * passed to acpi_install_address_space_handler() is large enough
-	 * to hold struct acpi_connection_info.
-	 */
-	struct acpi_connection_info conn_info;
-	struct list_head conns;
-	struct mutex conn_lock;
-	struct gpio_chip *chip;
-	struct list_head events;
-	struct list_head deferred_req_irqs_list_entry;
-};
 
 /**
  * struct acpi_gpio_info - ACPI GPIO specific information
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
index a90267470a4e..bd857ead9dcc 100644
--- a/drivers/gpio/gpiolib-acpi.h
+++ b/drivers/gpio/gpiolib-acpi.h
@@ -8,10 +8,13 @@
 #ifndef GPIOLIB_ACPI_H
 #define GPIOLIB_ACPI_H
 
+#include <linux/acpi.h>
 #include <linux/err.h>
-#include <linux/types.h>
-
 #include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
 
 struct device;
 struct fwnode_handle;
@@ -20,6 +23,38 @@ struct gpio_chip;
 struct gpio_desc;
 struct gpio_device;
 
+struct acpi_gpio_event {
+	struct list_head node;
+	acpi_handle handle;
+	irq_handler_t handler;
+	unsigned int pin;
+	unsigned int irq;
+	unsigned long irqflags;
+	bool irq_is_wake;
+	bool irq_requested;
+	struct gpio_desc *desc;
+};
+
+struct acpi_gpio_connection {
+	struct list_head node;
+	unsigned int pin;
+	struct gpio_desc *desc;
+};
+
+struct acpi_gpio_chip {
+	/*
+	 * ACPICA requires that the first field of the context parameter
+	 * passed to acpi_install_address_space_handler() is large enough
+	 * to hold struct acpi_connection_info.
+	 */
+	struct acpi_connection_info conn_info;
+	struct list_head conns;
+	struct mutex conn_lock;
+	struct gpio_chip *chip;
+	struct list_head events;
+	struct list_head deferred_req_irqs_list_entry;
+};
+
 #ifdef CONFIG_ACPI
 void acpi_gpiochip_add(struct gpio_chip *chip);
 void acpi_gpiochip_remove(struct gpio_chip *chip);
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 06/12] gpiolib: acpi: Expose core GPIO resource and OpRegion helpers
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (4 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 05/12] gpiolib: acpi: Declare shared structures in gpiolib-acpi.h Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 07/12] gpiolib: acpi: Add dedicated Operation Region module Marco Scardovi (scardracs)
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 12 ++++++------
 drivers/gpio/gpiolib-acpi.h      |  8 ++++++++
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 7217ec5c7fae..afd76301c41f 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -272,10 +272,10 @@ static void acpi_gpio_set_debounce_timeout(struct gpio_desc *desc,
 			   acpi_debounce, ret);
 }
 
-static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
-						struct acpi_resource_gpio *agpio,
-						unsigned int index,
-						const char *label)
+struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
+					 struct acpi_resource_gpio *agpio,
+					 unsigned int index,
+					 const char *label)
 {
 	int polarity = GPIO_ACTIVE_HIGH;
 	enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
@@ -1169,7 +1169,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 	return status;
 }
 
-static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
+void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
 {
 	struct gpio_chip *chip = achip->chip;
 	acpi_handle handle = ACPI_HANDLE(chip->parent);
@@ -1185,7 +1185,7 @@ static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
 			"Failed to install GPIO OpRegion handler\n");
 }
 
-static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
+void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
 {
 	struct gpio_chip *chip = achip->chip;
 	acpi_handle handle = ACPI_HANDLE(chip->parent);
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
index bd857ead9dcc..6729da5a6fb7 100644
--- a/drivers/gpio/gpiolib-acpi.h
+++ b/drivers/gpio/gpiolib-acpi.h
@@ -55,6 +55,14 @@ struct acpi_gpio_chip {
 	struct list_head deferred_req_irqs_list_entry;
 };
 
+struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
+					 struct acpi_resource_gpio *agpio,
+					 unsigned int index,
+					 const char *label);
+
+void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip);
+void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip);
+
 #ifdef CONFIG_ACPI
 void acpi_gpiochip_add(struct gpio_chip *chip);
 void acpi_gpiochip_remove(struct gpio_chip *chip);
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 07/12] gpiolib: acpi: Add dedicated Operation Region module
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (5 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 06/12] gpiolib: acpi: Expose core GPIO resource and OpRegion helpers Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 08/12] gpiolib: acpi: Divert OpRegion registration callbacks from core Marco Scardovi (scardracs)
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/Makefile                |   2 +-
 drivers/gpio/gpiolib-acpi-opregion.c | 175 +++++++++++++++++++++++++++
 2 files changed, 176 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpio/gpiolib-acpi-opregion.c

diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b267598b517d..1a416305465b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_OF_GPIO)		+= gpiolib-of.o
 obj-$(CONFIG_GPIO_CDEV)		+= gpiolib-cdev.o
 obj-$(CONFIG_GPIO_SYSFS)	+= gpiolib-sysfs.o
 obj-$(CONFIG_GPIO_ACPI)		+= gpiolib-acpi.o
-gpiolib-acpi-y			:= gpiolib-acpi-core.o gpiolib-acpi-quirks.o
+gpiolib-acpi-y			:= gpiolib-acpi-core.o gpiolib-acpi-quirks.o gpiolib-acpi-opregion.o
 obj-$(CONFIG_GPIOLIB)		+= gpiolib-swnode.o
 obj-$(CONFIG_GPIO_SHARED)	+= gpiolib-shared.o
 
diff --git a/drivers/gpio/gpiolib-acpi-opregion.c b/drivers/gpio/gpiolib-acpi-opregion.c
new file mode 100644
index 000000000000..77b1ee32ddce
--- /dev/null
+++ b/drivers/gpio/gpiolib-acpi-opregion.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ACPI Operation Region helper for GPIO API
+ *
+ * Copyright (C) 2026, Intel Corporation
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/mutex.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+
+#include "gpiolib.h"
+#include "gpiolib-acpi.h"
+
+static acpi_status
+acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
+			    u32 bits, u64 *value, void *handler_context,
+			    void *region_context)
+{
+	struct acpi_gpio_chip *achip = region_context;
+	struct gpio_chip *chip = achip->chip;
+	struct acpi_resource_gpio *agpio;
+	struct acpi_resource *ares;
+	u16 pin_index = address;
+	acpi_status status;
+	int length;
+	int i;
+
+	status = acpi_buffer_to_resource(achip->conn_info.connection,
+					 achip->conn_info.length, &ares);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
+		ACPI_FREE(ares);
+		return AE_BAD_PARAMETER;
+	}
+
+	agpio = &ares->data.gpio;
+
+	if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
+	    function == ACPI_WRITE)) {
+		ACPI_FREE(ares);
+		return AE_BAD_PARAMETER;
+	}
+
+	if (pin_index >= agpio->pin_table_length) {
+		ACPI_FREE(ares);
+		return AE_BAD_PARAMETER;
+	}
+
+	length = min(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;
+		struct gpio_desc *desc;
+		u16 word, shift;
+		bool found;
+
+		mutex_lock(&achip->conn_lock);
+
+		found = false;
+		list_for_each_entry(conn, &achip->conns, node) {
+			if (conn->pin == pin) {
+				found = true;
+				desc = conn->desc;
+				break;
+			}
+		}
+
+		/*
+		 * The same GPIO can be shared between operation region and
+		 * event but only if the access here is ACPI_READ. In that
+		 * case we "borrow" the event GPIO instead.
+		 */
+		if (!found && agpio->shareable == ACPI_SHARED &&
+		     function == ACPI_READ) {
+			struct acpi_gpio_event *event;
+
+			list_for_each_entry(event, &achip->events, node) {
+				if (event->pin == pin) {
+					desc = event->desc;
+					found = true;
+					break;
+				}
+			}
+		}
+
+		if (!found) {
+			desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
+			if (IS_ERR(desc)) {
+				mutex_unlock(&achip->conn_lock);
+				status = AE_ERROR;
+				goto out;
+			}
+
+			conn = kzalloc_obj(*conn);
+			if (!conn) {
+				gpiochip_free_own_desc(desc);
+				mutex_unlock(&achip->conn_lock);
+				status = AE_NO_MEMORY;
+				goto out;
+			}
+
+			conn->pin = pin;
+			conn->desc = desc;
+			list_add_tail(&conn->node, &achip->conns);
+		}
+
+		mutex_unlock(&achip->conn_lock);
+
+		/*
+		 * For the cases when OperationRegion() consists of more than
+		 * 64 bits calculate the word and bit shift to use that one to
+		 * access the value.
+		 */
+		word = i / 64;
+		shift = i % 64;
+
+		if (function == ACPI_WRITE) {
+			gpiod_set_raw_value_cansleep(desc, value[word] & BIT_ULL(shift));
+		} else {
+			if (gpiod_get_raw_value_cansleep(desc))
+				value[word] |= BIT_ULL(shift);
+			else
+				value[word] &= ~BIT_ULL(shift);
+		}
+	}
+
+out:
+	ACPI_FREE(ares);
+	return status;
+}
+
+void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
+{
+	struct gpio_chip *chip = achip->chip;
+	acpi_handle handle = ACPI_HANDLE(chip->parent);
+	acpi_status status;
+
+	INIT_LIST_HEAD(&achip->conns);
+	mutex_init(&achip->conn_lock);
+
+	status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
+						    acpi_gpio_adr_space_handler,
+						    NULL, achip);
+	if (ACPI_FAILURE(status))
+		dev_err(chip->parent,
+			"Failed to install GPIO OpRegion handler\n");
+}
+
+void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
+{
+	struct gpio_chip *chip = achip->chip;
+	acpi_handle handle = ACPI_HANDLE(chip->parent);
+	struct acpi_gpio_connection *conn, *tmp;
+	acpi_status status;
+
+	status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
+						   acpi_gpio_adr_space_handler);
+	if (ACPI_FAILURE(status)) {
+		dev_err(chip->parent,
+			"Failed to remove GPIO OpRegion handler\n");
+	}
+
+	list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
+		gpiochip_free_own_desc(conn->desc);
+		list_del(&conn->node);
+		kfree(conn);
+	}
+}
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 08/12] gpiolib: acpi: Divert OpRegion registration callbacks from core
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (6 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 07/12] gpiolib: acpi: Add dedicated Operation Region module Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 09/12] gpiolib: acpi: Remove unused static address space emulation " Marco Scardovi (scardracs)
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 36 --------------------------------
 1 file changed, 36 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index afd76301c41f..4802d4948f89 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -1169,42 +1169,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 	return status;
 }
 
-void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
-{
-	struct gpio_chip *chip = achip->chip;
-	acpi_handle handle = ACPI_HANDLE(chip->parent);
-	acpi_status status;
-
-	INIT_LIST_HEAD(&achip->conns);
-	mutex_init(&achip->conn_lock);
-	status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
-						    acpi_gpio_adr_space_handler,
-						    NULL, achip);
-	if (ACPI_FAILURE(status))
-		dev_err(chip->parent,
-			"Failed to install GPIO OpRegion handler\n");
-}
-
-void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
-{
-	struct gpio_chip *chip = achip->chip;
-	acpi_handle handle = ACPI_HANDLE(chip->parent);
-	struct acpi_gpio_connection *conn, *tmp;
-	acpi_status status;
-
-	status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
-						   acpi_gpio_adr_space_handler);
-	if (ACPI_FAILURE(status)) {
-		dev_err(chip->parent,
-			"Failed to remove GPIO OpRegion handler\n");
-	}
-
-	list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
-		gpiochip_free_own_desc(conn->desc);
-		list_del(&conn->node);
-		kfree(conn);
-	}
-}
 
 void acpi_gpiochip_add(struct gpio_chip *chip)
 {
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 09/12] gpiolib: acpi: Remove unused static address space emulation from core
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (7 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 08/12] gpiolib: acpi: Divert OpRegion registration callbacks from core Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 10/12] gpiolib: acpi: Declare shared event helpers in gpiolib-acpi.h Marco Scardovi (scardracs)
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 120 -------------------------------
 1 file changed, 120 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 4802d4948f89..b8976a0c798e 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -1049,126 +1049,6 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id,
 }
 EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_wake_get_by);
 
-static acpi_status
-acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
-			    u32 bits, u64 *value, void *handler_context,
-			    void *region_context)
-{
-	struct acpi_gpio_chip *achip = region_context;
-	struct gpio_chip *chip = achip->chip;
-	struct acpi_resource_gpio *agpio;
-	struct acpi_resource *ares;
-	u16 pin_index = address;
-	acpi_status status;
-	int length;
-	int i;
-
-	status = acpi_buffer_to_resource(achip->conn_info.connection,
-					 achip->conn_info.length, &ares);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
-		ACPI_FREE(ares);
-		return AE_BAD_PARAMETER;
-	}
-
-	agpio = &ares->data.gpio;
-
-	if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
-	    function == ACPI_WRITE)) {
-		ACPI_FREE(ares);
-		return AE_BAD_PARAMETER;
-	}
-
-	if (pin_index >= agpio->pin_table_length) {
-		ACPI_FREE(ares);
-		return AE_BAD_PARAMETER;
-	}
-
-	length = min(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;
-		struct gpio_desc *desc;
-		u16 word, shift;
-		bool found;
-
-		mutex_lock(&achip->conn_lock);
-
-		found = false;
-		list_for_each_entry(conn, &achip->conns, node) {
-			if (conn->pin == pin) {
-				found = true;
-				desc = conn->desc;
-				break;
-			}
-		}
-
-		/*
-		 * The same GPIO can be shared between operation region and
-		 * event but only if the access here is ACPI_READ. In that
-		 * case we "borrow" the event GPIO instead.
-		 */
-		if (!found && agpio->shareable == ACPI_SHARED &&
-		     function == ACPI_READ) {
-			struct acpi_gpio_event *event;
-
-			list_for_each_entry(event, &achip->events, node) {
-				if (event->pin == pin) {
-					desc = event->desc;
-					found = true;
-					break;
-				}
-			}
-		}
-
-		if (!found) {
-			desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
-			if (IS_ERR(desc)) {
-				mutex_unlock(&achip->conn_lock);
-				status = AE_ERROR;
-				goto out;
-			}
-
-			conn = kzalloc_obj(*conn);
-			if (!conn) {
-				gpiochip_free_own_desc(desc);
-				mutex_unlock(&achip->conn_lock);
-				status = AE_NO_MEMORY;
-				goto out;
-			}
-
-			conn->pin = pin;
-			conn->desc = desc;
-			list_add_tail(&conn->node, &achip->conns);
-		}
-
-		mutex_unlock(&achip->conn_lock);
-
-		/*
-		 * For the cases when OperationRegion() consists of more than
-		 * 64 bits calculate the word and bit shift to use that one to
-		 * access the value.
-		 */
-		word = i / 64;
-		shift = i % 64;
-
-		if (function == ACPI_WRITE) {
-			gpiod_set_raw_value_cansleep(desc, value[word] & BIT_ULL(shift));
-		} else {
-			if (gpiod_get_raw_value_cansleep(desc))
-				value[word] |= BIT_ULL(shift);
-			else
-				value[word] &= ~BIT_ULL(shift);
-		}
-	}
-
-out:
-	ACPI_FREE(ares);
-	return status;
-}
-
 
 void acpi_gpiochip_add(struct gpio_chip *chip)
 {
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 10/12] gpiolib: acpi: Declare shared event helpers in gpiolib-acpi.h
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (8 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 09/12] gpiolib: acpi: Remove unused static address space emulation " Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 11/12] gpiolib: acpi: Add dedicated ACPI GPIO events module Marco Scardovi (scardracs)
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
index 6729da5a6fb7..d209a4edb936 100644
--- a/drivers/gpio/gpiolib-acpi.h
+++ b/drivers/gpio/gpiolib-acpi.h
@@ -63,6 +63,9 @@ struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
 void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip);
 void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip);
 
+void acpi_gpio_chip_dh(acpi_handle handle, void *data);
+bool acpi_gpio_irq_is_wake(struct device *parent,
+			   const struct acpi_resource_gpio *agpio);
 #ifdef CONFIG_ACPI
 void acpi_gpiochip_add(struct gpio_chip *chip);
 void acpi_gpiochip_remove(struct gpio_chip *chip);
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 11/12] gpiolib: acpi: Add dedicated ACPI GPIO events module
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (9 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 10/12] gpiolib: acpi: Declare shared event helpers in gpiolib-acpi.h Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  7:53 ` [PATCH 12/12] gpiolib: acpi: Decouple Event and Interrupt handling from core Marco Scardovi (scardracs)
  2026-05-18  8:19 ` [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Andy Shevchenko
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/Makefile              |   2 +-
 drivers/gpio/gpiolib-acpi-events.c | 309 +++++++++++++++++++++++++++++
 2 files changed, 310 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpio/gpiolib-acpi-events.c

diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1a416305465b..75b38577b328 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_OF_GPIO)		+= gpiolib-of.o
 obj-$(CONFIG_GPIO_CDEV)		+= gpiolib-cdev.o
 obj-$(CONFIG_GPIO_SYSFS)	+= gpiolib-sysfs.o
 obj-$(CONFIG_GPIO_ACPI)		+= gpiolib-acpi.o
-gpiolib-acpi-y			:= gpiolib-acpi-core.o gpiolib-acpi-quirks.o gpiolib-acpi-opregion.o
+gpiolib-acpi-y			:= gpiolib-acpi-core.o gpiolib-acpi-quirks.o gpiolib-acpi-opregion.o gpiolib-acpi-events.o
 obj-$(CONFIG_GPIOLIB)		+= gpiolib-swnode.o
 obj-$(CONFIG_GPIO_SHARED)	+= gpiolib-shared.o
 
diff --git a/drivers/gpio/gpiolib-acpi-events.c b/drivers/gpio/gpiolib-acpi-events.c
new file mode 100644
index 000000000000..317528a25c92
--- /dev/null
+++ b/drivers/gpio/gpiolib-acpi-events.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ACPI Event and Interrupt helper for GPIO API
+ *
+ * Copyright (C) 2026, Intel Corporation
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include "gpiolib.h"
+#include "gpiolib-acpi.h"
+
+static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
+{
+	struct acpi_gpio_event *event = data;
+
+	acpi_evaluate_object(event->handle, NULL, NULL, NULL);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
+{
+	struct acpi_gpio_event *event = data;
+
+	acpi_execute_simple_method(event->handle, NULL, event->pin);
+
+	return IRQ_HANDLED;
+}
+
+static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
+				      struct acpi_gpio_event *event)
+{
+	struct device *parent = acpi_gpio->chip->parent;
+	int ret, value;
+
+	ret = request_threaded_irq(event->irq, NULL, event->handler,
+				   event->irqflags | IRQF_ONESHOT, "ACPI:Event", event);
+	if (ret) {
+		dev_err(parent, "Failed to setup interrupt handler for %d\n", event->irq);
+		return;
+	}
+
+	if (event->irq_is_wake)
+		enable_irq_wake(event->irq);
+
+	event->irq_requested = true;
+
+	/*
+	 * 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)) ==
+	     (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
+		value = gpiod_get_raw_value_cansleep(event->desc);
+		if (value == 0)
+			event->handler(event->irq, event);
+	}
+}
+
+static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
+{
+	struct acpi_gpio_event *event;
+
+	list_for_each_entry(event, &acpi_gpio->events, node)
+		acpi_gpiochip_request_irq(acpi_gpio, event);
+}
+
+bool acpi_gpio_irq_is_wake(struct device *parent,
+			   const struct acpi_resource_gpio *agpio)
+{
+	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;
+
+	if (acpi_gpio_in_ignore_list(ACPI_GPIO_IGNORE_WAKE, dev_name(parent), pin)) {
+		dev_info(parent, "Ignoring wakeup on pin %u\n", pin);
+		return false;
+	}
+
+	return true;
+}
+
+/* Always returns AE_OK so that we keep looping over the resources */
+static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
+					     void *context)
+{
+	struct acpi_gpio_chip *acpi_gpio = context;
+	struct gpio_chip *chip = acpi_gpio->chip;
+	struct acpi_resource_gpio *agpio;
+	acpi_handle handle, evt_handle;
+	struct acpi_gpio_event *event;
+	irq_handler_t handler = NULL;
+	struct gpio_desc *desc;
+	unsigned int pin;
+	int ret, irq;
+
+	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];
+
+	if (pin <= 255) {
+		char ev_name[8];
+
+		snprintf(ev_name, sizeof(ev_name), "_%c%02X",
+			 agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
+			 pin);
+		if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
+			handler = acpi_gpio_irq_handler;
+	}
+	if (!handler) {
+		if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
+			handler = acpi_gpio_irq_handler_evt;
+	}
+	if (!handler)
+		return AE_OK;
+
+	if (acpi_gpio_in_ignore_list(ACPI_GPIO_IGNORE_INTERRUPT, dev_name(chip->parent), pin)) {
+		dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin);
+		return AE_OK;
+	}
+
+	desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
+	if (IS_ERR(desc)) {
+		dev_err(chip->parent,
+			"Failed to request GPIO for pin 0x%04X, err %pe\n",
+			pin, desc);
+		return AE_OK;
+	}
+
+	ret = gpiochip_lock_as_irq(chip, pin);
+	if (ret) {
+		dev_err(chip->parent,
+			"Failed to lock GPIO pin 0x%04X as interrupt, err %d\n",
+			pin, ret);
+		goto fail_free_desc;
+	}
+
+	irq = gpiod_to_irq(desc);
+	if (irq < 0) {
+		dev_err(chip->parent,
+			"Failed to translate GPIO pin 0x%04X to IRQ, err %d\n",
+			pin, irq);
+		goto fail_unlock_irq;
+	}
+
+	event = kzalloc_obj(*event);
+	if (!event)
+		goto fail_unlock_irq;
+
+	event->irqflags = IRQF_ONESHOT;
+	if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
+		if (agpio->polarity == ACPI_ACTIVE_HIGH)
+			event->irqflags |= IRQF_TRIGGER_HIGH;
+		else
+			event->irqflags |= IRQF_TRIGGER_LOW;
+	} else {
+		switch (agpio->polarity) {
+		case ACPI_ACTIVE_HIGH:
+			event->irqflags |= IRQF_TRIGGER_RISING;
+			break;
+		case ACPI_ACTIVE_LOW:
+			event->irqflags |= IRQF_TRIGGER_FALLING;
+			break;
+		default:
+			event->irqflags |= IRQF_TRIGGER_RISING |
+					   IRQF_TRIGGER_FALLING;
+			break;
+		}
+	}
+
+	event->handle = evt_handle;
+	event->handler = handler;
+	event->irq = irq;
+	event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
+	event->pin = pin;
+	event->desc = desc;
+
+	list_add_tail(&event->node, &acpi_gpio->events);
+
+	return AE_OK;
+
+fail_unlock_irq:
+	gpiochip_unlock_as_irq(chip, pin);
+fail_free_desc:
+	gpiochip_free_own_desc(desc);
+
+	return AE_OK;
+}
+
+/**
+ * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
+ * @chip:      GPIO chip
+ *
+ * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
+ * handled by ACPI event methods which need to be called from the GPIO
+ * chip's interrupt handler. acpi_gpiochip_request_interrupts() finds out which
+ * GPIO pins have ACPI event methods and assigns interrupt handlers that calls
+ * the ACPI event methods for those pins.
+ */
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
+{
+	struct acpi_gpio_chip *acpi_gpio;
+	acpi_handle handle;
+	acpi_status status;
+
+	if (!chip->parent || !chip->to_irq)
+		return;
+
+	handle = ACPI_HANDLE(chip->parent);
+	if (!handle)
+		return;
+
+	status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+	if (ACPI_FAILURE(status))
+		return;
+
+	if (acpi_quirk_skip_gpio_event_handlers())
+		return;
+
+	acpi_walk_resources(handle, METHOD_NAME__AEI,
+			    acpi_gpiochip_alloc_event, acpi_gpio);
+
+	if (acpi_gpio_add_to_deferred_list(&acpi_gpio->deferred_req_irqs_list_entry))
+		return;
+
+	acpi_gpiochip_request_irqs(acpi_gpio);
+}
+EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
+
+/**
+ * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
+ * @chip:      GPIO chip
+ *
+ * Free interrupts associated with GPIO ACPI event method for the given
+ * GPIO chip.
+ */
+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
+{
+	struct acpi_gpio_chip *acpi_gpio;
+	struct acpi_gpio_event *event, *ep;
+	acpi_handle handle;
+	acpi_status status;
+
+	if (!chip->parent || !chip->to_irq)
+		return;
+
+	handle = ACPI_HANDLE(chip->parent);
+	if (!handle)
+		return;
+
+	status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+	if (ACPI_FAILURE(status))
+		return;
+
+	acpi_gpio_remove_from_deferred_list(&acpi_gpio->deferred_req_irqs_list_entry);
+
+	list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
+		if (event->irq_requested) {
+			if (event->irq_is_wake)
+				disable_irq_wake(event->irq);
+
+			free_irq(event->irq, event);
+		}
+
+		gpiochip_unlock_as_irq(chip, event->pin);
+		gpiochip_free_own_desc(event->desc);
+		list_del(&event->node);
+		kfree(event);
+	}
+}
+EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts);
+
+void __init acpi_gpio_process_deferred_list(struct list_head *list)
+{
+	struct acpi_gpio_chip *acpi_gpio, *tmp;
+
+	list_for_each_entry_safe(acpi_gpio, tmp, list, deferred_req_irqs_list_entry)
+		acpi_gpiochip_request_irqs(acpi_gpio);
+}
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 12/12] gpiolib: acpi: Decouple Event and Interrupt handling from core
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (10 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 11/12] gpiolib: acpi: Add dedicated ACPI GPIO events module Marco Scardovi (scardracs)
@ 2026-05-18  7:53 ` Marco Scardovi (scardracs)
  2026-05-18  8:19 ` [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Andy Shevchenko
  12 siblings, 0 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-18  7:53 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski
  Cc: Mika Westerberg, Andy Shevchenko, linux-gpio, linux-acpi,
	linux-kernel, Marco Scardovi (scardracs)

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 285 +------------------------------
 1 file changed, 1 insertion(+), 284 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index b8976a0c798e..99b7b0409810 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -106,25 +106,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin)
 	return gpio_device_get_desc(gdev, pin);
 }
 
-static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
-{
-	struct acpi_gpio_event *event = data;
-
-	acpi_evaluate_object(event->handle, NULL, NULL, NULL);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
-{
-	struct acpi_gpio_event *event = data;
-
-	acpi_execute_simple_method(event->handle, NULL, event->pin);
-
-	return IRQ_HANDLED;
-}
-
-static void acpi_gpio_chip_dh(acpi_handle handle, void *data)
+void acpi_gpio_chip_dh(acpi_handle handle, void *data)
 {
 	/* The address of this function is used as a key. */
 }
@@ -172,52 +154,7 @@ bool acpi_gpio_get_io_resource(struct acpi_resource *ares,
 }
 EXPORT_SYMBOL_GPL(acpi_gpio_get_io_resource);
 
-static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
-				      struct acpi_gpio_event *event)
-{
-	struct device *parent = acpi_gpio->chip->parent;
-	int ret, value;
-
-	ret = request_threaded_irq(event->irq, NULL, event->handler,
-				   event->irqflags | IRQF_ONESHOT, "ACPI:Event", event);
-	if (ret) {
-		dev_err(parent, "Failed to setup interrupt handler for %d\n", event->irq);
-		return;
-	}
-
-	if (event->irq_is_wake)
-		enable_irq_wake(event->irq);
 
-	event->irq_requested = true;
-
-	/*
-	 * 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)) ==
-	     (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
-		value = gpiod_get_raw_value_cansleep(event->desc);
-		if (value == 0)
-			event->handler(event->irq, event);
-	}
-}
-
-static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
-{
-	struct acpi_gpio_event *event;
-
-	list_for_each_entry(event, &acpi_gpio->events, node)
-		acpi_gpiochip_request_irq(acpi_gpio, event);
-}
 
 static enum gpiod_flags
 acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio, int polarity)
@@ -296,229 +233,9 @@ struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
 	return desc;
 }
 
-static bool acpi_gpio_irq_is_wake(struct device *parent,
-				  const struct acpi_resource_gpio *agpio)
-{
-	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;
-
-	if (acpi_gpio_in_ignore_list(ACPI_GPIO_IGNORE_WAKE, dev_name(parent), pin)) {
-		dev_info(parent, "Ignoring wakeup on pin %u\n", pin);
-		return false;
-	}
 
-	return true;
-}
-
-/* Always returns AE_OK so that we keep looping over the resources */
-static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
-					     void *context)
-{
-	struct acpi_gpio_chip *acpi_gpio = context;
-	struct gpio_chip *chip = acpi_gpio->chip;
-	struct acpi_resource_gpio *agpio;
-	acpi_handle handle, evt_handle;
-	struct acpi_gpio_event *event;
-	irq_handler_t handler = NULL;
-	struct gpio_desc *desc;
-	unsigned int pin;
-	int ret, irq;
-
-	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];
-
-	if (pin <= 255) {
-		char ev_name[8];
-
-		snprintf(ev_name, sizeof(ev_name), "_%c%02X",
-			 agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
-			 pin);
-		if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
-			handler = acpi_gpio_irq_handler;
-	}
-	if (!handler) {
-		if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
-			handler = acpi_gpio_irq_handler_evt;
-	}
-	if (!handler)
-		return AE_OK;
-
-	if (acpi_gpio_in_ignore_list(ACPI_GPIO_IGNORE_INTERRUPT, dev_name(chip->parent), pin)) {
-		dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin);
-		return AE_OK;
-	}
-
-	desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
-	if (IS_ERR(desc)) {
-		dev_err(chip->parent,
-			"Failed to request GPIO for pin 0x%04X, err %pe\n",
-			pin, desc);
-		return AE_OK;
-	}
-
-	ret = gpiochip_lock_as_irq(chip, pin);
-	if (ret) {
-		dev_err(chip->parent,
-			"Failed to lock GPIO pin 0x%04X as interrupt, err %d\n",
-			pin, ret);
-		goto fail_free_desc;
-	}
-
-	irq = gpiod_to_irq(desc);
-	if (irq < 0) {
-		dev_err(chip->parent,
-			"Failed to translate GPIO pin 0x%04X to IRQ, err %d\n",
-			pin, irq);
-		goto fail_unlock_irq;
-	}
-
-	event = kzalloc_obj(*event);
-	if (!event)
-		goto fail_unlock_irq;
-
-	event->irqflags = IRQF_ONESHOT;
-	if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
-		if (agpio->polarity == ACPI_ACTIVE_HIGH)
-			event->irqflags |= IRQF_TRIGGER_HIGH;
-		else
-			event->irqflags |= IRQF_TRIGGER_LOW;
-	} else {
-		switch (agpio->polarity) {
-		case ACPI_ACTIVE_HIGH:
-			event->irqflags |= IRQF_TRIGGER_RISING;
-			break;
-		case ACPI_ACTIVE_LOW:
-			event->irqflags |= IRQF_TRIGGER_FALLING;
-			break;
-		default:
-			event->irqflags |= IRQF_TRIGGER_RISING |
-					   IRQF_TRIGGER_FALLING;
-			break;
-		}
-	}
-
-	event->handle = evt_handle;
-	event->handler = handler;
-	event->irq = irq;
-	event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
-	event->pin = pin;
-	event->desc = desc;
-
-	list_add_tail(&event->node, &acpi_gpio->events);
-
-	return AE_OK;
-
-fail_unlock_irq:
-	gpiochip_unlock_as_irq(chip, pin);
-fail_free_desc:
-	gpiochip_free_own_desc(desc);
-
-	return AE_OK;
-}
-
-/**
- * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
- * @chip:      GPIO chip
- *
- * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
- * handled by ACPI event methods which need to be called from the GPIO
- * chip's interrupt handler. acpi_gpiochip_request_interrupts() finds out which
- * GPIO pins have ACPI event methods and assigns interrupt handlers that calls
- * the ACPI event methods for those pins.
- */
-void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
-{
-	struct acpi_gpio_chip *acpi_gpio;
-	acpi_handle handle;
-	acpi_status status;
-
-	if (!chip->parent || !chip->to_irq)
-		return;
-
-	handle = ACPI_HANDLE(chip->parent);
-	if (!handle)
-		return;
-
-	status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
-	if (ACPI_FAILURE(status))
-		return;
-
-	if (acpi_quirk_skip_gpio_event_handlers())
-		return;
-
-	acpi_walk_resources(handle, METHOD_NAME__AEI,
-			    acpi_gpiochip_alloc_event, acpi_gpio);
-
-	if (acpi_gpio_add_to_deferred_list(&acpi_gpio->deferred_req_irqs_list_entry))
-		return;
-
-	acpi_gpiochip_request_irqs(acpi_gpio);
-}
-EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
-
-/**
- * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
- * @chip:      GPIO chip
- *
- * Free interrupts associated with GPIO ACPI event method for the given
- * GPIO chip.
- */
-void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
-{
-	struct acpi_gpio_chip *acpi_gpio;
-	struct acpi_gpio_event *event, *ep;
-	acpi_handle handle;
-	acpi_status status;
-
-	if (!chip->parent || !chip->to_irq)
-		return;
-
-	handle = ACPI_HANDLE(chip->parent);
-	if (!handle)
-		return;
-
-	status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
-	if (ACPI_FAILURE(status))
-		return;
-
-	acpi_gpio_remove_from_deferred_list(&acpi_gpio->deferred_req_irqs_list_entry);
-
-	list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
-		if (event->irq_requested) {
-			if (event->irq_is_wake)
-				disable_irq_wake(event->irq);
-
-			free_irq(event->irq, event);
-		}
-
-		gpiochip_unlock_as_irq(chip, event->pin);
-		gpiochip_free_own_desc(event->desc);
-		list_del(&event->node);
-		kfree(event);
-	}
-}
-EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts);
-
-void __init acpi_gpio_process_deferred_list(struct list_head *list)
-{
-	struct acpi_gpio_chip *acpi_gpio, *tmp;
-
-	list_for_each_entry_safe(acpi_gpio, tmp, list, deferred_req_irqs_list_entry)
-		acpi_gpiochip_request_irqs(acpi_gpio);
-}
 
 int acpi_dev_add_driver_gpios(struct acpi_device *adev,
 			      const struct acpi_gpio_mapping *gpios)
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 01/12] gpiolib: acpi: Use snprintf() for ACPI event name formatting
  2026-05-18  7:53 ` [PATCH 01/12] gpiolib: acpi: Use snprintf() for ACPI event name formatting Marco Scardovi (scardracs)
@ 2026-05-18  8:07   ` Andy Shevchenko
  0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-05-18  8:07 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: Linus Walleij, Bartosz Golaszewski, Mika Westerberg, linux-gpio,
	linux-acpi, linux-kernel

On Mon, May 18, 2026 at 09:53:46AM +0200, Marco Scardovi (scardracs) wrote:
> Replace sprintf() with snprintf() when formatting ACPI GPIO
> event names and fix minor formatting inconsistencies.

It has also unrelated stuff. Do one thing in one patch.

...

>  	if (pin <= 255) {
>  		char ev_name[8];
> -		sprintf(ev_name, "_%c%02X",
> -			agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
> -			pin);
> +
> +		snprintf(ev_name, sizeof(ev_name), "_%c%02X",
> +			 agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
> +			 pin);
>  		if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
>  			handler = acpi_gpio_irq_handler;
>  	}

This doesn't seem to anyhow make code hardened or so. I'm not sure I see
the point. Also you may check the Git history around these lines.

>  }

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 02/12] gpiolib: acpi: Modernize string parsing in quirks layer
  2026-05-18  7:53 ` [PATCH 02/12] gpiolib: acpi: Modernize string parsing in quirks layer Marco Scardovi (scardracs)
@ 2026-05-18  8:11   ` Andy Shevchenko
  0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-05-18  8:11 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: Linus Walleij, Bartosz Golaszewski, Mika Westerberg, linux-gpio,
	linux-acpi, linux-kernel

On Mon, May 18, 2026 at 09:53:47AM +0200, Marco Scardovi (scardracs) wrote:

We do not accept patches with empty commit messages (it's not 2007 out there).

> Assisted-by: Antigravity:gemini-3-flash
> Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
> ---
>  		if (len == strlen(controller_in) &&
>  		    strncmp(controller, controller_in, len) == 0) {
> -			pin = simple_strtoul(pin_str + 1, &endp, 10);
> -			if (*endp != 0 && *endp != ',')

> +			char pin_buf[16];
> +			size_t pin_len = 0;
> +			const char *p = pin_str + 1;

Keep it in reversed xmas tree order.

> +
> +			while (*p && *p != ',') {
> +				if (pin_len < sizeof(pin_buf) - 1)
> +					pin_buf[pin_len++] = *p;
> +				else
> +					goto err;
> +				p++;
> +			}
> +			pin_buf[pin_len] = '\0';
> +
> +			if (kstrtouint(pin_buf, 10, &pin))

This returns an error code, is it got shadowed on purpose?

>  				goto err;

...

The temporary buffer makes an unneeded churn. simple_strtoul() will work okay.
Even if it's an overflow, it's user's responsibility. And since we have this
already, it's now part of ABI (kernel command line comes from outside of the
kernel).

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support
  2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
                   ` (11 preceding siblings ...)
  2026-05-18  7:53 ` [PATCH 12/12] gpiolib: acpi: Decouple Event and Interrupt handling from core Marco Scardovi (scardracs)
@ 2026-05-18  8:19 ` Andy Shevchenko
  12 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-05-18  8:19 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: Linus Walleij, Bartosz Golaszewski, Mika Westerberg, linux-gpio,
	linux-acpi, linux-kernel

On Mon, May 18, 2026 at 09:53:45AM +0200, Marco Scardovi (scardracs) wrote:
> Good morning everyone,
> 
> This patch series took fairly a bit of time because, well,

It needs more work. Please, take your time to get familiar with the Linux
kernel process and patches requirements (read Submitting Patches and related
documentation).

> it ended up going a "bit"
> out of hand. It improves style, robustness, resource safety, and modularity
> of the ACPI GPIO subsystem. The massive gpiolib-acpi-core.c driver (previously
> well over 1400 lines) has been significantly refactored, reducing its footprint
> by separating concerns into distinct, dedicated modules for ACPI Operation Region
> handling and ACPI Event/Interrupt processing.

> Key changes and structure of the series:
> 1. Hardening & Correctness (Patches 1-4):
>    - Style adjustments to match Linux Kernel coding standard.
>    - Modernized parsing in quirks using standard sysfs/kstrto helpers.
>    - Added robust bounds checking for ACPI GPIO resource pin ranges.
>    - Fixed a critical memory resource leak in the OpRegion cleanup path.

Start from fixing critical issues first.

> 2. ACPI Operation Region Modularization (Patches 5-9):
>    - Declared shared data structures in the local header.
>    - Exposed private-to-core registration helpers by making them non-static.
>    - Extracted Operation Region handling logic to gpiolib-acpi-opregion.c.
>    - Diverted callback registration to the new OpRegion module.
>    - Removed the unused static emulation handlers from the core driver.
> 
> 3. ACPI Event & Interrupt Handling Modularization (Patches 10-12):
>    - Declared shared helper prototypes in the local header.
>    - Extracted Event/Interrupt logic to gpiolib-acpi-events.c.
>    - Fully decoupled static event handlers and event structures from the core.
> 
> Build correctness and functional behavior were validated on x86 virtual
> platforms using virtme-ng under KASAN and kmemleak with successful boot,
> execution, and zero resource leaks.

I didn't get the point of the whole series. It also gets +80 or so LoC.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 05/12] gpiolib: acpi: Declare shared structures in gpiolib-acpi.h
  2026-05-18  7:53 ` [PATCH 05/12] gpiolib: acpi: Declare shared structures in gpiolib-acpi.h Marco Scardovi (scardracs)
@ 2026-05-18  8:21   ` Andy Shevchenko
  0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-05-18  8:21 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: Linus Walleij, Bartosz Golaszewski, Mika Westerberg, linux-gpio,
	linux-acpi, linux-kernel

On Mon, May 18, 2026 at 09:53:50AM +0200, Marco Scardovi (scardracs) wrote:

...

> +#include <linux/acpi.h>
>  #include <linux/err.h>
> -#include <linux/types.h>
> -

>  #include <linux/gpio/consumer.h>

This header was specifically made into a separate group.

> +#include <linux/interrupt.h>

> +#include <linux/list.h>

We don't include headers that are not being used. Follow IWYU.

> +#include <linux/mutex.h>
> +#include <linux/types.h>

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 03/12] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  2026-05-18  7:53 ` [PATCH 03/12] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
@ 2026-05-18 10:33   ` Mika Westerberg
  2026-05-19  7:00     ` [PATCH v2 0/2] gpiolib: acpi: Add bounds-checking and fix leak in OpRegion Marco Scardovi (scardracs)
  0 siblings, 1 reply; 29+ messages in thread
From: Mika Westerberg @ 2026-05-18 10:33 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: Linus Walleij, Bartosz Golaszewski, Mika Westerberg,
	Andy Shevchenko, linux-gpio, linux-acpi, linux-kernel

On Mon, May 18, 2026 at 09:53:48AM +0200, Marco Scardovi (scardracs) wrote:

You are missing here explanation why this patch is needed.

> Assisted-by: Antigravity:gemini-3-flash
> Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
> ---
>  drivers/gpio/gpiolib-acpi-core.c | 22 ++++++++++++++++++++--
>  1 file changed, 20 insertions(+), 2 deletions(-)

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 0/2] gpiolib: acpi: Add bounds-checking and fix leak in OpRegion
  2026-05-18 10:33   ` Mika Westerberg
@ 2026-05-19  7:00     ` Marco Scardovi (scardracs)
  2026-05-19  7:00       ` [PATCH 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
  2026-05-19  7:00       ` [PATCH 2/2] gpiolib: acpi: Fix resource leak in OpRegion cleanup path Marco Scardovi (scardracs)
  0 siblings, 2 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-19  7:00 UTC (permalink / raw)
  To: mika.westerberg
  Cc: andriy.shevchenko, brgl, linusw, linux-acpi, linux-gpio,
	linux-kernel, mscardovi95, westeri

Hi Andy, Mika,

Thanks in advance for your time, patience and your feedbacks.
I decided to split the original patch in two, one for the fixes
and one for the modularization of the code.

This first series includes:
  - Robust bounds checking for pin tables to prevent potential
    out-of-bounds reads when parsing malformed or empty ACPI
    namespace tables.
  - A resource leak fix in the OpRegion cleanup path if handler
    removal fails or encounters errors.

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>

Marco Scardovi (scardracs) (2):
  gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  gpiolib: acpi: Fix resource leak in OpRegion cleanup path

 drivers/gpio/gpiolib-acpi-core.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  2026-05-19  7:00     ` [PATCH v2 0/2] gpiolib: acpi: Add bounds-checking and fix leak in OpRegion Marco Scardovi (scardracs)
@ 2026-05-19  7:00       ` Marco Scardovi (scardracs)
  2026-05-19  7:25         ` Andy Shevchenko
  2026-05-19  7:00       ` [PATCH 2/2] gpiolib: acpi: Fix resource leak in OpRegion cleanup path Marco Scardovi (scardracs)
  1 sibling, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-19  7:00 UTC (permalink / raw)
  To: mika.westerberg
  Cc: andriy.shevchenko, brgl, linusw, linux-acpi, linux-gpio,
	linux-kernel, mscardovi95, westeri

Ensure that the GPIO pin resource arrays are safely bounded before
accessing indices. Add bounds checking in acpi_request_own_gpiod(),
acpi_gpio_irq_is_wake(), acpi_gpiochip_alloc_event(), and
acpi_gpio_adr_space_handler() to prevent out-of-bounds array reads if
the ACPI namespace provides malformed or empty pin tables.

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index eb8a40cfb7a9..d381631ba6f0 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -322,9 +322,14 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
 {
 	int polarity = GPIO_ACTIVE_HIGH;
 	enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
-	unsigned int pin = agpio->pin_table[index];
+	unsigned int pin;
 	struct gpio_desc *desc;
 
+	if (index >= agpio->pin_table_length)
+		return ERR_PTR(-EINVAL);
+
+	pin = agpio->pin_table[index];
+
 	desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
 	if (IS_ERR(desc))
 		return desc;
@@ -337,7 +342,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;
@@ -367,6 +377,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];
 
@@ -1110,6 +1123,11 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 		return AE_BAD_PARAMETER;
 	}
 
+	if (pin_index >= agpio->pin_table_length) {
+		ACPI_FREE(ares);
+		return AE_BAD_PARAMETER;
+	}
+
 	length = min(agpio->pin_table_length, pin_index + bits);
 	for (i = pin_index; i < length; ++i) {
 		unsigned int pin = agpio->pin_table[i];
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 2/2] gpiolib: acpi: Fix resource leak in OpRegion cleanup path
  2026-05-19  7:00     ` [PATCH v2 0/2] gpiolib: acpi: Add bounds-checking and fix leak in OpRegion Marco Scardovi (scardracs)
  2026-05-19  7:00       ` [PATCH 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
@ 2026-05-19  7:00       ` Marco Scardovi (scardracs)
  2026-05-19  8:28         ` Andy Shevchenko
  1 sibling, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-19  7:00 UTC (permalink / raw)
  To: mika.westerberg
  Cc: andriy.shevchenko, brgl, linusw, linux-acpi, linux-gpio,
	linux-kernel, mscardovi95, westeri

If acpi_remove_address_space_handler() fails, the cleanup function
acpi_gpiochip_free_regions() previously returned early. This leaks
the connections list and all requested GPIO descriptors.

Remove the early return statement so that connection cleanup and freeing
of descriptors are always executed, preventing memory leaks in teardown
failure paths.

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index d381631ba6f0..b6f2af23b204 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -1239,7 +1239,6 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
 	if (ACPI_FAILURE(status)) {
 		dev_err(chip->parent,
 			"Failed to remove GPIO OpRegion handler\n");
-		return;
 	}
 
 	list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  2026-05-19  7:00       ` [PATCH 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
@ 2026-05-19  7:25         ` Andy Shevchenko
  0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-05-19  7:25 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: mika.westerberg, brgl, linusw, linux-acpi, linux-gpio,
	linux-kernel, westeri

On Tue, May 19, 2026 at 09:00:30AM +0200, Marco Scardovi (scardracs) wrote:
> Ensure that the GPIO pin resource arrays are safely bounded before
> accessing indices. Add bounds checking in acpi_request_own_gpiod(),
> acpi_gpio_irq_is_wake(), acpi_gpiochip_alloc_event(), and
> acpi_gpio_adr_space_handler() to prevent out-of-bounds array reads if
> the ACPI namespace provides malformed or empty pin tables.

...

>  	int polarity = GPIO_ACTIVE_HIGH;
>  	enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
> -	unsigned int pin = agpio->pin_table[index];
> +	unsigned int pin;
>  	struct gpio_desc *desc;

Preserve reversed xmas tree order.

...

>  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];

This pin is not used...

>  	if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
>  		return false;

...in the above condition, so, you can move the check and pin assignment even
further.

...

>  	if (!acpi_gpio_get_irq_resource(ares, &agpio))
>  		return AE_OK;

> +	if (agpio->pin_table_length == 0)
> +		return AE_OK;

Move this check after the handle assignment.

>  	handle = ACPI_HANDLE(chip->parent);

>  	pin = agpio->pin_table[0];
>  

While at it, move this blank line to be before pin assignment.

...

> +	if (pin_index >= agpio->pin_table_length) {
> +		ACPI_FREE(ares);
> +		return AE_BAD_PARAMETER;
> +	}

This is bogus. Please, read the code. Do not blindly follow some AI nonsense.

>  	length = min(agpio->pin_table_length, pin_index + bits);
>  	for (i = pin_index; i < length; ++i) {
>  		unsigned int pin = agpio->pin_table[i];

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 2/2] gpiolib: acpi: Fix resource leak in OpRegion cleanup path
  2026-05-19  7:00       ` [PATCH 2/2] gpiolib: acpi: Fix resource leak in OpRegion cleanup path Marco Scardovi (scardracs)
@ 2026-05-19  8:28         ` Andy Shevchenko
  2026-05-20  7:45           ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Marco Scardovi (scardracs)
  0 siblings, 1 reply; 29+ messages in thread
From: Andy Shevchenko @ 2026-05-19  8:28 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: mika.westerberg, brgl, linusw, linux-acpi, linux-gpio,
	linux-kernel, westeri

On Tue, May 19, 2026 at 09:00:31AM +0200, Marco Scardovi (scardracs) wrote:
> If acpi_remove_address_space_handler() fails, the cleanup function
> acpi_gpiochip_free_regions() previously returned early. This leaks
> the connections list and all requested GPIO descriptors.
> 
> Remove the early return statement so that connection cleanup and freeing
> of descriptors are always executed, preventing memory leaks in teardown
> failure paths.

Same problem may happen in the acpi_gpio_adr_space_handler().
What you need is to split the list and GPIO cleaning into a helper
which will be used in both cases.

This might need a Fixes tag.

> Assisted-by: Antigravity:gemini-3-flash
> Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak
  2026-05-19  8:28         ` Andy Shevchenko
@ 2026-05-20  7:45           ` Marco Scardovi (scardracs)
  2026-05-20  7:45             ` [PATCH v3 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
                               ` (2 more replies)
  0 siblings, 3 replies; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-20  7:45 UTC (permalink / raw)
  To: andriy.shevchenko
  Cc: brgl, linusw, linux-acpi, linux-gpio, linux-kernel,
	mika.westerberg, mscardovi95, westeri

Hi Andy,

This new series addresses two issues in the ACPI GPIO library while trying
to address your feedbacks:
1. Adds robust bounds checking for pin resource indexing when requesting
   owned descriptors and querying wakeup/interrupt pin configurations.
2. Fixes a connection/descriptor leak in the OpRegion address space
   handler and handles connection rollback in a transaction-local list
   to avoid wiping successfully established connections.

Please note that some of these changes were found during a personal follow up
analysis before submitting the patches to the community. They are reported
to explain why some of these fixes are made in that way instead of another.

Changes since v2:
- Fixed a global over-cleanup bug in the error path of the handler, which
  incorrectly wiped the whole persistent connection list (achip->conns).
  We now use a temporary local list_head (new_conns) inside the handler
  to log and rollback only the connections requested during the current
  transaction, and splice them into the global list only on success.
- Renamed the global connections teardown helper to
  acpi_gpiochip_free_all_connections() to clearly indicate its scope.
- Fixed a potential concurrent connection duplication race in the handler
  using an optimistic double-check allocation retry pattern.
- Introduced the acpi_gpiochip_find_conn() helper to reduce lookup code
  duplication.
- Changed the subject prefix of Patch 2/2 to "Fixes: gpiolib: acpi: ...".

Changes since v1:
- Reworked bounds checking in acpi_gpio_adr_space_handler() to validate
  that the requested pin range [pin_index, pin_index + bits] remains within
  bounds of the ACPI resource pin table, returning -EINVAL instead of
  silent truncation.

As always I'll wait for your precious feedbacks

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>

Marco Scardovi (scardracs) (2):
  gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  Fixes: gpiolib: acpi: resource leak in OpRegion

 drivers/gpio/gpiolib-acpi-core.c | 157 ++++++++++++++++++++++++++++++---------
 1 file changed, 122 insertions(+), 35 deletions(-)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  2026-05-20  7:45           ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Marco Scardovi (scardracs)
@ 2026-05-20  7:45             ` Marco Scardovi (scardracs)
  2026-06-02  7:34               ` Andy Shevchenko
  2026-05-20  7:45             ` [PATCH v3 2/2] Fixes: gpiolib: acpi: resource leak in OpRegion Marco Scardovi (scardracs)
  2026-06-02  7:47             ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Andy Shevchenko
  2 siblings, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-20  7:45 UTC (permalink / raw)
  To: andriy.shevchenko
  Cc: brgl, linusw, linux-acpi, linux-gpio, linux-kernel,
	mika.westerberg, mscardovi95, westeri

Ensure that the GPIO pin resource arrays are safely bounded before
accessing indices. Add bounds checking in acpi_request_own_gpiod(),
acpi_gpio_irq_is_wake(), and acpi_gpiochip_alloc_event() to prevent
out-of-bounds array reads if the ACPI namespace provides malformed or
empty pin tables.

Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index eb8a40cfb7a9..a6d78dad299e 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -320,10 +320,18 @@ 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];
 	struct gpio_desc *desc;
+	enum gpiod_flags flags;
+	unsigned int pin;
+	int polarity;
+
+	polarity = GPIO_ACTIVE_HIGH;
+	flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
+
+	if (index >= agpio->pin_table_length)
+		return ERR_PTR(-EINVAL);
+
+	pin = agpio->pin_table[index];
 
 	desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
 	if (IS_ERR(desc))
@@ -337,11 +345,16 @@ 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->wake_capable != ACPI_WAKE_CAPABLE)
 		return false;
 
+	if (agpio->pin_table_length == 0)
+		return false;
+
+	pin = agpio->pin_table[0];
+
 	if (acpi_gpio_in_ignore_list(ACPI_GPIO_IGNORE_WAKE, dev_name(parent), pin)) {
 		dev_info(parent, "Ignoring wakeup on pin %u\n", pin);
 		return false;
@@ -368,6 +381,9 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
 		return AE_OK;
 
 	handle = ACPI_HANDLE(chip->parent);
+	if (agpio->pin_table_length == 0)
+		return AE_OK;
+
 	pin = agpio->pin_table[0];
 
 	if (pin <= 255) {
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 2/2] Fixes: gpiolib: acpi: resource leak in OpRegion
  2026-05-20  7:45           ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Marco Scardovi (scardracs)
  2026-05-20  7:45             ` [PATCH v3 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
@ 2026-05-20  7:45             ` Marco Scardovi (scardracs)
  2026-06-02  7:45               ` Andy Shevchenko
  2026-06-02  7:47             ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Andy Shevchenko
  2 siblings, 1 reply; 29+ messages in thread
From: Marco Scardovi (scardracs) @ 2026-05-20  7:45 UTC (permalink / raw)
  To: andriy.shevchenko
  Cc: brgl, linusw, linux-acpi, linux-gpio, linux-kernel,
	mika.westerberg, mscardovi95, westeri

If acpi_remove_address_space_handler() fails, the cleanup function
acpi_gpiochip_free_regions() previously returned early. This leaks
the connections list and all requested GPIO descriptors.

Similarly, if acpi_gpio_adr_space_handler() fails to allocate a connection
or request a GPIO descriptor during a multi-pin transaction, it exits
without freeing the descriptors and connections that were already allocated
in the same call.

To avoid leaks, introduce a localized new_conns list inside the handler to
track the new connections requested during the current transaction. On
error, roll back only the connections in the new_conns list (avoiding
deadlock on the non-recursive conn_lock and preventing over-cleanup of
historic connections). On success, splice the new_conns list into the
global achip->conns list under the conn_lock.

Additionally, rename the global connection cleanup function to
acpi_gpiochip_free_all_connections() and call it in the GPIO chip teardown
path.

Fixes: 473ed7be0da0 ("gpio / ACPI: Add support for ACPI GPIO operation regions")
Assisted-by: Antigravity:gemini-3-flash
Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 133 ++++++++++++++++++++++++-------
 1 file changed, 102 insertions(+), 31 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index a6d78dad299e..f891451ef0ba 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -1094,6 +1094,46 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id,
 }
 EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_wake_get_by);
 
+static void acpi_gpiochip_free_connection_list(struct list_head *list)
+{
+	struct acpi_gpio_connection *conn;
+	struct acpi_gpio_connection *tmp;
+
+	list_for_each_entry_safe_reverse(conn, tmp, list, node) {
+		gpiochip_free_own_desc(conn->desc);
+		list_del(&conn->node);
+		kfree(conn);
+	}
+}
+
+static void acpi_gpiochip_free_all_connections(struct acpi_gpio_chip *achip)
+{
+	guard(mutex)(&achip->conn_lock);
+
+	acpi_gpiochip_free_connection_list(&achip->conns);
+}
+
+static struct acpi_gpio_connection *
+acpi_gpiochip_find_conn(struct acpi_gpio_chip *achip,
+			struct list_head *new_conns, unsigned int pin)
+{
+	struct acpi_gpio_connection *conn;
+
+	list_for_each_entry(conn, &achip->conns, node) {
+		if (conn->pin == pin)
+			return conn;
+	}
+
+	if (new_conns) {
+		list_for_each_entry(conn, new_conns, node) {
+			if (conn->pin == pin)
+				return conn;
+		}
+	}
+
+	return NULL;
+}
+
 static acpi_status
 acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 			    u32 bits, u64 *value, void *handler_context,
@@ -1101,11 +1141,16 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 {
 	struct acpi_gpio_chip *achip = region_context;
 	struct gpio_chip *chip = achip->chip;
+	struct acpi_gpio_connection *other;
+	struct acpi_gpio_connection *conn;
 	struct acpi_resource_gpio *agpio;
 	struct acpi_resource *ares;
 	u16 pin_index = address;
+	LIST_HEAD(new_conns);
 	acpi_status status;
 	int length;
+	u16 shift;
+	u16 word;
 	int i;
 
 	status = acpi_buffer_to_resource(achip->conn_info.connection,
@@ -1129,20 +1174,15 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 	length = min(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;
 		struct gpio_desc *desc;
-		u16 word, shift;
-		bool found;
+		bool found = false;
 
 		mutex_lock(&achip->conn_lock);
 
-		found = false;
-		list_for_each_entry(conn, &achip->conns, node) {
-			if (conn->pin == pin) {
-				found = true;
-				desc = conn->desc;
-				break;
-			}
+		conn = acpi_gpiochip_find_conn(achip, &new_conns, pin);
+		if (conn) {
+			desc = conn->desc;
+			found = true;
 		}
 
 		/*
@@ -1163,34 +1203,62 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 			}
 		}
 
+		mutex_unlock(&achip->conn_lock);
+
 		if (!found) {
 			desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
 			if (IS_ERR(desc)) {
-				mutex_unlock(&achip->conn_lock);
+				/*
+				 * In case of concurrent handler execution, if
+				 * another thread has already requested the same
+				 * GPIO pin, this call might fail with -EBUSY.
+				 * Acquire the lock and re-check both lists. If
+				 * the other thread has added it in the meantime,
+				 * we use that one.
+				 */
+				if (PTR_ERR(desc) == -EBUSY) {
+					mutex_lock(&achip->conn_lock);
+					conn = acpi_gpiochip_find_conn(achip, &new_conns, pin);
+					if (conn) {
+						desc = conn->desc;
+						found = true;
+					}
+					mutex_unlock(&achip->conn_lock);
+					if (found)
+						goto use_existing;
+				}
 				status = AE_ERROR;
-				goto out;
+				goto err_free_new_conns;
 			}
 
 			conn = kzalloc_obj(*conn);
 			if (!conn) {
 				gpiochip_free_own_desc(desc);
-				mutex_unlock(&achip->conn_lock);
 				status = AE_NO_MEMORY;
-				goto out;
+				goto err_free_new_conns;
 			}
 
 			conn->pin = pin;
 			conn->desc = desc;
-			list_add_tail(&conn->node, &achip->conns);
-		}
 
-		mutex_unlock(&achip->conn_lock);
+			mutex_lock(&achip->conn_lock);
+			/*
+			 * Re-check both lists again before adding to local
+			 * new_conns, as another thread could have completed
+			 * and spliced its list while conn_lock was released.
+			 */
+			other = acpi_gpiochip_find_conn(achip, &new_conns, pin);
+			if (other) {
+				gpiochip_free_own_desc(conn->desc);
+				kfree(conn);
+				desc = other->desc;
+			} else {
+				list_add_tail(&conn->node, &new_conns);
+			}
+			mutex_unlock(&achip->conn_lock);
+		}
 
-		/*
-		 * For the cases when OperationRegion() consists of more than
-		 * 64 bits calculate the word and bit shift to use that one to
-		 * access the value.
-		 */
+use_existing:
 		word = i / 64;
 		shift = i % 64;
 
@@ -1204,9 +1272,19 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 		}
 	}
 
+	mutex_lock(&achip->conn_lock);
+	list_splice_tail(&new_conns, &achip->conns);
+	mutex_unlock(&achip->conn_lock);
+
+	status = AE_OK;
+
 out:
 	ACPI_FREE(ares);
 	return status;
+
+err_free_new_conns:
+	acpi_gpiochip_free_connection_list(&new_conns);
+	goto out;
 }
 
 static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
@@ -1229,22 +1307,15 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
 {
 	struct gpio_chip *chip = achip->chip;
 	acpi_handle handle = ACPI_HANDLE(chip->parent);
-	struct acpi_gpio_connection *conn, *tmp;
 	acpi_status status;
 
 	status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
 						   acpi_gpio_adr_space_handler);
-	if (ACPI_FAILURE(status)) {
+	if (ACPI_FAILURE(status))
 		dev_err(chip->parent,
 			"Failed to remove GPIO OpRegion handler\n");
-		return;
-	}
 
-	list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
-		gpiochip_free_own_desc(conn->desc);
-		list_del(&conn->node);
-		kfree(conn);
-	}
+	acpi_gpiochip_free_all_connections(achip);
 }
 
 void acpi_gpiochip_add(struct gpio_chip *chip)
-- 
2.54.0


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
  2026-05-20  7:45             ` [PATCH v3 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
@ 2026-06-02  7:34               ` Andy Shevchenko
  0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-06-02  7:34 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: brgl, linusw, linux-acpi, linux-gpio, linux-kernel,
	mika.westerberg, westeri

On Wed, May 20, 2026 at 09:45:46AM +0200, Marco Scardovi (scardracs) wrote:
> Ensure that the GPIO pin resource arrays are safely bounded before
> accessing indices. Add bounds checking in acpi_request_own_gpiod(),
> acpi_gpio_irq_is_wake(), and acpi_gpiochip_alloc_event() to prevent
> out-of-bounds array reads if the ACPI namespace provides malformed or
> empty pin tables.

...

> -	int polarity = GPIO_ACTIVE_HIGH;
> -	enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);

> +	enum gpiod_flags flags;

> +	int polarity;

What's the point?

...

> +	polarity = GPIO_ACTIVE_HIGH;
> +	flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
> +
> +	if (index >= agpio->pin_table_length)
> +		return ERR_PTR(-EINVAL);

Now, what's the point of assigning flags and polarity before check? If you move
them after pin assignment below it will justify the changes in the definition
block above.

> +	pin = agpio->pin_table[index];

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 2/2] Fixes: gpiolib: acpi: resource leak in OpRegion
  2026-05-20  7:45             ` [PATCH v3 2/2] Fixes: gpiolib: acpi: resource leak in OpRegion Marco Scardovi (scardracs)
@ 2026-06-02  7:45               ` Andy Shevchenko
  0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-06-02  7:45 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: brgl, linusw, linux-acpi, linux-gpio, linux-kernel,
	mika.westerberg, westeri

On Wed, May 20, 2026 at 09:45:47AM +0200, Marco Scardovi (scardracs) wrote:
> If acpi_remove_address_space_handler() fails, the cleanup function
> acpi_gpiochip_free_regions() previously returned early. This leaks
> the connections list and all requested GPIO descriptors.
> 
> Similarly, if acpi_gpio_adr_space_handler() fails to allocate a connection
> or request a GPIO descriptor during a multi-pin transaction, it exits
> without freeing the descriptors and connections that were already allocated
> in the same call.
> 
> To avoid leaks, introduce a localized new_conns list inside the handler to
> track the new connections requested during the current transaction. On
> error, roll back only the connections in the new_conns list (avoiding
> deadlock on the non-recursive conn_lock and preventing over-cleanup of
> historic connections). On success, splice the new_conns list into the
> global achip->conns list under the conn_lock.
> 
> Additionally, rename the global connection cleanup function to
> acpi_gpiochip_free_all_connections() and call it in the GPIO chip teardown
> path.

...

> +static void acpi_gpiochip_free_connection_list(struct list_head *list)
> +{
> +	struct acpi_gpio_connection *conn;
> +	struct acpi_gpio_connection *tmp;

Make it a single line.

> +	list_for_each_entry_safe_reverse(conn, tmp, list, node) {
> +		gpiochip_free_own_desc(conn->desc);
> +		list_del(&conn->node);
> +		kfree(conn);
> +	}
> +}

...

> +static struct acpi_gpio_connection *
> +acpi_gpiochip_find_conn(struct acpi_gpio_chip *achip,
> +			struct list_head *new_conns, unsigned int pin)

We allow longer lines, so

static struct acpi_gpio_connection *
acpi_gpiochip_find_conn(struct acpi_gpio_chip *achip, struct list_head *new_conns,
			unsigned int pin)

is fine

> +{
> +	struct acpi_gpio_connection *conn;
> +
> +	list_for_each_entry(conn, &achip->conns, node) {
> +		if (conn->pin == pin)
> +			return conn;
> +	}

> +	if (new_conns) {

Is it ever called with new_conns == NULL?

> +		list_for_each_entry(conn, new_conns, node) {
> +			if (conn->pin == pin)
> +				return conn;
> +		}
> +	}
> +
> +	return NULL;
> +}

...

Before fixing the issue, introduce helpers and use them in the existing code
first. Then in the follow up fix the issue.

...

>  		struct gpio_desc *desc;
> -		u16 word, shift;
> -		bool found;
> +		bool found = false;

Do you still need it? Wouldn't 'conn == NULL' be equal to 'false'?

...

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak
  2026-05-20  7:45           ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Marco Scardovi (scardracs)
  2026-05-20  7:45             ` [PATCH v3 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
  2026-05-20  7:45             ` [PATCH v3 2/2] Fixes: gpiolib: acpi: resource leak in OpRegion Marco Scardovi (scardracs)
@ 2026-06-02  7:47             ` Andy Shevchenko
  2 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-06-02  7:47 UTC (permalink / raw)
  To: Marco Scardovi (scardracs)
  Cc: brgl, linusw, linux-acpi, linux-gpio, linux-kernel,
	mika.westerberg, westeri

On Wed, May 20, 2026 at 09:45:45AM +0200, Marco Scardovi (scardracs) wrote:
> Hi Andy,
> 
> This new series addresses two issues in the ACPI GPIO library while trying
> to address your feedbacks:
> 1. Adds robust bounds checking for pin resource indexing when requesting
>    owned descriptors and querying wakeup/interrupt pin configurations.
> 2. Fixes a connection/descriptor leak in the OpRegion address space
>    handler and handles connection rollback in a transaction-local list
>    to avoid wiping successfully established connections.
> 
> Please note that some of these changes were found during a personal follow up
> analysis before submitting the patches to the community. They are reported
> to explain why some of these fixes are made in that way instead of another.

Thanks for the update!

Please, split the second patch more to make it better to understand what the
helpers are doing (without changing the behaviour) and then fix the problem.

Otherwise it looks better than previous attempts.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2026-06-02  7:47 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-18  7:53 [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 01/12] gpiolib: acpi: Use snprintf() for ACPI event name formatting Marco Scardovi (scardracs)
2026-05-18  8:07   ` Andy Shevchenko
2026-05-18  7:53 ` [PATCH 02/12] gpiolib: acpi: Modernize string parsing in quirks layer Marco Scardovi (scardracs)
2026-05-18  8:11   ` Andy Shevchenko
2026-05-18  7:53 ` [PATCH 03/12] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
2026-05-18 10:33   ` Mika Westerberg
2026-05-19  7:00     ` [PATCH v2 0/2] gpiolib: acpi: Add bounds-checking and fix leak in OpRegion Marco Scardovi (scardracs)
2026-05-19  7:00       ` [PATCH 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
2026-05-19  7:25         ` Andy Shevchenko
2026-05-19  7:00       ` [PATCH 2/2] gpiolib: acpi: Fix resource leak in OpRegion cleanup path Marco Scardovi (scardracs)
2026-05-19  8:28         ` Andy Shevchenko
2026-05-20  7:45           ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Marco Scardovi (scardracs)
2026-05-20  7:45             ` [PATCH v3 1/2] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Marco Scardovi (scardracs)
2026-06-02  7:34               ` Andy Shevchenko
2026-05-20  7:45             ` [PATCH v3 2/2] Fixes: gpiolib: acpi: resource leak in OpRegion Marco Scardovi (scardracs)
2026-06-02  7:45               ` Andy Shevchenko
2026-06-02  7:47             ` [PATCH v3 0/2] gpiolib: acpi: Fix bounds-checking and connection leak Andy Shevchenko
2026-05-18  7:53 ` [PATCH 04/12] gpiolib: acpi: Fix resource leak in OpRegion cleanup path Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 05/12] gpiolib: acpi: Declare shared structures in gpiolib-acpi.h Marco Scardovi (scardracs)
2026-05-18  8:21   ` Andy Shevchenko
2026-05-18  7:53 ` [PATCH 06/12] gpiolib: acpi: Expose core GPIO resource and OpRegion helpers Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 07/12] gpiolib: acpi: Add dedicated Operation Region module Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 08/12] gpiolib: acpi: Divert OpRegion registration callbacks from core Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 09/12] gpiolib: acpi: Remove unused static address space emulation " Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 10/12] gpiolib: acpi: Declare shared event helpers in gpiolib-acpi.h Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 11/12] gpiolib: acpi: Add dedicated ACPI GPIO events module Marco Scardovi (scardracs)
2026-05-18  7:53 ` [PATCH 12/12] gpiolib: acpi: Decouple Event and Interrupt handling from core Marco Scardovi (scardracs)
2026-05-18  8:19 ` [PATCH 00/12] gpiolib: acpi: Refactor, harden, and modularize ACPI GPIO support Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome