Skip to content

Commit 4d936f1

Browse files
avpatelKAGA-KOKO
authored andcommitted
irqchip/sifive-plic: Probe plic driver early for Allwinner D1 platform
The latest Linux RISC-V no longer boots on the Allwinner D1 platform because the sun4i_timer driver fails to get an interrupt from PLIC due to the recent conversion of the PLIC to a platform driver. Converting the sun4i timer to a platform driver does not work either because the D1 does not have a SBI timer available so early boot hangs. See the 'Closes:' link for deeper analysis. The real fix requires enabling the SBI time extension in the platform firmware (OpenSBI) and convert sun4i_timer into platform driver. Unfortunately, the real fix involves changing multiple places and can't be achieved in a short duration and aside of that requires users to update firmware. As a work-around, retrofit PLIC probing such that the PLIC is probed early only for the Allwinner D1 platform and probed as a regular platform driver for rest of the RISC-V platforms. In the process, partially revert some of the previous changes because the PLIC device pointer is not available in all probing paths. Fixes: e306a89 ("irqchip/sifive-plic: Chain to parent IRQ after handlers are ready") Fixes: 8ec99b0 ("irqchip/sifive-plic: Convert PLIC driver into a platform driver") Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Anup Patel <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Samuel Holland <[email protected]> Tested-by: Emil Renner Berthing <[email protected]> Tested-by: Charlie Jenkins <[email protected]> Reviewed-by: Samuel Holland <[email protected]> Reviewed-by: Charlie Jenkins <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/all/[email protected] Closes: https://lore.kernel.org/lkml/[email protected]/
1 parent 47ac09b commit 4d936f1

File tree

1 file changed

+71
-44
lines changed

1 file changed

+71
-44
lines changed

drivers/irqchip/irq-sifive-plic.c

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (C) 2017 SiFive
44
* Copyright (C) 2018 Christoph Hellwig
55
*/
6+
#define pr_fmt(fmt) "riscv-plic: " fmt
67
#include <linux/cpu.h>
78
#include <linux/interrupt.h>
89
#include <linux/io.h>
@@ -63,7 +64,7 @@
6364
#define PLIC_QUIRK_EDGE_INTERRUPT 0
6465

6566
struct plic_priv {
66-
struct device *dev;
67+
struct fwnode_handle *fwnode;
6768
struct cpumask lmask;
6869
struct irq_domain *irqdomain;
6970
void __iomem *regs;
@@ -378,8 +379,8 @@ static void plic_handle_irq(struct irq_desc *desc)
378379
int err = generic_handle_domain_irq(handler->priv->irqdomain,
379380
hwirq);
380381
if (unlikely(err)) {
381-
dev_warn_ratelimited(handler->priv->dev,
382-
"can't find mapping for hwirq %lu\n", hwirq);
382+
pr_warn_ratelimited("%pfwP: can't find mapping for hwirq %lu\n",
383+
handler->priv->fwnode, hwirq);
383384
}
384385
}
385386

@@ -408,7 +409,8 @@ static int plic_starting_cpu(unsigned int cpu)
408409
enable_percpu_irq(plic_parent_irq,
409410
irq_get_trigger_type(plic_parent_irq));
410411
else
411-
dev_warn(handler->priv->dev, "cpu%d: parent irq not available\n", cpu);
412+
pr_warn("%pfwP: cpu%d: parent irq not available\n",
413+
handler->priv->fwnode, cpu);
412414
plic_set_threshold(handler, PLIC_ENABLE_THRESHOLD);
413415

414416
return 0;
@@ -424,38 +426,36 @@ static const struct of_device_id plic_match[] = {
424426
{}
425427
};
426428

427-
static int plic_parse_nr_irqs_and_contexts(struct platform_device *pdev,
429+
static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
428430
u32 *nr_irqs, u32 *nr_contexts)
429431
{
430-
struct device *dev = &pdev->dev;
431432
int rc;
432433

433434
/*
434435
* Currently, only OF fwnode is supported so extend this
435436
* function for ACPI support.
436437
*/
437-
if (!is_of_node(dev->fwnode))
438+
if (!is_of_node(fwnode))
438439
return -EINVAL;
439440

440-
rc = of_property_read_u32(to_of_node(dev->fwnode), "riscv,ndev", nr_irqs);
441+
rc = of_property_read_u32(to_of_node(fwnode), "riscv,ndev", nr_irqs);
441442
if (rc) {
442-
dev_err(dev, "riscv,ndev property not available\n");
443+
pr_err("%pfwP: riscv,ndev property not available\n", fwnode);
443444
return rc;
444445
}
445446

446-
*nr_contexts = of_irq_count(to_of_node(dev->fwnode));
447+
*nr_contexts = of_irq_count(to_of_node(fwnode));
447448
if (WARN_ON(!(*nr_contexts))) {
448-
dev_err(dev, "no PLIC context available\n");
449+
pr_err("%pfwP: no PLIC context available\n", fwnode);
449450
return -EINVAL;
450451
}
451452

452453
return 0;
453454
}
454455

