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

From: Anup Patel
Date: Wed Apr 03 2024 - 10:19:09 EST


On Wed, Apr 3, 2024 at 2:01 PM Lad, Prabhakar
<prabhakar.csengg@xxxxxxxxx> wrote:
>
> Hi Anup,
>
> On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <apatel@xxxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxxx>
> > ---
> > drivers/irqchip/irq-sifive-plic.c | 101 ++++++++++++++++++------------
> > 1 file changed, 61 insertions(+), 40 deletions(-)
> >
> This patch seems to have broken things on RZ/Five SoC, after reverting
> this patch I get to boot it back again on v6.9-rc2. Looks like there
> is some probe order issue after switching to platform driver?

Yes, this is most likely related to probe ordering based on your DT.

Can you share the failing boot log and DT ?

Regards,
Anup

>
> Cheers,
> Prabhakar
>
> > 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-arm-kernel mailing list
> > linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel