[PATCH v14 01/18] irqchip/sifive-plic: Convert PLIC driver into a platform driver

Anup Patel apatel at ventanamicro.com
Tue Jun 18 08:48:35 PDT 2024


On Tue, Jun 18, 2024 at 7:00 PM Emil Renner Berthing
<emil.renner.berthing at canonical.com> wrote:
>
> Anup Patel wrote:
> > The PLIC driver does not require very early initialization so convert
> > it into a platform driver.
> >
> > After conversion, the PLIC driver is probed after CPUs are brought-up
> > so setup cpuhp state after context handler of all online CPUs are
> > initialized otherwise PLIC driver crashes for platforms with multiple
> > PLIC instances.
> >
> > Signed-off-by: Anup Patel <apatel at ventanamicro.com>
>
> Hi Anup,
>
> Sorry for the late reply to the mailing list, but ever since 6.9 where this was
> applied my Allwinner D1 based boards no longer boot. This is the log of my
> LicheeRV Dock booting plain 6.10-rc4, locking up and then rebooting due to the
> the watchdog timing out:
>
> https://pastebin.com/raw/nsbzgEKW
>
> On 6.10-rc4 I can bring the same board to boot by reverting this patch and all
> patches building on it. Eg.:
>
>   git revert e306a894bd51 a7fb69ffd7ce abb720579490 \
>              956521064780 a15587277a24 6c725f33d67b \
>              b68d0ff529a9 25d862e183d4 8ec99b033147

Does your board boot with only SBI timer driver enabled ?

If yes then probing of Allwinner timer driver needs to be fixed since it
depends on PLIC.

Regards,
Anup

