[PATCH v5 12/17] irqchip/riscv-imsic: Support IOMMU MSI address lists
Anup Patel
anup at brainfault.org
Wed Sep 23 05:01:05 PDT 2026
On Mon, Aug 31, 2026 at 8:30 PM Andrew Jones
<andrew.jones at oss.qualcomm.com> wrote:
>
> RISC-V IOMMU host interrupt remapping maps every possible host IMSIC
> target into one contiguous IOVA range. MSI message composition therefore
> needs each target's position within that range.
>
> When the S-mode IMSIC address list is available, prepare the complete
> list while allocating an IRQ. This allows the IOMMU backend to map the
> pages and cache the contiguous base IOVA in the MSI descriptor. Skip the
> optional preparation when no list is available, allowing devices which
> do not need IOMMU MSI translation to keep using physical MSI messages.
>
> When the descriptor has an IOMMU MSI mapping, use the selected logical
> CPU directly as the page index within the IOVA range. Use the same path
> for initial composition and affinity updates. Messages remain physical
> when no IOMMU MSI mapping is required.
>
> Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
> ---
> drivers/irqchip/Kconfig | 1 +
> drivers/irqchip/irq-riscv-imsic-platform.c | 25 +++++++++++++++++++---
> 2 files changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 42f2278a702d..c7cda52b21eb 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -656,6 +656,7 @@ config RISCV_IMSIC
> select IRQ_DOMAIN_HIERARCHY
> select GENERIC_IRQ_MATRIX_ALLOCATOR
> select GENERIC_MSI_IRQ
> + select IRQ_MSI_IOMMU
> select IRQ_MSI_LIB
>
> config RISCV_RPMI_SYSMSI
> diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
> index 643c8e459611..6e26a31f7503 100644
> --- a/drivers/irqchip/irq-riscv-imsic-platform.c
> +++ b/drivers/irqchip/irq-riscv-imsic-platform.c
> @@ -10,6 +10,7 @@
> #include <linux/cpu.h>
> #include <linux/interrupt.h>
> #include <linux/io.h>
> +#include <linux/iommu.h>
> #include <linux/irq.h>
> #include <linux/irqchip.h>
> #include <linux/irqdomain.h>
> @@ -69,8 +70,10 @@ static void imsic_irq_ack(struct irq_data *d)
> irq_move_irq(d);
> }
>
> -static void imsic_irq_compose_vector_msg(struct imsic_vector *vec, struct msi_msg *msg)
> +static void imsic_irq_compose_vector_msg(struct irq_data *d, struct imsic_vector *vec,
> + struct msi_msg *msg)
> {
> + struct msi_desc *desc = irq_data_get_msi_desc(d);
> phys_addr_t msi_addr;
>
> if (WARN_ON(!vec))
> @@ -79,6 +82,11 @@ static void imsic_irq_compose_vector_msg(struct imsic_vector *vec, struct msi_ms
> if (WARN_ON(!imsic_cpu_page_phys(vec->cpu, 0, &msi_addr)))
> return;
>
> + if (desc->iommu_msi_shift) {
Is it expected that iommu_msi_shift == 0 means no IOMMU in the path?
> + msi_addr = (desc->iommu_msi_iova << desc->iommu_msi_shift) +
> + vec->cpu * IMSIC_MMIO_PAGE_SZ;
> + }
> +
> msg->address_hi = upper_32_bits(msi_addr);
> msg->address_lo = lower_32_bits(msi_addr);
> msg->data = vec->local_id;
> @@ -86,7 +94,7 @@ static void imsic_irq_compose_vector_msg(struct imsic_vector *vec, struct msi_ms
>
> static void imsic_irq_compose_msg(struct irq_data *d, struct msi_msg *msg)
> {
> - imsic_irq_compose_vector_msg(irq_data_get_irq_chip_data(d), msg);
> + imsic_irq_compose_vector_msg(d, irq_data_get_irq_chip_data(d), msg);
> }
>
> #ifdef CONFIG_SMP
> @@ -94,7 +102,7 @@ static void imsic_msi_update_msg(struct irq_data *d, struct imsic_vector *vec)
> {
> struct msi_msg msg = { };
>
> - imsic_irq_compose_vector_msg(vec, &msg);
> + imsic_irq_compose_vector_msg(d, vec, &msg);
> irq_data_get_irq_chip(d)->irq_write_msi_msg(d, &msg);
> }
>
> @@ -225,7 +233,9 @@ static struct irq_chip imsic_irq_base_chip = {
> static int imsic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> unsigned int nr_irqs, void *args)
> {
> + msi_alloc_info_t *info = args;
> struct imsic_vector *vec;
> + int ret;
>
> /* Multi-MSI is not supported yet. */
> if (nr_irqs > 1)
> @@ -235,6 +245,15 @@ static int imsic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> if (!vec)
> return -ENOSPC;
>
> + if (imsic->smode_msi_pa) {
The imsic_setup_state() will fail if smode_msi_pa creation fails at
boot time so this looks like a paranoid check.
> + ret = iommu_dma_prepare_msi_list(info->desc, imsic->smode_msi_pa,
> + num_possible_cpus(), IMSIC_MMIO_PAGE_SZ);
> + if (ret) {
> + imsic_vector_free(vec);
> + return ret;
> + }
> + }
> +
> irq_domain_set_info(domain, virq, virq, &imsic_irq_base_chip, vec,
> handle_edge_irq, NULL, NULL);
> irq_set_noprobe(virq);
> --
> 2.43.0
>
Regards,
Anup
More information about the linux-riscv
mailing list