Re: [PATCH v2 3/3] PCI: rzg3s: Fix IRQ domain initialization error handling

"Lad, Prabhakar" <[email protected]>
Newsgroups org.kernel.vger.linux-renesas-soc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci,org.kernel.vger.stable
Message-ID <CA+V-a8ujEokYydnADu3uxLxb0StKpB3sjsKPZqv=m4YF6Za6pA@mail.gmail.com>
Hi Claudiu,

Thank you for the review.

On Fri, Jul 31, 2026 at 5:02 PM Claudiu Beznea <[email protected]> wrote:
>
> Hi, Prabhakar,
>
> On 7/27/26 12:58, Prabhakar wrote:
> > From: Lad Prabhakar <[email protected]>
> >
> > rzg3s_pcie_init_irqdomain() installs chained handlers for the INTx
> > parent interrupts before creating the INTx irqdomain and initializing
> > MSI support.
> >
> > If any subsequent step fails, such as obtaining an INTx IRQ,
> > creating the irqdomain, or initializing MSI, the error path returns
> > without removing any chained handlers that were already installed.
> > This leaves stale handler and data pointers attached to the parent
> > interrupts.
> >
> > Fix the error path by unwinding the chained handler registration before
> > returning. Also clear the chained handlers during
> > rzg3s_pcie_teardown_irqdomain() so that teardown fully mirrors the
> > initialization sequence.
> >
> > Fixes: 7ef502fb35b28 ("PCI: Add Renesas RZ/G3S host controller driver")
> > Cc: [email protected]
> > Signed-off-by: Lad Prabhakar <[email protected]>
> > ---
> > v1->v2:
> > - Restricted the code to max 80 columns.
> > - Moved calling irq_domain_remove() under err_cleanup_intx label.
> > ---
> >   drivers/pci/controller/pcie-rzg3s-host.c | 49 +++++++++++++++++-------
> >   1 file changed, 36 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
> > index f51b5d7c1998..70f1faf7e422 100644
> > --- a/drivers/pci/controller/pcie-rzg3s-host.c
> > +++ b/drivers/pci/controller/pcie-rzg3s-host.c
> > @@ -1006,22 +1006,35 @@ static const struct irq_domain_ops rzg3s_pcie_intx_domain_ops = {
> >       .xlate = irq_domain_xlate_onetwocell,
> >   };
> >
> > +static void rzg3s_pcie_clear_intx_handlers(struct rzg3s_pcie_host *host,
> > +                                        int count)
> > +{
> > +     while (--count >= 0) {
> > +             irq_set_chained_handler_and_data(host->intx_irqs[count], NULL,
> > +                                              NULL);
> > +     }
> > +}
> > +
> >   static int rzg3s_pcie_init_irqdomain(struct rzg3s_pcie_host *host)
> >   {
> >       struct device *dev = host->dev;
> >       struct platform_device *pdev = to_platform_device(dev);
> > +     int i, ret;
> >
> > -     for (int i = 0; i < PCI_NUM_INTX; i++) {
> > +     for (i = 0; i < PCI_NUM_INTX; i++) {
> >               char irq_name[5] = {0};
> >               int irq;
> >
> >               scnprintf(irq_name, ARRAY_SIZE(irq_name), "int%c", 'a' + i);
> >
> >               irq = platform_get_irq_byname(pdev, irq_name);
> > -             if (irq < 0)
> > -                     return dev_err_probe(dev, irq,
> > -                                          "Failed to parse and map INT%c IRQ\n",
> > -                                          'A' + i);
> > +             if (irq < 0) {
> > +                     ret = irq;
> > +                     dev_err_probe(dev, ret,
> > +                                   "Failed to parse and map INT%c IRQ\n",
> > +                                   'A' + i);
> > +                     goto err_cleanup_intx;
> > +             }
> >
> >               host->intx_irqs[i] = irq;
> >               irq_set_chained_handler_and_data(irq,
> > @@ -1033,21 +1046,29 @@ static int rzg3s_pcie_init_irqdomain(struct rzg3s_pcie_host *host)
> >                                                    PCI_NUM_INTX,
> >                                                    &rzg3s_pcie_intx_domain_ops,
> >                                                    host);
> > -     if (!host->intx_domain)
> > -             return dev_err_probe(dev, -EINVAL,
> > -                                  "Failed to add irq domain for INTx IRQs\n");
> > +     if (!host->intx_domain) {
> > +             ret = -EINVAL;
> > +             dev_err_probe(dev, ret,
> > +                           "Failed to add irq domain for INTx IRQs\n");
> > +             goto err_cleanup_intx;
> > +     }
> >       irq_domain_update_bus_token(host->intx_domain, DOMAIN_BUS_WIRED);
> >
> >       if (IS_ENABLED(CONFIG_PCI_MSI)) {
> > -             int ret = rzg3s_pcie_init_msi(host);
> > +             ret = rzg3s_pcie_init_msi(host);
> >
> > -             if (ret) {
> > -                     irq_domain_remove(host->intx_domain);
> > -                     return ret;
> > -             }
> > +             if (ret)
> > +                     goto err_cleanup_intx;
> >       }
> >
> >       return 0;
> > +
> > +err_cleanup_intx:
> > +     if (host->intx_domain)
> > +             irq_domain_remove(host->intx_domain);
> > +     rzg3s_pcie_clear_intx_handlers(host, i);
>
> If you have it like this it worth squashing these lines in the same function, e.g.:
>
>         rzg3s_pcie_teardown_intx(host, i);
>
> defined something like:
Ok.

>
> void rzg3s_pcie_teardown_intx(struct rzg3s_pcie_host *host, int count)
> {
>         if (host->intx_domain)
>                 irq_domain_remove(host->intx_domain);
>
This needs to be done after the handler has been set to NULL as the
handler does use intx_domain (pointed by Sashiko).

>
>         while (--count >= 0) {
>                 irq_set_chained_handler_and_data(host->intx_irqs[count], NULL,
>                                                  NULL);
>         }
> }
>
> > +
> > +     return ret;
> >   }
> >
> >   static void rzg3s_pcie_teardown_irqdomain(struct rzg3s_pcie_host *host)
> > @@ -1055,6 +1076,8 @@ static void rzg3s_pcie_teardown_irqdomain(struct rzg3s_pcie_host *host)
> >       if (IS_ENABLED(CONFIG_PCI_MSI))
> >               rzg3s_pcie_teardown_msi(host);
> >
> > +     rzg3s_pcie_clear_intx_handlers(host, PCI_NUM_INTX);
> > +
> >       irq_domain_remove(host->intx_domain);
>
> And use the same function here, replacing:
>
> -       rzg3s_pcie_clear_intx_handlers(host, PCI_NUM_INTX);
> -
> -       irq_domain_remove(host->intx_domain);
> +       rzg3s_pcie_teardown_intx(host, PCI_NUM_INTX);
>
> Btw, the order b/w rzg3s_pcie_clear_intx_heandlers() and irq_domain_remove() was
> revered here compared with the order from rzg3s_pcie_init_irqdomain().
I will do the below:

static void rzg3s_pcie_teardown_intx(struct rzg3s_pcie_host *host,
                     int count)
{
    while (--count >= 0) {
        irq_set_chained_handler_and_data(host->intx_irqs[count], NULL,
                         NULL);
    }

    if (host->intx_domain)
        irq_domain_remove(host->intx_domain);
}

Cheers,
Prabhakar
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.