455-
static int plic_parse_context_parent(struct platform_device *pdev, u32 context,
456+
static int plic_parse_context_parent(struct fwnode_handle *fwnode, u32 context,
456457
u32 *parent_hwirq, int *parent_cpu)
457458
{
458-
struct device *dev = &pdev->dev;
459459
struct of_phandle_args parent;
460460
unsigned long hartid;
461461
int rc;
@@ -464,10 +464,10 @@ static int plic_parse_context_parent(struct platform_device *pdev, u32 context,
464464
* Currently, only OF fwnode is supported so extend this
465465
* function for ACPI support.
466466
*/
467-
if (!is_of_node(dev->fwnode))
467+
if (!is_of_node(fwnode))
468468
return -EINVAL;
469469

470-
rc = of_irq_parse_one(to_of_node(dev->fwnode), context, &parent);
470+
rc = of_irq_parse_one(to_of_node(fwnode), context, &parent);
471471
if (rc)
472472
return rc;
473473

@@ -480,48 +480,55 @@ static int plic_parse_context_parent(struct platform_device *pdev, u32 context,
480480
return 0;
481481
}
482482

483-
static int plic_probe(struct platform_device *pdev)
483+
static int plic_probe(struct fwnode_handle *fwnode)
484484
{
485485
int error = 0, nr_contexts, nr_handlers = 0, cpu, i;
486-
struct device *dev = &pdev->dev;
487486
unsigned long plic_quirks = 0;
488487
struct plic_handler *handler;
489488
u32 nr_irqs, parent_hwirq;
490489
struct plic_priv *priv;
491490
irq_hw_number_t hwirq;
491+
void __iomem *regs;
492492

493-
if (is_of_node(dev->fwnode)) {
493+
if (is_of_node(fwnode)) {
494494
const struct of_device_id *id;
495495

496-
id = of_match_node(plic_match, to_of_node(dev->fwnode));
496+
id = of_match_node(plic_match, to_of_node(fwnode));
497497
if (id)
498498
plic_quirks = (unsigned long)id->data;
499+
500+
regs = of_iomap(to_of_node(fwnode), 0);
501+
if (!regs)
502+
return -ENOMEM;
503+
} else {
504+
return -ENODEV;
499505
}
500506

501-
error = plic_parse_nr_irqs_and_contexts(pdev, &nr_irqs, &nr_contexts);
507+
error = plic_parse_nr_irqs_and_contexts(fwnode, &nr_irqs, &nr_contexts);
502508
if (error)
503-
return error;
509+
goto fail_free_regs;
504510

505-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
506-
if (!priv)
507-
return -ENOMEM;
511+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
512+
if (!priv) {
513+
error = -ENOMEM;
514+
goto fail_free_regs;
515+
}
508516

509-
priv->dev = dev;
517+
priv->fwnode = fwnode;
510518
priv->plic_quirks = plic_quirks;
511519
priv->nr_irqs = nr_irqs;
520+
priv->regs = regs;
512521

513-
priv->regs = devm_platform_ioremap_resource(pdev, 0);
514-
if (WARN_ON(!priv->regs))
515-
return -EIO;
516-
517-
priv->prio_save = devm_bitmap_zalloc(dev, nr_irqs, GFP_KERNEL);
518-
if (!priv->prio_save)
519-
return -ENOMEM;
522+
priv->prio_save = bitmap_zalloc(nr_irqs, GFP_KERNEL);
523+
if (!priv->prio_save) {
524+
error = -ENOMEM;
525+
goto fail_free_priv;
526+
}
520527

521528
for (i = 0; i < nr_contexts; i++) {
522-
error = plic_parse_context_parent(pdev, i, &parent_hwirq, &cpu);
529+
error = plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu);
523530
if (error) {
524-
dev_warn(dev, "hwirq for context%d not found\n", i);
531+
pr_warn("%pfwP: hwirq for context%d not found\n", fwnode, i);
525532
continue;
526533
}
527534

@@ -543,7 +550,7 @@ static int plic_probe(struct platform_device *pdev)
543550
}
544551

545552
if (cpu < 0) {
546-
dev_warn(dev, "Invalid cpuid for context %d\n", i);
553+
pr_warn("%pfwP: Invalid cpuid for context %d\n", fwnode, i);
547554
continue;
548555
}
549556

@@ -554,7 +561,7 @@ static int plic_probe(struct platform_device *pdev)
554561
*/
555562
handler = per_cpu_ptr(&plic_handlers, cpu);
556563
if (handler->present) {
557-
dev_warn(dev, "handler already present for context %d.\n", i);
564+
pr_warn("%pfwP: handler already present for context %d.\n", fwnode, i);
558565
plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD);
559566
goto done;
560567
}
@@ -568,8 +575,8 @@ static int plic_probe(struct platform_device *pdev)
568575
i * CONTEXT_ENABLE_SIZE;
569576
handler->priv = priv;
570577

571-
handler->enable_save = devm_kcalloc(dev, DIV_ROUND_UP(nr_irqs, 32),
572-
sizeof(*handler->enable_save), GFP_KERNEL);
578+
handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32),
579+
sizeof(*handler->enable_save), GFP_KERNEL);
573580
if (!handler->enable_save)
574581
goto fail_cleanup_contexts;
575582
done:
@@ -581,7 +588,7 @@ static int plic_probe(struct platform_device *pdev)
581588
nr_handlers++;
582589
}
583590

