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? 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