[PATCH v5 11/17] irqchip/riscv-imsic: Add S-mode MSI address list

From: Andrew Jones

Date: Mon Aug 31 2026 - 14:14:11 EST


Upcoming RISC-V IOMMU interrupt remapping needs to map every possible
host IMSIC target into one contiguous MSI IOVA range. MSI message
composition then uses the target CPU's position within that range.

Build an S-mode IMSIC physical address array indexed by logical CPU.
Require every possible CPU to have an initialized IMSIC page before
publishing the array. This preserves physical address zero as a valid
target and guarantees the array has num_possible_cpus() entries.

The array size and each target's index can therefore be derived
directly, without storing duplicate count or per-CPU index metadata.

Signed-off-by: Andrew Jones <andrew.jones@xxxxxxxxxxxxxxxx>
---
drivers/irqchip/irq-riscv-imsic-state.c | 32 +++++++++++++++++++++++++
drivers/irqchip/irq-riscv-imsic-state.h | 1 +
2 files changed, 33 insertions(+)

diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
index df38a7670a89..c7ebddd308ec 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.c
+++ b/drivers/irqchip/irq-riscv-imsic-state.c
@@ -709,6 +709,31 @@ static int __init imsic_get_mmio_resource(struct fwnode_handle *fwnode,
return of_address_to_resource(to_of_node(fwnode), index, res);
}

+static int __init imsic_init_smode_msi_pa(void)
+{
+ struct imsic_global_config *global = &imsic->global;
+ phys_addr_t *smode_msi_pa;
+ unsigned int cpu;
+
+ smode_msi_pa = kcalloc(num_possible_cpus(), sizeof(*smode_msi_pa), GFP_KERNEL);
+ if (!smode_msi_pa)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu) {
+ struct imsic_local_config *local = per_cpu_ptr(global->local, cpu);
+
+ if (!local->msi_va) {
+ kfree(smode_msi_pa);
+ return -ENODEV;
+ }
+
+ smode_msi_pa[cpu] = local->msi_pa;
+ }
+
+ imsic->smode_msi_pa = smode_msi_pa;
+ return 0;
+}
+
static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
struct imsic_global_config *global,
u32 *nr_parent_irqs,
@@ -959,6 +984,12 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
goto out_local_cleanup;
}

+ rc = imsic_init_smode_msi_pa();
+ if (rc) {
+ pr_err("%pfwP: failed to initialize S-mode MSI addresses\n", fwnode);
+ goto out_local_cleanup;
+ }
+
/* Initialize matrix allocator */
rc = imsic_matrix_init();
if (rc) {
@@ -984,6 +1015,7 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
out_free_local:
free_percpu(imsic->global.local);
out_free_priv:
+ kfree(imsic->smode_msi_pa);
kfree(imsic);
imsic = NULL;
return rc;
diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h
index c42ee180b305..11352f14e32d 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.h
+++ b/drivers/irqchip/irq-riscv-imsic-state.h
@@ -49,6 +49,7 @@ struct imsic_priv {

/* Global configuration common for all HARTs */
struct imsic_global_config global;
+ phys_addr_t *smode_msi_pa;

/* Per-CPU state */
struct imsic_local_priv __percpu *lpriv;
--
2.43.0