]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
irqchip/riscv-intc: Add ACPI support for AIA
authorSunil V L <sunilvl@ventanamicro.com>
Mon, 12 Aug 2024 00:59:25 +0000 (06:29 +0530)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 27 Aug 2024 13:48:35 +0000 (15:48 +0200)
The RINTC subtype structure in MADT also has information about other
interrupt controllers. Save this information and provide interfaces to
retrieve them when required by corresponding drivers.

Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Björn Töpel <bjorn@rivosinc.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://patch.msgid.link/20240812005929.113499-14-sunilvl@ventanamicro.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
arch/riscv/include/asm/irq.h
drivers/irqchip/irq-riscv-intc.c

index 44a0b128c60280e41064274e88dac3e402c560df..7e9a84a005edffa41dfb08e003ff0bfa4980d819 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <asm-generic/irq.h>
 
+#define INVALID_CONTEXT UINT_MAX
+
 void riscv_set_intc_hwnode_fn(struct fwnode_handle *(*fn)(void));
 
 struct fwnode_handle *riscv_get_intc_hwnode(void);
@@ -28,6 +30,11 @@ enum riscv_irqchip_type {
 int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,
                            u32 *id, u32 *nr_irqs, u32 *nr_idcs);
 struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi);
+unsigned long acpi_rintc_index_to_hartid(u32 index);
+unsigned long acpi_rintc_ext_parent_to_hartid(unsigned int plic_id, unsigned int ctxt_idx);
+unsigned int acpi_rintc_get_plic_nr_contexts(unsigned int plic_id);
+unsigned int acpi_rintc_get_plic_context(unsigned int plic_id, unsigned int ctxt_idx);
+int __init acpi_rintc_get_imsic_mmio_info(u32 index, struct resource *res);
 
 #else
 static inline int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,
@@ -36,6 +43,32 @@ static inline int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi
        return 0;
 }
 
+static inline unsigned long acpi_rintc_index_to_hartid(u32 index)
+{
+       return INVALID_HARTID;
+}
+
+static inline unsigned long acpi_rintc_ext_parent_to_hartid(unsigned int plic_id,
+                                                           unsigned int ctxt_idx)
+{
+       return INVALID_HARTID;
+}
+
+static inline unsigned int acpi_rintc_get_plic_nr_contexts(unsigned int plic_id)
+{
+       return INVALID_CONTEXT;
+}
+
+static inline unsigned int acpi_rintc_get_plic_context(unsigned int plic_id, unsigned int ctxt_idx)
+{
+       return INVALID_CONTEXT;
+}
+
+static inline int __init acpi_rintc_get_imsic_mmio_info(u32 index, struct resource *res)
+{
+       return 0;
+}
+
 #endif /* CONFIG_ACPI */
 
 #endif /* _ASM_RISCV_IRQ_H */
index 47f3200476da5ee3c90f1f7c5c9b0cdac676ee7b..8c54113862205b4e50ed8a87da2e9ecd90107c10 100644 (file)
@@ -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;
 }