summaryrefslogtreecommitdiff
path: root/drivers/irqchip/irq-riscv-intc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip/irq-riscv-intc.c')
-rw-r--r--drivers/irqchip/irq-riscv-intc.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
index 47f3200476da..8c5411386220 100644
--- a/drivers/irqchip/irq-riscv-intc.c
+++ b/drivers/irqchip/irq-riscv-intc.c
@@ -250,6 +250,85 @@ IRQCHIP_DECLARE(andes, "andestech,cpu-intc", riscv_intc_init);
#ifdef CONFIG_ACPI
+struct rintc_data {
+ union {
+ u32 ext_intc_id;
+ struct {
+ u32 context_id : 16,
+ reserved : 8,
+ aplic_plic_id : 8;
+ };
+ };
+ unsigned long hart_id;
+ u64 imsic_addr;
+ u32 imsic_size;
+};
+
+static u32 nr_rintc;
+static struct rintc_data *rintc_acpi_data[NR_CPUS];
+
+#define for_each_matching_plic(_plic_id) \
+ unsigned int _plic; \
+ \
+ for (_plic = 0; _plic < nr_rintc; _plic++) \
+ if (rintc_acpi_data[_plic]->aplic_plic_id != _plic_id) \
+ continue; \
+ else
+
+unsigned int acpi_rintc_get_plic_nr_contexts(unsigned int plic_id)
+{
+ unsigned int nctx = 0;
+
+ for_each_matching_plic(plic_id)
+ nctx++;
+
+ return nctx;
+}
+
+static struct rintc_data *get_plic_context(unsigned int plic_id, unsigned int ctxt_idx)
+{
+ unsigned int ctxt = 0;
+
+ for_each_matching_plic(plic_id) {
+ if (ctxt == ctxt_idx)
+ return rintc_acpi_data[_plic];
+
+ ctxt++;
+ }
+
+ return NULL;
+}
+
+unsigned long acpi_rintc_ext_parent_to_hartid(unsigned int plic_id, unsigned int ctxt_idx)
+{
+ struct rintc_data *data = get_plic_context(plic_id, ctxt_idx);
+
+ return data ? data->hart_id : INVALID_HARTID;
+}
+
+unsigned int acpi_rintc_get_plic_context(unsigned int plic_id, unsigned int ctxt_idx)
+{
+ struct rintc_data *data = get_plic_context(plic_id, ctxt_idx);
+
+ return data ? data->context_id : INVALID_CONTEXT;
+}
+
+unsigned long acpi_rintc_index_to_hartid(u32 index)
+{
+ return index >= nr_rintc ? INVALID_HARTID : rintc_acpi_data[index]->hart_id;
+}
+
+int acpi_rintc_get_imsic_mmio_info(u32 index, struct resource *res)
+{
+ if (index >= nr_rintc)
+ return -1;
+
+ res->start = rintc_acpi_data[index]->imsic_addr;
+ res->end = res->start + rintc_acpi_data[index]->imsic_size - 1;
+ res->flags = IORESOURCE_MEM;
+ return 0;
+}
+
static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
@@ -258,6 +337,15 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
int rc;
rintc = (struct acpi_madt_rintc *)header;
+ rintc_acpi_data[nr_rintc] = kzalloc(sizeof(*rintc_acpi_data[0]), GFP_KERNEL);
+ if (!rintc_acpi_data[nr_rintc])
+ return -ENOMEM;
+
+ rintc_acpi_data[nr_rintc]->ext_intc_id = rintc->ext_intc_id;
+ rintc_acpi_data[nr_rintc]->hart_id = rintc->hart_id;
+ rintc_acpi_data[nr_rintc]->imsic_addr = rintc->imsic_addr;
+ rintc_acpi_data[nr_rintc]->imsic_size = rintc->imsic_size;
+ nr_rintc++;
/*
* The ACPI MADT will have one INTC for each CPU (or HART)
@@ -277,6 +365,8 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
rc = riscv_intc_init_common(fn, &riscv_intc_chip);
if (rc)
irq_domain_free_fwnode(fn);
+ else
+ acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id);
return rc;
}