Skip to content

Commit 206dd13

Browse files
vlsunilrafaeljw
authored andcommitted
irqchip/sifive-plic: Add ACPI support
Add ACPI support in PLIC driver. Use the mapping created early during boot to get details about the PLIC. Signed-off-by: Sunil V L <[email protected]> Co-developed-by: Haibo Xu <[email protected]> Signed-off-by: Haibo Xu <[email protected]> Reviewed-by: Anup Patel <[email protected]> Tested-by: Björn Töpel <[email protected]> Acked-by: Thomas Gleixner <[email protected]> Link: https://patch.msgid.link/[email protected] [ rjw: Rebase on top of recent irqchip changes ] Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 5122e38 commit 206dd13

File tree

1 file changed

+77
-22
lines changed

1 file changed

+77
-22
lines changed

drivers/irqchip/irq-sifive-plic.c

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (C) 2018 Christoph Hellwig
55
*/
66
#define pr_fmt(fmt) "riscv-plic: " fmt
7+
#include <linux/acpi.h>
78
#include <linux/cpu.h>
89
#include <linux/interrupt.h>
910
#include <linux/io.h>
@@ -71,6 +72,8 @@ struct plic_priv {
7172
unsigned long plic_quirks;
7273
unsigned int nr_irqs;
7374
unsigned long *prio_save;
75+
u32 gsi_base;
76+
int acpi_plic_id;
7477
};
7578

7679
struct plic_handler {
@@ -325,6 +328,10 @@ static int plic_irq_domain_translate(struct irq_domain *d,
325328
{
326329
struct plic_priv *priv = d->host_data;
327330

331+
/* For DT, gsi_base is always zero. */
332+
if (fwspec->param[0] >= priv->gsi_base)
333+
fwspec->param[0] = fwspec->param[0] - priv->gsi_base;
334+
328335
if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
329336
return irq_domain_translate_twocell(d, fwspec, hwirq, type);
330337

@@ -426,17 +433,36 @@ static const struct of_device_id plic_match[] = {
426433
{}
427434
};
428435

436+
#ifdef CONFIG_ACPI
437+
438+
static const struct acpi_device_id plic_acpi_match[] = {
439+
{ "RSCV0001", 0 },
440+
{}
441+
};
442+
MODULE_DEVICE_TABLE(acpi, plic_acpi_match);
443+
444+
#endif
429445
static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
430-
u32 *nr_irqs, u32 *nr_contexts)
446+
u32 *nr_irqs, u32 *nr_contexts,
447+
u32 *gsi_base, u32 *id)
431448
{
432449
int rc;
433450

434-
/*
435-
* Currently, only OF fwnode is supported so extend this
436-
* function for ACPI support.
437-
*/
438-
if (!is_of_node(fwnode))
439-
return -EINVAL;
451+
if (!is_of_node(fwnode)) {
452+
rc = riscv_acpi_get_gsi_info(fwnode, gsi_base, id, nr_irqs, NULL);
453+
if (rc) {
454+
pr_err("%pfwP: failed to find GSI mapping\n", fwnode);
455+
return rc;
456+
}
457+
458+
*nr_contexts = acpi_rintc_get_plic_nr_contexts(*id);
459+
if (WARN_ON(!*nr_contexts)) {
460+
pr_err("%pfwP: no PLIC context available\n", fwnode);
461+
return -EINVAL;
462+
}
463+
464+
return 0;
465+
}
440466

441467
rc = of_property_read_u32(to_of_node(fwnode), "riscv,ndev", nr_irqs);
442468
if (rc) {
@@ -450,22 +476,28 @@ static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
450476
return -EINVAL;
451477
}
452478

479+
*gsi_base = 0;
480+
*id = 0;
481+
453482
return 0;
454483
}
455484

456485
static int plic_parse_context_parent(struct fwnode_handle *fwnode, u32 context,
457-
u32 *parent_hwirq, int *parent_cpu)
486+
u32 *parent_hwirq, int *parent_cpu, u32 id)
458487
{
459488
struct of_phandle_args parent;
460489
unsigned long hartid;
461490
int rc;
462491

463-
/*
464-
* Currently, only OF fwnode is supported so extend this
465-
* function for ACPI support.
466-
*/
467-
if (!is_of_node(fwnode))
468-
return -EINVAL;
492+
if (!is_of_node(fwnode)) {
493+
hartid = acpi_rintc_ext_parent_to_hartid(id, context);
494+
if (hartid == INVALID_HARTID)
495+
return -EINVAL;
496+
497+
*parent_cpu = riscv_hartid_to_cpuid(hartid);
498+
*parent_hwirq = RV_IRQ_EXT;
499+
return 0;
500+
}
469501

470502
rc = of_irq_parse_one(to_of_node(fwnode), context, &parent);
471503
if (rc)
@@ -489,6 +521,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
489521
struct plic_priv *priv;
490522
irq_hw_number_t hwirq;
491523
void __iomem *regs;
524+
int id, context_id;
525+
u32 gsi_base;
492526

493527
if (is_of_node(fwnode)) {
494528
const struct of_device_id *id;
@@ -501,10 +535,12 @@ static int plic_probe(struct fwnode_handle *fwnode)
501535
if (!regs)
502536
return -ENOMEM;
503537
} else {
504-
return -ENODEV;
538+
regs = devm_platform_ioremap_resource(to_platform_device(fwnode->dev), 0);
539+
if (IS_ERR(regs))
540+
return PTR_ERR(regs);
505541
}
506542

507-
error = plic_parse_nr_irqs_and_contexts(fwnode, &nr_irqs, &nr_contexts);
543+
error = plic_parse_nr_irqs_and_contexts(fwnode, &nr_irqs, &nr_contexts, &gsi_base, &id);
508544
if (error)
509545
goto fail_free_regs;
510546

@@ -518,6 +554,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
518554
priv->plic_quirks = plic_quirks;
519555
priv->nr_irqs = nr_irqs;
520556
priv->regs = regs;
557+
priv->gsi_base = gsi_base;
558+
priv->acpi_plic_id = id;
521559

522560
priv->prio_save = bitmap_zalloc(nr_irqs, GFP_KERNEL);
523561
if (!priv->prio_save) {
@@ -526,12 +564,23 @@ static int plic_probe(struct fwnode_handle *fwnode)
526564
}
527565

528566
for (i = 0; i < nr_contexts; i++) {
529-
error = plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu);
567+
error = plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu,
568+
priv->acpi_plic_id);
530569
if (error) {
531570
pr_warn("%pfwP: hwirq for context%d not found\n", fwnode, i);
532571
continue;
533572
}
534573

