2024-02-22 09:40:47

by Anup Patel

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

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 <[email protected]>
---
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



Subject: [tip: irq/msi] irqchip/sifive-plic: Convert PLIC driver into a platform driver

The following commit has been merged into the irq/msi branch of tip:

Commit-ID: 8ec99b033147ef3bb8f0a560c24eb1baec3bc0be
Gitweb: https://git.kernel.org/tip/8ec99b033147ef3bb8f0a560c24eb1baec3bc0be
Author: Anup Patel <[email protected]>
AuthorDate: Thu, 22 Feb 2024 15:09:49 +05:30
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 23 Feb 2024 10:18:43 +01:00

irqchip/sifive-plic: Convert PLIC driver into a platform driver

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 <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
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 5b7bc4f..7400a07 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 @@ done:

/*
* 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 @@ out_free_priv:
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);

2024-04-03 08:59:26

by Prabhakar

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

Hi Anup,

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

2024-04-03 14:19:24

by Anup Patel

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

On Wed, Apr 3, 2024 at 2:01 PM Lad, Prabhakar
<[email protected]> wrote:
>
> Hi Anup,
>
> On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <[email protected]> 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 <[email protected]>
> > ---
> > 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
> > [email protected]
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

2024-04-03 16:23:12

by Prabhakar

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

On Wed, Apr 3, 2024 at 3:17 PM Anup Patel <[email protected]> wrote:
>
> On Wed, Apr 3, 2024 at 2:01 PM Lad, Prabhakar
> <[email protected]> wrote:
> >
> > Hi Anup,
> >
> > On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <apatel@ventanamicrocom> 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 <[email protected]>
> > > ---
> > > 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 ?

non working case, https://paste.debian.net/1312947/
after reverting, https://paste.debian.net/1312948/
(attached is the DTB)

Cheers,
Prabhakar


Attachments:
r9a07g043f01-smarc.dtb (22.83 kB)

2024-04-03 16:28:54

by Samuel Holland

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

Hi Prabhakar,

On 2024-04-03 10:49 AM, Lad, Prabhakar wrote:
> On Wed, Apr 3, 2024 at 3:17 PM Anup Patel <[email protected]> wrote:
>>
>> On Wed, Apr 3, 2024 at 2:01 PM Lad, Prabhakar
>> <[email protected]> wrote:
>>>
>>> Hi Anup,
>>>
>>> On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <[email protected]> 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 <[email protected]>
>>>> ---
>>>> 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 ?
>
> non working case, https://paste.debian.net/1312947/

Looks like you need to add "keep_bootcon" to your kernel command line to get a
full log here.

> after reverting, https://paste.debian.net/1312948/
> (attached is the DTB)

I don't see anything suspicious between the "riscv-intc" lines and the "Fixed
dependency cycle(s)" lines that looks like it would depend on the PLIC IRQ
domain. Maybe there is some driver that does not handle -EPROBE_DEFER? It's hard
to tell without the full log from the failure case.

Regards,
Samuel


2024-04-03 16:43:15

by Anup Patel

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

On Wed, Apr 3, 2024 at 9:19 PM Lad, Prabhakar
<[email protected]> wrote:
>
> On Wed, Apr 3, 2024 at 3:17 PM Anup Patel <[email protected]> wrote:
> >
> > On Wed, Apr 3, 2024 at 2:01 PM Lad, Prabhakar
> > <[email protected]> wrote:
> > >
> > > Hi Anup,
> > >
> > > On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <[email protected]> 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 <[email protected]>
> > > > ---
> > > > 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 ?
>
> non working case, https://paste.debian.net/1312947/

> after reverting, https://paste.debian.net/1312948/
> (attached is the DTB)

Can you add "console=ttySC0,115200" to kernel parameters and
share updated boot logs ?

Regards,
Anup

2024-04-03 18:15:07

by Prabhakar

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

Hi Samuel and Anup,

On Wed, Apr 3, 2024 at 5:28 PM Samuel Holland <[email protected]> wrote:
>
> Hi Prabhakar,
>
> On 2024-04-03 10:49 AM, Lad, Prabhakar wrote:
> > On Wed, Apr 3, 2024 at 3:17 PM Anup Patel <[email protected]> wrote:
> >>
> >> On Wed, Apr 3, 2024 at 2:01 PM Lad, Prabhakar
> >> <[email protected]> wrote:
> >>>
> >>> Hi Anup,
> >>>
> >>> On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <[email protected]> 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 <[email protected]>
> >>>> ---
> >>>> 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 ?
> >
> > non working case, https://paste.debian.net/1312947/
>
> Looks like you need to add "keep_bootcon" to your kernel command line to get a
> full log here.
>
Thanks for the pointer, that helped me to get to the root cause.

> > after reverting, https://paste.debian.net/1312948/
> > (attached is the DTB)
>
> I don't see anything suspicious between the "riscv-intc" lines and the "Fixed
> dependency cycle(s)" lines that looks like it would depend on the PLIC IRQ
> domain. Maybe there is some driver that does not handle -EPROBE_DEFER? It's hard
> to tell without the full log from the failure case.
>
The clock required for the PLIC wasnt available during the probe of
this driver. This bug got hidden when the PLIC driver was probed
earlier in boot where it used an incorrect clock source. Ive created
a patch which adds a missing clock for the PLIC.

Sorry for the noise!

Cheers,
Prabhakar

2024-04-03 21:06:27

by Anup Patel

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

On Wed, Apr 3, 2024 at 9:19 PM Lad, Prabhakar
<[email protected]> wrote:
>
> On Wed, Apr 3, 2024 at 3:17 PM Anup Patel <[email protected]> wrote:
> >
> > On Wed, Apr 3, 2024 at 2:01 PM Lad, Prabhakar
> > <[email protected]> wrote:
> > >
> > > Hi Anup,
> > >
> > > On Thu, Feb 22, 2024 at 9:41 AM Anup Patel <[email protected]> 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 <[email protected]>
> > > > ---
> > > > 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 ?
>
> non working case, https://paste.debian.net/1312947/
> after reverting, https://paste.debian.net/1312948/
> (attached is the DTB)

One potential problem is that
drivers/clocksource/renesas-ostm.c is probed early
using TIMER_OF_DECLARE() but the timer interrupt
is connected to PLIC which is probed late hence the
timer probe will fail.

We have two possible options:
1) Disable OSTM nodes
2) Improve the OSTM driver to probe like a
regular platform device on RISC-V

Regards,
Anup