* [PATCH 0/2] gpiolib: GPIO line irq_set_affinity helper @ 2026-10-23 15:11 Liang Hao 2026-10-23 15:11 ` [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs Liang Hao 2026-10-23 15:11 ` [PATCH 2/2] gpio: dwapb: Use gpiolib irq_set_affinity helper Liang Hao 0 siblings, 2 replies; 7+ messages in thread From: Liang Hao @ 2026-10-23 15:11 UTC (permalink / raw) To: linux-gpio; +Cc: Liang Hao Hi, Several GPIO irqchips omit irq_chip->irq_set_affinity on line IRQs, so user writes to /proc/irq/<gpio-line>/smp_affinity* fail. The helper covers hierarchical domains with parent_data and chained gpio_irq_chips that use parent_handler and parent virqs without parent_data on the line. This series adds a shared helper so drivers can expose affinity on GPIO line IRQs: the mask is applied on the parent interrupt, and the line IRQ reflects the result for proc and validation. Product init or resume scripts that restore per-line affinity depend on a line-level callback; without it those writes never reach the parent. Patch 1 adds gpiochip_irq_set_affinity() and GPIOCHIP_IRQ_AFFINITY_HELPERS: hierarchical lines use irq_chip_set_affinity_parent(); chained lines resolve the parent virq from gpio_irq_chip and call the parent irq_chip->irq_set_affinity() directly. Unknown parent: -EINVAL. Patch 2 enables the macro on gpio-dwapb (snps,dw-apb-gpio, DT chained). Tested on arm64: sysfs GPIO export + edge, write child gpiolib virq smp_affinity_list/smp_affinity — fails without the series, succeeds and reads back with it. Thanks, Liang Hao Liang Hao (2): gpiolib: Add irq_set_affinity helper for GPIO line IRQs gpio: dwapb: Use gpiolib irq_set_affinity helper drivers/gpio/gpio-dwapb.c | 1 + drivers/gpio/gpiolib.c | 79 +++++++++++++++++++++++++++++++++++++ include/linux/gpio/driver.h | 5 +++ 3 files changed, 85 insertions(+) -- 2.54.0 (Apple Git-157) ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs 2026-10-23 15:11 [PATCH 0/2] gpiolib: GPIO line irq_set_affinity helper Liang Hao @ 2026-10-23 15:11 ` Liang Hao 2026-10-23 15:35 ` sashiko-bot ` (2 more replies) 2026-10-23 15:11 ` [PATCH 2/2] gpio: dwapb: Use gpiolib irq_set_affinity helper Liang Hao 1 sibling, 3 replies; 7+ messages in thread From: Liang Hao @ 2026-10-23 15:11 UTC (permalink / raw) To: linux-gpio; +Cc: Liang Hao, Linus Walleij, Bartosz Golaszewski, linux-kernel GPIO line IRQs need irq_chip->irq_set_affinity so user space can steer affinity to the upstream controller. Hierarchical domains use parent_data; chained controllers (parent_handler, no parent_data on the line) store parent virqs in gpio_irq_chip instead. Add gpiochip_irq_set_affinity() and GPIOCHIP_IRQ_AFFINITY_HELPERS. Hierarchical lines delegate via irq_chip_set_affinity_parent(). Chained lines resolve the parent virq and call the parent irq_chip->irq_set_affinity() directly. Return -EINVAL if the parent virq cannot be resolved. Signed-off-by: Liang Hao <haohlliang@gmail.com> --- drivers/gpio/gpiolib.c | 79 +++++++++++++++++++++++++++++++++++++ include/linux/gpio/driver.h | 5 +++ 2 files changed, 84 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2987051d9904..0a4626579963 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2104,6 +2104,85 @@ void gpiochip_irq_relres(struct irq_data *d) } EXPORT_SYMBOL(gpiochip_irq_relres); +static unsigned int gpiochip_chained_parent_virq(struct gpio_chip *gc, + struct irq_data *d) +{ + struct gpio_irq_chip *girq = &gc->irq; + unsigned int hwirq = irqd_to_hwirq(d); + struct irq_desc *desc; + + if (!girq->parent_handler) + return 0; + + if (!girq->initialized || !girq->num_parents || !girq->parents) + return 0; + + if (girq->num_parents == 1) + return girq->parents[0]; + + if (girq->map) { + if (!gpiochip_irqchip_irq_valid(gc, hwirq)) + return 0; + return girq->map[hwirq]; + } + + desc = irq_to_desc(d->irq); + if (desc && desc->parent_irq) + return desc->parent_irq; + + return 0; +} + +/** + * gpiochip_irq_set_affinity() - irq_chip set_affinity helper for GPIO lines + * @d: Pointer to the GPIO line irq_data + * @dest: Affinity mask to set + * @force: True to enforce the mask without online CPU checks + * + * Hierarchical irqdomains with parent_data delegate through + * irq_chip_set_affinity_parent(). GPIO irqchips that use a chained parent + * handler resolve the parent virq and apply the mask through the parent + * irq_chip as described in gpiochip_chained_parent_virq(). + * + * Affinity is programmed on the parent irq, not independently per line. GPIO + * lines that share one parent irq also share its affinity; updating one line + * replaces the mask for all lines on that parent. + * + * Return: IRQ_SET_MASK_* on success, or a negative errno on error. + */ +int gpiochip_irq_set_affinity(struct irq_data *d, + const struct cpumask *dest, bool force) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct irq_data *pdata; + unsigned int parent; + int ret; + + if (d->parent_data) + return irq_chip_set_affinity_parent(d, dest, force); + + parent = gpiochip_chained_parent_virq(gc, d); + if (!parent) + return -EINVAL; + + pdata = irq_get_irq_data(parent); + if (!pdata || !pdata->chip || !pdata->chip->irq_set_affinity) + return -EINVAL; + + ret = pdata->chip->irq_set_affinity(pdata, dest, force); + switch (ret) { + case IRQ_SET_MASK_OK: + case IRQ_SET_MASK_OK_NOCOPY: + case IRQ_SET_MASK_OK_DONE: + irq_data_update_effective_affinity(d, + irq_data_get_effective_affinity_mask(pdata)); + return IRQ_SET_MASK_OK; + default: + return ret; + } +} +EXPORT_SYMBOL_GPL(gpiochip_irq_set_affinity); + static void gpiochip_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 4077dc678cae..a772bf1707aa 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -658,12 +658,17 @@ void gpiochip_enable_irq(struct gpio_chip *gc, unsigned int offset); /* irq_data versions of the above */ int gpiochip_irq_reqres(struct irq_data *data); void gpiochip_irq_relres(struct irq_data *data); +int gpiochip_irq_set_affinity(struct irq_data *data, + const struct cpumask *dest, bool force); /* Paste this in your irq_chip structure */ #define GPIOCHIP_IRQ_RESOURCE_HELPERS \ .irq_request_resources = gpiochip_irq_reqres, \ .irq_release_resources = gpiochip_irq_relres +#define GPIOCHIP_IRQ_AFFINITY_HELPERS \ + .irq_set_affinity = gpiochip_irq_set_affinity + static inline void gpio_irq_chip_set_chip(struct gpio_irq_chip *girq, const struct irq_chip *chip) { -- 2.54.0 (Apple Git-157) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs 2026-10-23 15:11 ` [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs Liang Hao @ 2026-10-23 15:35 ` sashiko-bot 2026-10-24 1:52 ` kernel test robot 2026-10-24 2:58 ` kernel test robot 2 siblings, 0 replies; 7+ messages in thread From: sashiko-bot @ 2026-10-23 15:35 UTC (permalink / raw) To: Liang Hao, linux-gpio Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] gpiolib: unlocked parent affinity update in gpiochip_irq_set_affinity() - [Low] gpiolib: missing hierarchy Kconfig guard in gpiochip_irq_set_affinity() -- commit 6be16d8d1664dad3beb504901b90bb4ff317a568 Author: Liang Hao <haohlliang@gmail.com> gpiolib: Add irq_set_affinity helper for GPIO line IRQs This commit adds gpiochip_irq_set_affinity() and a helper macro so GPIO line interrupts can forward affinity updates to upstream interrupt controllers in both hierarchical and chained irqchip setups. > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c > index 2987051d99043..0a46265799631 100644 > --- a/drivers/gpio/gpiolib.c > +++ b/drivers/gpio/gpiolib.c [ ... ] > +int gpiochip_irq_set_affinity(struct irq_data *d, > + const struct cpumask *dest, bool force) > +{ > + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); > + struct irq_data *pdata; > + unsigned int parent; > + int ret; > + > + if (d->parent_data) > + return irq_chip_set_affinity_parent(d, dest, force); [Severity: Low] Will this fail to build when hierarchical irqdomains are not enabled in the kernel configuration? In drivers/gpio/Kconfig, the gpiolib irqchip option only selects the base irqdomain support: drivers/gpio/Kconfig: config GPIOLIB_IRQCHIP select IRQ_DOMAIN bool However, both the parent_data member in struct irq_data and the declaration of irq_chip_set_affinity_parent() in include/linux/irq.h are guarded by the hierarchy configuration option: include/linux/irq.h: struct irq_data { ... #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY struct irq_data *parent_data; #endif void *chip_data; }; ... #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY ... extern int irq_chip_set_affinity_parent(struct irq_data *data, const struct cpumask *dest, bool force); Should the d->parent_data check and irq_chip_set_affinity_parent() call in gpiochip_irq_set_affinity() be guarded by an #ifdef just like the other hierarchical helpers in drivers/gpio/gpiolib.c? > + > + parent = gpiochip_chained_parent_virq(gc, d); > + if (!parent) > + return -EINVAL; > + > + pdata = irq_get_irq_data(parent); > + if (!pdata || !pdata->chip || !pdata->chip->irq_set_affinity) > + return -EINVAL; > + > + ret = pdata->chip->irq_set_affinity(pdata, dest, force); > + switch (ret) { > + case IRQ_SET_MASK_OK: > + case IRQ_SET_MASK_OK_NOCOPY: > + case IRQ_SET_MASK_OK_DONE: > + irq_data_update_effective_affinity(d, > + irq_data_get_effective_affinity_mask(pdata)); > + return IRQ_SET_MASK_OK; > + default: > + return ret; > + } > +} [Severity: High] Is it safe to invoke pdata->chip->irq_set_affinity() directly on a chained parent interrupt without holding the parent irq_desc lock or updating the parent descriptor's affinity state? Unlike hierarchical domains where d and d->parent_data belong to the same struct irq_desc, a chained parent virq has a separate struct irq_desc with its own lock and its own struct irq_common_data. When the genirq core invokes gpiochip_irq_set_affinity() through irq_do_set_affinity(), only the child GPIO line's desc->lock is held. Calling pdata->chip->irq_set_affinity(pdata, dest, force) unlocked from gpiochip_irq_set_affinity() appears to introduce several issues: 1. Concurrent affinity updates on sibling GPIO lines sharing the same parent virq (or concurrent operations on the parent virq itself, such as CPU hotplug migration in migrate_one_irq()) will race inside the parent irq_chip callback and on pdata's effective_affinity mask. Upstream irqchip drivers assume their own irq_desc->lock serializes irq_set_affinity(), for example in drivers/irqchip/irq-gic-v3.c:gic_set_affinity(): enabled = gic_peek_irq(d, GICD_ISENABLER); if (enabled) gic_mask_irq(d); ... gic_write_irouter(val, reg); if (enabled) gic_unmask_irq(d); irq_data_update_effective_affinity(d, cpumask_of(cpu)); and in drivers/irqchip/irq-sifive-plic.c:plic_set_affinity(): plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); irq_data_update_effective_affinity(d, cpumask_of(cpu)); if (!irqd_irq_disabled(d)) plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); Without holding the parent descriptor's lock, concurrent calls can corrupt the parent routing state or observe the parent temporarily masked and leave it permanently disabled. 2. Because irq_do_set_affinity() only updates desc->irq_common_data.affinity on the child descriptor: kernel/irq/manage.c:irq_do_set_affinity() switch (ret) { case IRQ_SET_MASK_OK: case IRQ_SET_MASK_OK_DONE: cpumask_copy(desc->irq_common_data.affinity, mask); fallthrough; case IRQ_SET_MASK_OK_NOCOPY: irq_validate_effective_affinity(data); irq_set_thread_affinity(desc); ret = 0; } bypassing irq_do_set_affinity() on the parent descriptor leaves the parent's irq_common_data.affinity unmodified (and skips deferred affinity movement checks). As a result, CPU hot-unplug in kernel/irq/cpuhotplug.c:migrate_one_irq() will migrate the parent interrupt using its stale affinity mask, and on configurations without effective affinity masks, irq_data_get_effective_affinity_mask(pdata) will also return that stale parent affinity mask: include/linux/irq.h:irq_data_get_effective_affinity_mask() static inline const struct cpumask *irq_data_get_effective_affinity_mask(struct irq_data *d) { return irq_data_get_affinity_mask(d); } 3. When multiple GPIO lines share a chained parent virq, requesting and starting up any sibling GPIO line later via request_threaded_irq() -> __setup_irq() -> irq_startup() -> irq_setup_affinity() will see a fresh child descriptor without a user-configured affinity mask and call irq_do_set_affinity() with irq_default_affinity: kernel/irq/manage.c:irq_setup_affinity() if (irqd_affinity_is_managed(&desc->irq_data) || irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) { if (cpumask_intersects(desc->irq_common_data.affinity, cpu_online_mask)) set = desc->irq_common_data.affinity; else irqd_clear(&desc->irq_data, IRQD_AFFINITY_SET); } ... return irq_do_set_affinity(&desc->irq_data, &mask, false); Won't starting a second GPIO line on the same parent virq silently reset the shared parent interrupt's hardware affinity back to the default mask, leaving any previously configured sibling GPIO line out of sync with the hardware? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261023151209.58772-1-haohlliang@gmail.com?part=1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs 2026-10-23 15:11 ` [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs Liang Hao 2026-10-23 15:35 ` sashiko-bot @ 2026-10-24 1:52 ` kernel test robot 2026-10-24 2:58 ` kernel test robot 2 siblings, 0 replies; 7+ messages in thread From: kernel test robot @ 2026-10-24 1:52 UTC (permalink / raw) To: Liang Hao, linux-gpio Cc: llvm, oe-kbuild-all, Liang Hao, Linus Walleij, Bartosz Golaszewski, linux-kernel Hi Liang, kernel test robot noticed the following build errors: [auto build test ERROR on brgl/gpio/for-next] [also build test ERROR on linus/master v7.3 next-20261022] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Liang-Hao/gpiolib-Add-irq_set_affinity-helper-for-GPIO-line-IRQs/20261023-231104 base: https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next patch link: https://lore.kernel.org/r/20261023151209.58772-2-haohlliang%40gmail.com patch subject: [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs config: mips-ci20_defconfig (https://download.01.org/0day-ci/archive/20261024/202610240908.4J3PwdPn-lkp@intel.com/config) compiler: clang version 24.0.0git (https://github.com/llvm/llvm-project 186e70f4e6a1521991d2340d3d49b23b1beff11f) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261024/202610240908.4J3PwdPn-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202610240908.4J3PwdPn-lkp@intel.com/ All errors (new ones prefixed by >>): >> drivers/gpio/gpiolib.c:2154:9: error: no member named 'parent_data' in 'struct irq_data' 2154 | if (d->parent_data) | ~ ^ >> drivers/gpio/gpiolib.c:2155:10: error: call to undeclared function 'irq_chip_set_affinity_parent'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 2155 | return irq_chip_set_affinity_parent(d, dest, force); | ^ drivers/gpio/gpiolib.c:2155:10: note: did you mean 'irq_set_affinity_hint'? include/linux/interrupt.h:407:19: note: 'irq_set_affinity_hint' declared here 407 | static inline int irq_set_affinity_hint(unsigned int irq, | ^ 2 errors generated. vim +2154 drivers/gpio/gpiolib.c 2128 2129 /** 2130 * gpiochip_irq_set_affinity() - irq_chip set_affinity helper for GPIO lines 2131 * @d: Pointer to the GPIO line irq_data 2132 * @dest: Affinity mask to set 2133 * @force: True to enforce the mask without online CPU checks 2134 * 2135 * Hierarchical irqdomains with parent_data delegate through 2136 * irq_chip_set_affinity_parent(). GPIO irqchips that use a chained parent 2137 * handler resolve the parent virq and apply the mask through the parent 2138 * irq_chip as described in gpiochip_chained_parent_virq(). 2139 * 2140 * Affinity is programmed on the parent irq, not independently per line. GPIO 2141 * lines that share one parent irq also share its affinity; updating one line 2142 * replaces the mask for all lines on that parent. 2143 * 2144 * Return: IRQ_SET_MASK_* on success, or a negative errno on error. 2145 */ 2146 int gpiochip_irq_set_affinity(struct irq_data *d, 2147 const struct cpumask *dest, bool force) 2148 { 2149 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 2150 struct irq_data *pdata; 2151 unsigned int parent; 2152 int ret; 2153 > 2154 if (d->parent_data) > 2155 return irq_chip_set_affinity_parent(d, dest, force); 2156 2157 parent = gpiochip_chained_parent_virq(gc, d); 2158 if (!parent) 2159 return -EINVAL; 2160 2161 pdata = irq_get_irq_data(parent); 2162 if (!pdata || !pdata->chip || !pdata->chip->irq_set_affinity) 2163 return -EINVAL; 2164 2165 ret = pdata->chip->irq_set_affinity(pdata, dest, force); 2166 switch (ret) { 2167 case IRQ_SET_MASK_OK: 2168 case IRQ_SET_MASK_OK_NOCOPY: 2169 case IRQ_SET_MASK_OK_DONE: 2170 irq_data_update_effective_affinity(d, 2171 irq_data_get_effective_affinity_mask(pdata)); 2172 return IRQ_SET_MASK_OK; 2173 default: 2174 return ret; 2175 } 2176 } 2177 EXPORT_SYMBOL_GPL(gpiochip_irq_set_affinity); 2178 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs 2026-10-23 15:11 ` [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs Liang Hao 2026-10-23 15:35 ` sashiko-bot 2026-10-24 1:52 ` kernel test robot @ 2026-10-24 2:58 ` kernel test robot 2 siblings, 0 replies; 7+ messages in thread From: kernel test robot @ 2026-10-24 2:58 UTC (permalink / raw) To: Liang Hao, linux-gpio Cc: oe-kbuild-all, Liang Hao, Linus Walleij, Bartosz Golaszewski, linux-kernel Hi Liang, kernel test robot noticed the following build errors: [auto build test ERROR on brgl/gpio/for-next] [also build test ERROR on linus/master v7.3 next-20261022] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Liang-Hao/gpiolib-Add-irq_set_affinity-helper-for-GPIO-line-IRQs/20261023-231104 base: https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next patch link: https://lore.kernel.org/r/20261023151209.58772-2-haohlliang%40gmail.com patch subject: [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs config: microblaze-defconfig (https://download.01.org/0day-ci/archive/20261024/202610241003.gRosyohv-lkp@intel.com/config) compiler: microblaze-linux-gcc (GCC) 16.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261024/202610241003.gRosyohv-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202610241003.gRosyohv-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/gpio/gpiolib.c: In function 'gpiochip_irq_set_affinity': >> drivers/gpio/gpiolib.c:2154:14: error: 'struct irq_data' has no member named 'parent_data' 2154 | if (d->parent_data) | ^~ >> drivers/gpio/gpiolib.c:2155:24: error: implicit declaration of function 'irq_chip_set_affinity_parent'; did you mean 'irq_set_affinity_hint'? [-Wimplicit-function-declaration] 2155 | return irq_chip_set_affinity_parent(d, dest, force); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ | irq_set_affinity_hint vim +2154 drivers/gpio/gpiolib.c 2128 2129 /** 2130 * gpiochip_irq_set_affinity() - irq_chip set_affinity helper for GPIO lines 2131 * @d: Pointer to the GPIO line irq_data 2132 * @dest: Affinity mask to set 2133 * @force: True to enforce the mask without online CPU checks 2134 * 2135 * Hierarchical irqdomains with parent_data delegate through 2136 * irq_chip_set_affinity_parent(). GPIO irqchips that use a chained parent 2137 * handler resolve the parent virq and apply the mask through the parent 2138 * irq_chip as described in gpiochip_chained_parent_virq(). 2139 * 2140 * Affinity is programmed on the parent irq, not independently per line. GPIO 2141 * lines that share one parent irq also share its affinity; updating one line 2142 * replaces the mask for all lines on that parent. 2143 * 2144 * Return: IRQ_SET_MASK_* on success, or a negative errno on error. 2145 */ 2146 int gpiochip_irq_set_affinity(struct irq_data *d, 2147 const struct cpumask *dest, bool force) 2148 { 2149 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 2150 struct irq_data *pdata; 2151 unsigned int parent; 2152 int ret; 2153 > 2154 if (d->parent_data) > 2155 return irq_chip_set_affinity_parent(d, dest, force); 2156 2157 parent = gpiochip_chained_parent_virq(gc, d); 2158 if (!parent) 2159 return -EINVAL; 2160 2161 pdata = irq_get_irq_data(parent); 2162 if (!pdata || !pdata->chip || !pdata->chip->irq_set_affinity) 2163 return -EINVAL; 2164 2165 ret = pdata->chip->irq_set_affinity(pdata, dest, force); 2166 switch (ret) { 2167 case IRQ_SET_MASK_OK: 2168 case IRQ_SET_MASK_OK_NOCOPY: 2169 case IRQ_SET_MASK_OK_DONE: 2170 irq_data_update_effective_affinity(d, 2171 irq_data_get_effective_affinity_mask(pdata)); 2172 return IRQ_SET_MASK_OK; 2173 default: 2174 return ret; 2175 } 2176 } 2177 EXPORT_SYMBOL_GPL(gpiochip_irq_set_affinity); 2178 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/2] gpio: dwapb: Use gpiolib irq_set_affinity helper 2026-10-23 15:11 [PATCH 0/2] gpiolib: GPIO line irq_set_affinity helper Liang Hao 2026-10-23 15:11 ` [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs Liang Hao @ 2026-10-23 15:11 ` Liang Hao 2026-10-23 15:30 ` sashiko-bot 1 sibling, 1 reply; 7+ messages in thread From: Liang Hao @ 2026-10-23 15:11 UTC (permalink / raw) To: linux-gpio Cc: Liang Hao, Hoan Tran, Linus Walleij, Bartosz Golaszewski, linux-kernel Wire GPIOCHIP_IRQ_AFFINITY_HELPERS into dwapb_irq_chip. Signed-off-by: Liang Hao <haohlliang@gmail.com> --- drivers/gpio/gpio-dwapb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index aa7c08e60707..9e63c3ecb5b4 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -412,6 +412,7 @@ static const struct irq_chip dwapb_irq_chip = { .irq_enable = dwapb_irq_enable, .irq_disable = dwapb_irq_disable, .irq_set_wake = pm_sleep_ptr(dwapb_irq_set_wake), + GPIOCHIP_IRQ_AFFINITY_HELPERS, .flags = IRQCHIP_IMMUTABLE, GPIOCHIP_IRQ_RESOURCE_HELPERS, }; -- 2.54.0 (Apple Git-157) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] gpio: dwapb: Use gpiolib irq_set_affinity helper 2026-10-23 15:11 ` [PATCH 2/2] gpio: dwapb: Use gpiolib irq_set_affinity helper Liang Hao @ 2026-10-23 15:30 ` sashiko-bot 0 siblings, 0 replies; 7+ messages in thread From: sashiko-bot @ 2026-10-23 15:30 UTC (permalink / raw) To: Liang Hao, linux-gpio Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] gpio: dwapb: broken irq_set_affinity on multi-IRQ DT and ACPI platforms - [High] gpio: unlocked parent call and state desync in gpiochip_irq_set_affinity() - [Low] gpio: unguarded parent_data access in gpiochip_irq_set_affinity() -- commit 72a8fcde432031570e3b16d2b7058ce326e44df1 Author: Liang Hao <haohlliang@gmail.com> gpio: dwapb: Use gpiolib irq_set_affinity helper This commit wires GPIOCHIP_IRQ_AFFINITY_HELPERS into dwapb_irq_chip so that dwapb GPIO interrupts use the gpiolib irq_set_affinity helper. > diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c > index aa7c08e607074..9e63c3ecb5b45 100644 > --- a/drivers/gpio/gpio-dwapb.c > +++ b/drivers/gpio/gpio-dwapb.c > @@ -412,6 +412,7 @@ static const struct irq_chip dwapb_irq_chip = { > .irq_enable = dwapb_irq_enable, > .irq_disable = dwapb_irq_disable, > .irq_set_wake = pm_sleep_ptr(dwapb_irq_set_wake), > + GPIOCHIP_IRQ_AFFINITY_HELPERS, [Severity: High] Does wiring GPIOCHIP_IRQ_AFFINITY_HELPERS unconditionally into dwapb_irq_chip cause irq_set_affinity to fail with -EINVAL on multi-IRQ Device Tree platforms and ACPI platforms? In drivers/gpio/gpio-dwapb.c, dwapb_convert_irqs() compacts non-zero per-line parent IRQs into pirq->irq[]: drivers/gpio/gpio-dwapb.c:dwapb_convert_irqs() { for (i = 0; i < pp->ngpio; ++i) { if (!pp->irq[i]) continue; pirq->irq[pirq->nr_irqs++] = pp->irq[i]; } } And dwapb_configure_irqs() sets up girq differently depending on whether there is an ACPI companion or Device Tree interrupts: drivers/gpio/gpio-dwapb.c:dwapb_configure_irqs() { if (has_acpi_companion(gpio->dev)) { girq->num_parents = 0; girq->parents = NULL; girq->parent_handler = NULL; err = devm_request_irq(gpio->dev, pp->irq[0], dwapb_irq_handler_mfd, IRQF_SHARED, DWAPB_DRIVER_NAME, gpio); ... } else { girq->num_parents = pirq->nr_irqs; girq->parents = pirq->irq; girq->parent_handler_data = gpio; girq->parent_handler = dwapb_irq_handler; } } On Device Tree platforms with multiple parent interrupts (where pirq->nr_irqs > 1, such as platforms wiring dedicated per-GPIO interrupts on Port A), girq->map is left NULL. In drivers/gpio/gpiolib.c, gpiochip_irq_map() only calls irq_set_parent() when gc->irq.num_parents == 1 or gc->irq.map is non-NULL, leaving desc->parent_irq == 0: drivers/gpio/gpiolib.c:gpiochip_irq_map() { if (gc->irq.num_parents == 1) ret = irq_set_parent(irq, gc->irq.parents[0]); else if (gc->irq.map) ret = irq_set_parent(irq, gc->irq.map[hwirq]); } When gpiochip_irq_set_affinity() -> gpiochip_chained_parent_virq() runs, girq->num_parents != 1, girq->map is NULL, and desc->parent_irq is 0, so gpiochip_chained_parent_virq() returns 0 and gpiochip_irq_set_affinity() returns -EINVAL. Furthermore, if per-line parent IRQs are sparsely populated such that only a single line j > 0 has a valid parent IRQ, dwapb_convert_irqs() compacts it into pirq->irq[0] with pirq->nr_irqs == 1, causing gpiochip_chained_parent_virq() to return line j's parent virq for any GPIO line on Port A. On ACPI platforms (has_acpi_companion(gpio->dev)), girq->parent_handler is NULL, so gpiochip_chained_parent_virq() also immediately returns 0: drivers/gpio/gpiolib.c:gpiochip_chained_parent_virq() { if (!girq->parent_handler) return 0; ... if (girq->num_parents == 1) return girq->parents[0]; if (girq->map) { if (!gpiochip_irqchip_irq_valid(gc, hwirq)) return 0; return girq->map[hwirq]; } desc = irq_to_desc(d->irq); if (desc && desc->parent_irq) return desc->parent_irq; return 0; } Because dwapb_irq_chip.irq_set_affinity is now non-NULL, __irq_can_set_affinity() and irq_can_set_affinity_usr() evaluate to true. Won't this cause irq_startup() -> irq_setup_affinity() to fail with -EINVAL when requesting any GPIO IRQ, migrate_one_irq() in kernel/irq/cpuhotplug.c to log ratelimited warnings during CPU hot-unplug, and writes to /proc/irq/<N>/smp_affinity to fail on these platforms? [Severity: High] Can calling pdata->chip->irq_set_affinity() through gpiochip_irq_set_affinity() on a chained dwapb irq_chip race on the parent irq_chip without parent_desc->lock held and desynchronize parent and sibling IRQ affinity state? For chained dwapb GPIO interrupts, d->parent_data is NULL and the parent is a separate virq with its own struct irq_desc. When the genirq core invokes dwapb_irq_chip.irq_set_affinity, only the child GPIO descriptor lock is held, yet gpiochip_irq_set_affinity() directly calls into the parent chip: drivers/gpio/gpiolib.c:gpiochip_irq_set_affinity() { pdata = irq_get_irq_data(parent); if (!pdata || !pdata->chip || !pdata->chip->irq_set_affinity) return -EINVAL; ret = pdata->chip->irq_set_affinity(pdata, dest, force); switch (ret) { case IRQ_SET_MASK_OK: case IRQ_SET_MASK_OK_NOCOPY: case IRQ_SET_MASK_OK_DONE: irq_data_update_effective_affinity(d, irq_data_get_effective_affinity_mask(pdata)); return IRQ_SET_MASK_OK; } Parent irq_chip callbacks such as gic_set_affinity() in drivers/irqchip/irq-gic-v3.c or plic_set_affinity() in drivers/irqchip/irq-sifive-plic.c expect their own parent_desc->lock to be held while masking, updating routing registers, unmasking, and updating pdata->common->effective_affinity. If two GPIO lines sharing a parent IRQ update affinity concurrently (or race with operations on the parent virq), can this corrupt hardware routing state and effective_affinity masks? In addition, because calling pdata->chip->irq_set_affinity() directly bypasses irq_do_set_affinity() on parent_desc, parent_desc->irq_common_data.affinity and IRQD_AFFINITY_SET are never updated on the parent descriptor. And when any sibling GPIO line sharing the same parent IRQ is later started via request_threaded_irq() -> irq_startup() -> irq_setup_affinity() in kernel/irq/manage.c: kernel/irq/manage.c:irq_setup_affinity() { struct cpumask *set = irq_default_affinity; ... if (!__irq_can_set_affinity(desc)) return 0; ... return irq_do_set_affinity(&desc->irq_data, &mask, false); } won't starting that second GPIO line overwrite the shared parent IRQ's hardware routing back to irq_default_affinity while leaving the first GPIO line's descriptor reporting stale affinity masks? [Severity: Low] Will gpiochip_irq_set_affinity() in drivers/gpio/gpiolib.c fail to build when CONFIG_GPIOLIB_IRQCHIP is enabled without CONFIG_IRQ_DOMAIN_HIERARCHY? In include/linux/irq.h, parent_data in struct irq_data and irq_chip_set_affinity_parent() are only declared when CONFIG_IRQ_DOMAIN_HIERARCHY is enabled: include/linux/irq.h:struct irq_data { #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY struct irq_data *parent_data; #endif } However, gpiochip_irq_set_affinity() accesses d->parent_data and calls irq_chip_set_affinity_parent() without a CONFIG_IRQ_DOMAIN_HIERARCHY guard: drivers/gpio/gpiolib.c:gpiochip_irq_set_affinity() { if (d->parent_data) return irq_chip_set_affinity_parent(d, dest, force); } Since CONFIG_GPIO_DWAPB and CONFIG_GPIOLIB_IRQCHIP do not select CONFIG_IRQ_DOMAIN_HIERARCHY, should this block in gpiochip_irq_set_affinity() be guarded with CONFIG_IRQ_DOMAIN_HIERARCHY like the other parent_data users in drivers/gpio/gpiolib.c and drivers/gpio/gpio-dwapb.c? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261023151209.58772-1-haohlliang@gmail.com?part=2 ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-24 2:59 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-23 15:11 [PATCH 0/2] gpiolib: GPIO line irq_set_affinity helper Liang Hao 2026-10-23 15:11 ` [PATCH 1/2] gpiolib: Add irq_set_affinity helper for GPIO line IRQs Liang Hao 2026-10-23 15:35 ` sashiko-bot 2026-10-24 1:52 ` kernel test robot 2026-10-24 2:58 ` kernel test robot 2026-10-23 15:11 ` [PATCH 2/2] gpio: dwapb: Use gpiolib irq_set_affinity helper Liang Hao 2026-10-23 15:30 ` sashiko-bot
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.