584-
priv->irqdomain = irq_domain_add_linear(to_of_node(dev->fwnode), nr_irqs + 1,
591+
priv->irqdomain = irq_domain_add_linear(to_of_node(fwnode), nr_irqs + 1,
585592
&plic_irqdomain_ops, priv);
586593
if (WARN_ON(!priv->irqdomain))
587594
goto fail_cleanup_contexts;
@@ -619,13 +626,13 @@ static int plic_probe(struct platform_device *pdev)
619626
}
620627
}
621628

622-
dev_info(dev, "mapped %d interrupts with %d handlers for %d contexts.\n",
623-
nr_irqs, nr_handlers, nr_contexts);
629+
pr_info("%pfwP: mapped %d interrupts with %d handlers for %d contexts.\n",
630+
fwnode, nr_irqs, nr_handlers, nr_contexts);
624631
return 0;
625632

626633
fail_cleanup_contexts:
627634
for (i = 0; i < nr_contexts; i++) {
628-
if (plic_parse_context_parent(pdev, i, &parent_hwirq, &cpu))
635+
if (plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu))
629636
continue;
630637
if (parent_hwirq != RV_IRQ_EXT || cpu < 0)
631638
continue;
@@ -634,17 +641,37 @@ static int plic_probe(struct platform_device *pdev)
634641
handler->present = false;
635642
handler->hart_base = NULL;
636643
handler->enable_base = NULL;
644+
kfree(handler->enable_save);
637645
handler->enable_save = NULL;
638646
handler->priv = NULL;
639647
}
640-
return -ENOMEM;
648+
bitmap_free(priv->prio_save);
649+
fail_free_priv:
650+
kfree(priv);
651+
fail_free_regs:
652+
iounmap(regs);
653+
return error;
654+
}
655+
656+
static int plic_platform_probe(struct platform_device *pdev)
657+
{
658+
return plic_probe(pdev->dev.fwnode);
641659
}
642660

643661
static struct platform_driver plic_driver = {
644662
.driver = {
645663
.name = "riscv-plic",
646664
.of_match_table = plic_match,
665+
.suppress_bind_attrs = true,
647666
},
648-
.probe = plic_probe,
667+
.probe = plic_platform_probe,
649668
};
650669
builtin_platform_driver(plic_driver);
670+
671+
static int __init plic_early_probe(struct device_node *node,
672+
struct device_node *parent)
673+
{
674+
return plic_probe(&node->fwnode);
675+
}
676+
677+
IRQCHIP_DECLARE(riscv, "allwinner,sun20i-d1-plic", plic_early_probe);

0 commit comments

Comments
 (0)