>
> After that it boots but run into this separate issue:
> https://lore.kernel.org/all/DM6PR01MB58047C810DDD5D0AE397CADFF7C22@DM6PR01MB5804.prod.exchangelabs.com/
>
> Samuel: After the reverts above applying this also prevents my board from
> booting:
> https://lore.kernel.org/all/20240312192519.1602493-1-samuel.holland@sifive.com/
>
> /Emil
>
> > ---
> >  drivers/irqchip/irq-sifive-plic.c | 101 ++++++++++++++++++------------
> >  1 file changed, 61 insertions(+), 40 deletions(-)
> >
> > diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
> > index 5b7bc4fd9517..7400a07fc479 100644
> > --- a/drivers/irqchip/irq-sifive-plic.c
> > +++ b/drivers/irqchip/irq-sifive-plic.c
> > @@ -64,6 +64,7 @@
> >  #define PLIC_QUIRK_EDGE_INTERRUPT    0
> >
> >  struct plic_priv {
> > +     struct device *dev;
> >       struct cpumask lmask;
> >       struct irq_domain *irqdomain;
> >       void __iomem *regs;
> > @@ -406,30 +407,50 @@ static int plic_starting_cpu(unsigned int cpu)
> >       return 0;
> >  }
> >
> > -static int __init __plic_init(struct device_node *node,
> > -                           struct device_node *parent,
> > -                           unsigned long plic_quirks)
> > +static const struct of_device_id plic_match[] = {
> > +     { .compatible = "sifive,plic-1.0.0" },
> > +     { .compatible = "riscv,plic0" },
> > +     { .compatible = "andestech,nceplic100",
> > +       .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
> > +     { .compatible = "thead,c900-plic",
> > +       .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
> > +     {}
> > +};
> > +
> > +static int plic_probe(struct platform_device *pdev)
> >  {
> >       int error = 0, nr_contexts, nr_handlers = 0, i;
> > -     u32 nr_irqs;
> > -     struct plic_priv *priv;
> > +     struct device *dev = &pdev->dev;
> > +     unsigned long plic_quirks = 0;
> >       struct plic_handler *handler;
> > +     struct plic_priv *priv;
> > +     bool cpuhp_setup;
> >       unsigned int cpu;
> > +     u32 nr_irqs;
> > +
> > +     if (is_of_node(dev->fwnode)) {
> > +             const struct of_device_id *id;
> > +
> > +             id = of_match_node(plic_match, to_of_node(dev->fwnode));
> > +             if (id)
> > +                     plic_quirks = (unsigned long)id->data;
> > +     }
> >
> >       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> >       if (!priv)
> >               return -ENOMEM;
> >
> > +     priv->dev = dev;
> >       priv->plic_quirks = plic_quirks;
> >
> > -     priv->regs = of_iomap(node, 0);
> > +     priv->regs = of_iomap(to_of_node(dev->fwnode), 0);
> >       if (WARN_ON(!priv->regs)) {
> >               error = -EIO;
> >               goto out_free_priv;
> >       }
> >
> >       error = -EINVAL;
> > -     of_property_read_u32(node, "riscv,ndev", &nr_irqs);
> > +     of_property_read_u32(to_of_node(dev->fwnode), "riscv,ndev", &nr_irqs);
> >       if (WARN_ON(!nr_irqs))
> >               goto out_iounmap;
> >
> > @@ -439,13 +460,13 @@ static int __init __plic_init(struct device_node *node,
> >       if (!priv->prio_save)
> >               goto out_free_priority_reg;
> >
> > -     nr_contexts = of_irq_count(node);
> > +     nr_contexts = of_irq_count(to_of_node(dev->fwnode));
> >       if (WARN_ON(!nr_contexts))
> >               goto out_free_priority_reg;
> >
> >       error = -ENOMEM;
> > -     priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
> > -                     &plic_irqdomain_ops, priv);
> > +     priv->irqdomain = irq_domain_add_linear(to_of_node(dev->fwnode), nr_irqs + 1,
> > +                                             &plic_irqdomain_ops, priv);
> >       if (WARN_ON(!priv->irqdomain))
> >               goto out_free_priority_reg;
> >
> > @@ -455,7 +476,7 @@ static int __init __plic_init(struct device_node *node,
> >               int cpu;
> >               unsigned long hartid;
> >
> > -             if (of_irq_parse_one(node, i, &parent)) {
> > +             if (of_irq_parse_one(to_of_node(dev->fwnode), i, &parent)) {
> >                       pr_err("failed to parse parent for context %d.\n", i);
> >                       continue;
> >               }
> > @@ -491,7 +512,7 @@ static int __init __plic_init(struct device_node *node,
> >
> >               /* Find parent domain and register chained handler */
> >               if (!plic_parent_irq && irq_find_host(parent.np)) {
> > -                     plic_parent_irq = irq_of_parse_and_map(node, i);
> > +                     plic_parent_irq = irq_of_parse_and_map(to_of_node(dev->fwnode), i);
> >                       if (plic_parent_irq)
> >                               irq_set_chained_handler(plic_parent_irq,
> >                                                       plic_handle_irq);
> > @@ -533,20 +554,29 @@ static int __init __plic_init(struct device_node *node,
> >
> >       /*
> >        * We can have multiple PLIC instances so setup cpuhp state
> > -      * and register syscore operations only when context handler
> > -      * for current/boot CPU is present.
> > +      * and register syscore operations only once after context
> > +      * handlers of all online CPUs are initialized.
> >        */
> > -     handler = this_cpu_ptr(&plic_handlers);
> > -     if (handler->present && !plic_cpuhp_setup_done) {
> > -             cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
> > -                               "irqchip/sifive/plic:starting",
> > -                               plic_starting_cpu, plic_dying_cpu);
> > -             register_syscore_ops(&plic_irq_syscore_ops);
> > -             plic_cpuhp_setup_done = true;
> > +     if (!plic_cpuhp_setup_done) {
> > +             cpuhp_setup = true;
> > +             for_each_online_cpu(cpu) {
> > +                     handler = per_cpu_ptr(&plic_handlers, cpu);
> > +                     if (!handler->present) {
> > +                             cpuhp_setup = false;
> > +                             break;
> > +                     }
> > +             }
> > +             if (cpuhp_setup) {
> > +                     cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
> > +                                       "irqchip/sifive/plic:starting",
> > +                                       plic_starting_cpu, plic_dying_cpu);
> > +                     register_syscore_ops(&plic_irq_syscore_ops);
> > +                     plic_cpuhp_setup_done = true;
> > +             }
> >       }
> >
> > -     pr_info("%pOFP: mapped %d interrupts with %d handlers for"
> > -             " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
> > +     pr_info("%pOFP: mapped %d interrupts with %d handlers for %d contexts.\n",
> > +             to_of_node(dev->fwnode), nr_irqs, nr_handlers, nr_contexts);
> >       return 0;
> >
> >  out_free_enable_reg:
> > @@ -563,20 +593,11 @@ static int __init __plic_init(struct device_node *node,
> >       return error;
> >  }
> >
> > -static int __init plic_init(struct device_node *node,
> > -                         struct device_node *parent)
> > -{
> > -     return __plic_init(node, parent, 0);
> > -}
> > -
> > -IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
> > -IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
> > -
> > -static int __init plic_edge_init(struct device_node *node,
> > -                              struct device_node *parent)
> > -{
> > -     return __plic_init(node, parent, BIT(PLIC_QUIRK_EDGE_INTERRUPT));
> > -}
> > -
> > -IRQCHIP_DECLARE(andestech_nceplic100, "andestech,nceplic100", plic_edge_init);
> > -IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_edge_init);
> > +static struct platform_driver plic_driver = {
> > +     .driver = {
> > +             .name           = "riscv-plic",
> > +             .of_match_table = plic_match,
> > +     },
> > +     .probe = plic_probe,
> > +};
> > +builtin_platform_driver(plic_driver);
> > --
> > 2.34.1
> >
> >
> > _______________________________________________
> > linux-riscv mailing list
> > linux-riscv at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-riscv



More information about the linux-arm-kernel mailing list