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

Lad, Prabhakar prabhakar.csengg at gmail.com
Wed Apr 3 01:29:43 PDT 2024


Hi Anup,

On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <apatel at ventanamicro.com> 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>
> ---
>  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 at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-riscv mailing list