574+
if (is_of_node(fwnode)) {
575+
context_id = i;
576+
} else {
577+
context_id = acpi_rintc_get_plic_context(priv->acpi_plic_id, i);
578+
if (context_id == INVALID_CONTEXT) {
579+
pr_warn("%pfwP: invalid context id for context%d\n", fwnode, i);
580+
continue;
581+
}
582+
}
583+
535584
/*
536585
* Skip contexts other than external interrupts for our
537586
* privilege level.
@@ -569,10 +618,10 @@ static int plic_probe(struct fwnode_handle *fwnode)
569618
cpumask_set_cpu(cpu, &priv->lmask);
570619
handler->present = true;
571620
handler->hart_base = priv->regs + CONTEXT_BASE +
572-
i * CONTEXT_SIZE;
621+
context_id * CONTEXT_SIZE;
573622
raw_spin_lock_init(&handler->enable_lock);
574623
handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE +
575-
i * CONTEXT_ENABLE_SIZE;
624+
context_id * CONTEXT_ENABLE_SIZE;
576625
handler->priv = priv;
577626

578627
handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32),
@@ -588,8 +637,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
588637
nr_handlers++;
589638
}
590639

591-
priv->irqdomain = irq_domain_add_linear(to_of_node(fwnode), nr_irqs + 1,
592-
&plic_irqdomain_ops, priv);
640+
priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs + 1,
641+
&plic_irqdomain_ops, priv);
593642
if (WARN_ON(!priv->irqdomain))
594643
goto fail_cleanup_contexts;
595644

@@ -626,13 +675,18 @@ static int plic_probe(struct fwnode_handle *fwnode)
626675
}
627676
}
628677

678+
#ifdef CONFIG_ACPI
679+
if (!acpi_disabled)
680+
acpi_dev_clear_dependencies(ACPI_COMPANION(fwnode->dev));
681+
#endif
682+
629683
pr_info("%pfwP: mapped %d interrupts with %d handlers for %d contexts.\n",
630684
fwnode, nr_irqs, nr_handlers, nr_contexts);
631685
return 0;
632686

633687
fail_cleanup_contexts:
634688
for (i = 0; i < nr_contexts; i++) {
635-
if (plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu))
689+
if (plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu, priv->acpi_plic_id))
636690
continue;
637691
if (parent_hwirq != RV_IRQ_EXT || cpu < 0)
638692
continue;
@@ -663,6 +717,7 @@ static struct platform_driver plic_driver = {
663717
.name = "riscv-plic",
664718
.of_match_table = plic_match,
665719
.suppress_bind_attrs = true,
720+
.acpi_match_table = ACPI_PTR(plic_acpi_match),
666721
},
667722
.probe = plic_platform_probe,
668723
};

0 commit comments

Comments
 (0)