Skip to content

Commit 8ec99b0

Browse files
avpatelKAGA-KOKO
authored andcommitted
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 <apatel@ventanamicro.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20240222094006.1030709-2-apatel@ventanamicro.com
1 parent 129993d commit 8ec99b0

File tree

1 file changed

+61
-40
lines changed

1 file changed

+61
-40
lines changed

drivers/irqchip/irq-sifive-plic.c

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#define PLIC_QUIRK_EDGE_INTERRUPT 0
6565

6666
struct plic_priv {
67+
struct device *dev;
6768
struct cpumask lmask;
6869
struct irq_domain *irqdomain;
6970
void __iomem *regs;
@@ -406,30 +407,50 @@ static int plic_starting_cpu(unsigned int cpu)
406407
return 0;
407408
}
408409

409-
static int __init __plic_init(struct device_node *node,
410-
struct device_node *parent,
411-
unsigned long plic_quirks)
410+
static const struct of_device_id plic_match[] = {
411+
{ .compatible = "sifive,plic-1.0.0" },
412+
{ .compatible = "riscv,plic0" },
413+
{ .compatible = "andestech,nceplic100",
414+
.data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
415+
{ .compatible = "thead,c900-plic",
416+
.data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
417+
{}
418+
};
419+
420+
static int plic_probe(struct platform_device *pdev)
412421
{
413422
int error = 0, nr_contexts, nr_handlers = 0, i;
414-
u32 nr_irqs;
415-
struct plic_priv *priv;
423+
struct device *dev = &pdev->dev;
424+
unsigned long plic_quirks = 0;
416425
struct plic_handler *handler;
426+
struct plic_priv *priv;
427+
bool cpuhp_setup;
417428
unsigned int cpu;
429+
u32 nr_irqs;
430+
431+
if (is_of_node(dev->fwnode)) {
432+
const struct of_device_id *id;
433+
434+
id = of_match_node(plic_match, to_of_node(dev->fwnode));
435+
if (id)
436+
plic_quirks = (unsigned long)id->data;
437+
}
418438

419439
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
420440
if (!priv)
421441
return -ENOMEM;
422442

443+
priv->dev = dev;
423444
priv->plic_quirks = plic_quirks;
424445

425-
priv->regs = of_iomap(node, 0);
446+
priv->regs = of_iomap(to_of_node(dev->fwnode), 0);
426447
if (WARN_ON(!priv->regs)) {
427448
error = -EIO;
428449
goto out_free_priv;
429450
}
430451

431452
error = -EINVAL;
432-
of_property_read_u32(node, "riscv,ndev", &nr_irqs);
453+
of_property_read_u32(to_of_node(dev->fwnode), "riscv,ndev", &nr_irqs);
433454
if (WARN_ON(!nr_irqs))
434455
goto out_iounmap;
435456

@@ -439,13 +460,13 @@ static int __init __plic_init(struct device_node *node,
439460
if (!priv->prio_save)
440461
goto out_free_priority_reg;
441462

442-
nr_contexts = of_irq_count(node);
463+
nr_contexts = of_irq_count(to_of_node(dev->fwnode));
443464
if (WARN_ON(!nr_contexts))
444465
goto out_free_priority_reg;
445466

446467
error = -ENOMEM;
447-
priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
448-
&plic_irqdomain_ops, priv);
468+
priv->irqdomain = irq_domain_add_linear(to_of_node(dev->fwnode), nr_irqs + 1,
469+
&plic_irqdomain_ops, priv);
449470
if (WARN_ON(!priv->irqdomain))
450471
goto out_free_priority_reg;
451472

@@ -455,7 +476,7 @@ static int __init __plic_init(struct device_node *node,
455476
int cpu;
456477
unsigned long hartid;
457478

458-
if (of_irq_parse_one(node, i, &parent)) {
479+
if (of_irq_parse_one(to_of_node(dev->fwnode), i, &parent)) {
459480
pr_err("failed to parse parent for context %d.\n", i);
460481
continue;
461482
}
@@ -491,7 +512,7 @@ static int __init __plic_init(struct device_node *node,
491512

492513
/* Find parent domain and register chained handler */
493514
if (!plic_parent_irq && irq_find_host(parent.np)) {
494-
plic_parent_irq = irq_of_parse_and_map(node, i);
515+
plic_parent_irq = irq_of_parse_and_map(to_of_node(dev->fwnode), i);
495516
if (plic_parent_irq)
496517
irq_set_chained_handler(plic_parent_irq,
497518
plic_handle_irq);
@@ -533,20 +554,29 @@ static int __init __plic_init(struct device_node *node,
533554

534555
/*
535556
* We can have multiple PLIC instances so setup cpuhp state
536-
* and register syscore operations only when context handler
537-
* for current/boot CPU is present.
557+
* and register syscore operations only once after context
558+
* handlers of all online CPUs are initialized.
538559
*/
539-
handler = this_cpu_ptr(&plic_handlers);
540-
if (handler->present && !plic_cpuhp_setup_done) {
541-
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
542-
"irqchip/sifive/plic:starting",
543-
plic_starting_cpu, plic_dying_cpu);
544-
register_syscore_ops(&plic_irq_syscore_ops);
545-
plic_cpuhp_setup_done = true;
560+
if (!plic_cpuhp_setup_done) {
561+
cpuhp_setup = true;
562+
for_each_online_cpu(cpu) {
563+
handler = per_cpu_ptr(&plic_handlers, cpu);
564+
if (!handler->present) {
565+
cpuhp_setup = false;
566+
break;
567+
}
568+
}
569+
if (cpuhp_setup) {
570+
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
571+
"irqchip/sifive/plic:starting",
572+
plic_starting_cpu, plic_dying_cpu);
573+
register_syscore_ops(&plic_irq_syscore_ops);
574+
plic_cpuhp_setup_done = true;
575+
}
546576
}
547577

548-
pr_info("%pOFP: mapped %d interrupts with %d handlers for"
549-
" %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
578+
pr_info("%pOFP: mapped %d interrupts with %d handlers for %d contexts.\n",
579+
to_of_node(dev->fwnode), nr_irqs, nr_handlers, nr_contexts);
550580
return 0;
551581

552582
out_free_enable_reg:
@@ -563,20 +593,11 @@ static int __init __plic_init(struct device_node *node,
563593
return error;
564594
}
565595

566-
static int __init plic_init(struct device_node *node,
567-
struct device_node *parent)
568-
{
569-
return __plic_init(node, parent, 0);
570-
}
571-
572-
IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
573-
IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
574-
575-
static int __init plic_edge_init(struct device_node *node,
576-
struct device_node *parent)
577-
{
578-
return __plic_init(node, parent, BIT(PLIC_QUIRK_EDGE_INTERRUPT));
579-
}
580-
581-
IRQCHIP_DECLARE(andestech_nceplic100, "andestech,nceplic100", plic_edge_init);
582-
IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_edge_init);
596+
static struct platform_driver plic_driver = {
597+
.driver = {
598+
.name = "riscv-plic",
599+
.of_match_table = plic_match,
600+
},
601+
.probe = plic_probe,
602+
};
603+
builtin_platform_driver(plic_driver);

0 commit comments

Comments
 (0)