Re: [PATCH 07/16] irqchip/mips-gic: clean up IRQ domain creation failure

From: Radu Rendec

Date: Sun Aug 02 2026 - 15:21:31 EST


On Tue, 2026-07-14 at 21:24 +0800, Haofeng Li wrote:
> From: Haofeng Li <lihaofeng@xxxxxxxxxx>
>
> After mapping the register base, irq_domain_create_simple() failure
> returns without unmapping it.

It does, but this driver is meant to initialize once during the (early)
kernel start-up and stay there for the rest of the kernel lifetime.
Also, this is the Global Interrupt Controller (GIC) driver. If this
fails to initialize, I very much doubt the system is usable anyway.

> The CPU chained or VEIC handler is also installed before either IRQ
> domain is ready. Unmapping the registers while that handler remains
> published would leave a path to unmapped MMIO,

... which is probably one of the reasons why the IO range was not
unmapped originally.

> and a later IPI domain
> failure would expose a half-initialized controller.
>
> Unmap and clear the register base when primary domain creation fails,
> and publish the CPU interrupt handler only after both domains have
> been created successfully.

Why? Please see my point above about the role of this driver. This
driver not only has a fundamental role, but also has a different
lifecycle and does not follow the cleanup paradigm of a typical driver
that can be unloaded/reloaded/re-probed.

>
> Fixes: fbea754123ae ("irqchip: mips-gic: Inline __gic_init()")
>
> Signed-off-by: Haofeng Li <lihaofeng@xxxxxxxxxx>
> ---
>  drivers/irqchip/irq-mips-gic.c | 24 +++++++++++++-----------
>  1 file changed, 13 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
> index 19a57c5e2b2e..85fe0d8a34c5 100644
> --- a/drivers/irqchip/irq-mips-gic.c
> +++ b/drivers/irqchip/irq-mips-gic.c
> @@ -956,23 +956,14 @@ static int __init gic_of_init(struct device_node *node,
>   gic_shared_intrs = FIELD_GET(GIC_CONFIG_NUMINTERRUPTS, gicconfig);
>   gic_shared_intrs = (gic_shared_intrs + 1) * 8;
>  
> - if (cpu_has_veic) {
> - /* Always use vector 1 in EIC mode */
> - gic_cpu_pin = 0;
> - set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
> -        __gic_irq_dispatch);
> - } else {
> - gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
> - irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
> - gic_irq_dispatch);
> - }
> -
>   gic_irq_domain = irq_domain_create_simple(of_fwnode_handle(node),
>     GIC_NUM_LOCAL_INTRS +
>     gic_shared_intrs, 0,
>     &gic_irq_domain_ops, NULL);
>   if (!gic_irq_domain) {
>   pr_err("Failed to add IRQ domain");
> + iounmap(mips_gic_base);
> + mips_gic_base = NULL;
>   return -ENXIO;
>   }
>  
> @@ -980,6 +971,17 @@ static int __init gic_of_init(struct device_node *node,
>   if (ret)
>   return ret;
>  
> + if (cpu_has_veic) {
> + /* Always use vector 1 in EIC mode */
> + gic_cpu_pin = 0;
> + set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
> +        __gic_irq_dispatch);
> + } else {
> + gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
> + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
> + gic_irq_dispatch);
> + }
> +
>   board_bind_eic_interrupt = &gic_bind_eic_interrupt;
>  
>   /*