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

Emil Renner Berthing emil.renner.berthing at canonical.com
Tue Jun 18 06:30:20 PDT 2024


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

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-riscv mailing list