[PATCH v6 11/16] irqchip/riscv-imsic: Support IOMMU MSI address lists

Nutty.Liu nutty.liu at hotmail.com
Sun Sep 27 20:18:48 PDT 2026


On 9/25/2026 11:16 PM, Andrew Jones 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.
>
> Prepare the complete IMSIC address list while allocating an IRQ. The
> list is guaranteed to exist after IMSIC state initialization. The IOMMU
> backend maps the pages and caches the contiguous base IOVA in the MSI
> descriptor when translation is needed.
>
> 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. A zero iommu_msi_shift
> means no MSI address translation is required, so keep physical messages.
>
> Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
> Tested-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
Reviewed-by: Nutty Liu <nutty.liu at hotmail.com>

Thanks,
Nutty
> ---
>   drivers/irqchip/Kconfig                    |  1 +
>   drivers/irqchip/irq-riscv-imsic-platform.c | 24 +++++++++++++++++++---
>   2 files changed, 22 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 20b77fbc51ee..a038e1121be3 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -651,6 +651,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..ddb2bb570cdc 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,12 @@ 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;
>   
> +	/* A zero shift means no IOMMU MSI mapping is needed. */
> +	if (desc->iommu_msi_shift) {
> +		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 +95,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 +103,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 +234,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 +246,13 @@ static int imsic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
>   	if (!vec)
>   		return -ENOSPC;
>   
> +	ret = iommu_dma_prepare_msi_list(info->desc, imsic->msi_pa_list,
> +					 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);



More information about the linux-riscv mailing list