* [PATCH v7 0/5] iommu/riscv: Enable MSI remapping and IOMMU_DMA
@ 2026-10-22 15:45 Andrew Jones
2026-10-22 15:45 ` [PATCH v7 1/5] iommu/dma: Prepare MSI physical address lists Andrew Jones
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Andrew Jones @ 2026-10-22 15:45 UTC (permalink / raw)
To: linux-riscv, iommu
Cc: linux-kernel, tomasz.jeznach, jgg, jgg, joro, will, robin.murphy,
pjw, palmer, anup, tglx, kevin.tian, fangyu.yu, nutty.liu
This series adds MSI remapping for IMSIC so a device's MSI target gets
translated the same way its DMA does, allowing RISC-V to enable IOMMU_DMA
and paging domains by default.
The IMSIC MSI target address changes with interrupt affinity, so every
possible target must be mapped before an affinity change can select it
in atomic context. The IMSIC driver prepares an ordered list of targets
with iommu_dma_prepare_msi_list() when allocating an IRQ. DMA-IOMMU maps
the list into one contiguous IOVA range and caches the base in the domain.
The MSI descriptor carries the base IOVA and mapping granule, allowing
IMSIC to compose the target address without allocating memory or looking
up IOMMU state during affinity changes.
Ordered-list mappings have their own cache, separate from the existing
single-page MSI cache. IOVA allocation, mapping and rollback are shared
between the two paths.
VFIO and iommufd support from v6[1] is deferred. This series does not
enable VFIO_IOMMU_TYPE1 or introduce an IOMMU_RESV_SW_MSI reservation.
I'll look into Nicolin's MSI-window configuration patches[2] in a
follow-on series and see if I can avoid introducing IOMMU_RESV_SW_MSI
entirely. Without that reservation, the legacy Type1 backend cannot
provide the MSI mappings it needs, so I'll try to support existing Type1
userspace through iommufd's compatibility interface. That path will need
automatic MSI IOVA allocation, since existing Type1 userspace won't issue
Nicolin's new ioctls.
LLM-based coding assistants were used during development for code
exploration, patch review, test execution, and drafting and editing
commit messages and this cover letter. I reviewed and finalized all
resulting code and text. Per-patch Assisted-by tags are omitted in
light of ongoing discussions about simplifying coding-assistant
attribution.
Thanks,
drew
[1] https://lore.kernel.org/all/20260925151659.419512-1-andrew.jones@oss.qualcomm.com/
[2] https://lore.kernel.org/linux-iommu/cover.1760487869.git.nicolinc@nvidia.com/
v7:
- Rebased on linux-iommu/next at 20bfd2575765
- Added deferred-attach handling to the list API
- Simplified ordered-list mapping to a cached base IOVA per domain,
separate from the existing per-page cache [Robin]
- Shared IOVA allocation, mapping and rollback between the list and
single-page paths [Jason]
- Dropped the fixed MSI window in response to Jason's ABI concerns and
deferred supporting VFIO Type1
Andrew Jones (4):
iommu/dma: Prepare MSI physical address lists
iommu/dma: Introduce iommu_dma_prepare_msi_list()
irqchip/riscv-imsic: Add MSI address list
irqchip/riscv-imsic: Support IOMMU MSI address lists
Tomasz Jeznach (1):
iommu/dma: Enable IOMMU_DMA for 64-bit RISC-V
drivers/iommu/Kconfig | 2 +-
drivers/iommu/dma-iommu.c | 77 ++++++++++++++++++++--
drivers/iommu/dma-iommu.h | 10 +++
drivers/iommu/iommu.c | 43 ++++++++++++
drivers/irqchip/Kconfig | 1 +
drivers/irqchip/irq-riscv-imsic-platform.c | 24 ++++++-
drivers/irqchip/irq-riscv-imsic-state.c | 32 +++++++++
drivers/irqchip/irq-riscv-imsic-state.h | 3 +
include/linux/iommu.h | 9 +++
9 files changed, 190 insertions(+), 11 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 1/5] iommu/dma: Prepare MSI physical address lists
2026-10-22 15:45 [PATCH v7 0/5] iommu/riscv: Enable MSI remapping and IOMMU_DMA Andrew Jones
@ 2026-10-22 15:45 ` Andrew Jones
2026-10-22 15:46 ` [PATCH v7 2/5] iommu/dma: Introduce iommu_dma_prepare_msi_list() Andrew Jones
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Andrew Jones @ 2026-10-22 15:45 UTC (permalink / raw)
To: linux-riscv, iommu
Cc: linux-kernel, tomasz.jeznach, jgg, jgg, joro, will, robin.murphy,
pjw, palmer, anup, tglx, kevin.tian, fangyu.yu, nutty.liu
IMSIC affinity changes need every possible target mapped. Introduce
iommu_dma_sw_msi_list() to cache one contiguous IOVA range base for
a list of targets.
Signed-off-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
---
drivers/iommu/dma-iommu.c | 77 +++++++++++++++++++++++++++++++++++----
drivers/iommu/dma-iommu.h | 10 +++++
2 files changed, 80 insertions(+), 7 deletions(-)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 1f624f241ac1..1046b19be584 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -59,6 +59,8 @@ struct iommu_dma_options {
struct iommu_dma_cookie {
struct iova_domain iovad;
struct list_head msi_page_list;
+ /* Base IOVA of the complete MSI target list */
+ dma_addr_t msi_list_iova;
/* Flush queue */
union {
struct iova_fq *single_fq;
@@ -2204,13 +2206,42 @@ static struct list_head *cookie_msi_pages(const struct iommu_domain *domain)
}
}
+static dma_addr_t iommu_dma_alloc_msi_iova(struct device *dev, struct iommu_domain *domain,
+ const phys_addr_t *phys_addrs,
+ unsigned int nr_addrs, size_t granule)
+{
+ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+ size_t size = nr_addrs * granule;
+ dma_addr_t iova;
+ unsigned int i;
+
+ iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
+ if (!iova)
+ return 0;
+
+ for (i = 0; i < nr_addrs; i++) {
+ if (iommu_map(domain, iova + i * granule, phys_addrs[i], granule,
+ prot, GFP_KERNEL))
+ goto out_unmap;
+ }
+ return iova;
+
+out_unmap:
+ if (i) {
+ size_t mapped = i * granule;
+
+ WARN_ON_ONCE(iommu_unmap(domain, iova, mapped) != mapped);
+ }
+ iommu_dma_free_iova(domain, iova, size, NULL);
+ return 0;
+}
+
static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
phys_addr_t msi_addr, struct iommu_domain *domain)
{
struct list_head *msi_page_list = cookie_msi_pages(domain);
struct iommu_dma_msi_page *msi_page;
dma_addr_t iova;
- int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
size_t size = cookie_msi_granule(domain);
static DEFINE_MUTEX(msi_prepare_lock);
@@ -2235,21 +2266,16 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
if (!msi_page)
return NULL;
- iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
+ iova = iommu_dma_alloc_msi_iova(dev, domain, &msi_addr, 1, size);
if (!iova)
goto out_free_page;
- if (iommu_map(domain, iova, msi_addr, size, prot, GFP_KERNEL))
- goto out_free_iova;
-
INIT_LIST_HEAD(&msi_page->list);
msi_page->phys = msi_addr;
msi_page->iova = iova;
list_add(&msi_page->list, msi_page_list);
return msi_page;
-out_free_iova:
- iommu_dma_free_iova(domain, iova, size, NULL);
out_free_page:
kfree(msi_page);
return NULL;
@@ -2271,6 +2297,43 @@ int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
return 0;
}
+/*
+ * All calls for a DMA domain must supply the same complete target list.
+ * The group mutex serializes creation and reuse of the cached mapping.
+ */
+int iommu_dma_sw_msi_list(struct iommu_domain *domain, struct msi_desc *desc,
+ const phys_addr_t *phys_addrs, unsigned int nr_addrs,
+ size_t granule)
+{
+ struct device *dev = msi_desc_to_dev(desc);
+ struct iommu_dma_cookie *cookie;
+ unsigned int i;
+
+ iommu_group_mutex_assert(dev);
+ if (domain->cookie_type != IOMMU_COOKIE_DMA_IOVA)
+ return -EOPNOTSUPP;
+
+ cookie = domain->iova_cookie;
+ if (granule < PAGE_SIZE || granule != cookie->iovad.granule)
+ return -EOPNOTSUPP;
+ if (!nr_addrs || nr_addrs > SIZE_MAX / granule)
+ return -EINVAL;
+
+ if (!cookie->msi_list_iova) {
+ for (i = 0; i < nr_addrs; i++)
+ if (!IS_ALIGNED(phys_addrs[i], granule))
+ return -EINVAL;
+
+ cookie->msi_list_iova = iommu_dma_alloc_msi_iova(dev, domain, phys_addrs,
+ nr_addrs, granule);
+ if (!cookie->msi_list_iova)
+ return -ENOMEM;
+ }
+
+ msi_desc_set_iommu_msi_iova(desc, cookie->msi_list_iova, ilog2(granule));
+ return 0;
+}
+
static int iommu_dma_init(void)
{
if (is_kdump_kernel())
diff --git a/drivers/iommu/dma-iommu.h b/drivers/iommu/dma-iommu.h
index 040d00252563..2a36ed736910 100644
--- a/drivers/iommu/dma-iommu.h
+++ b/drivers/iommu/dma-iommu.h
@@ -21,6 +21,9 @@ void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
phys_addr_t msi_addr);
+int iommu_dma_sw_msi_list(struct iommu_domain *domain, struct msi_desc *desc,
+ const phys_addr_t *phys_addrs, unsigned int nr_addrs,
+ size_t granule);
extern bool iommu_dma_forcedac;
@@ -59,5 +62,12 @@ static inline int iommu_dma_sw_msi(struct iommu_domain *domain,
return -ENODEV;
}
+static inline int iommu_dma_sw_msi_list(struct iommu_domain *domain, struct msi_desc *desc,
+ const phys_addr_t *phys_addrs, unsigned int nr_addrs,
+ size_t granule)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_IOMMU_DMA */
#endif /* __DMA_IOMMU_H */
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 2/5] iommu/dma: Introduce iommu_dma_prepare_msi_list()
2026-10-22 15:45 [PATCH v7 0/5] iommu/riscv: Enable MSI remapping and IOMMU_DMA Andrew Jones
2026-10-22 15:45 ` [PATCH v7 1/5] iommu/dma: Prepare MSI physical address lists Andrew Jones
@ 2026-10-22 15:46 ` Andrew Jones
2026-10-22 15:46 ` [PATCH v7 3/5] irqchip/riscv-imsic: Add MSI address list Andrew Jones
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Andrew Jones @ 2026-10-22 15:46 UTC (permalink / raw)
To: linux-riscv, iommu
Cc: linux-kernel, tomasz.jeznach, jgg, jgg, joro, will, robin.murphy,
pjw, palmer, anup, tglx, kevin.tian, fangyu.yu, nutty.liu
IMSIC needs an interface to prepare all MSI targets before an IRQ
affinity change can select one in atomic context.
Signed-off-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
---
drivers/iommu/iommu.c | 43 +++++++++++++++++++++++++++++++++++++++++++
include/linux/iommu.h | 9 +++++++++
2 files changed, 52 insertions(+)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b486b8bbd1fc..b8d4d601efd4 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -4266,4 +4266,47 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
mutex_unlock(&group->mutex);
return ret;
}
+
+/**
+ * iommu_dma_prepare_msi_list() - Map the complete list of MSI targets
+ * @desc: MSI descriptor to receive the base IOVA and granule shift
+ * @phys_addrs: Ordered array of target physical addresses
+ * @nr_addrs: Number of targets in the array
+ * @granule: Size and alignment of each target mapping
+ *
+ * Every call for a DMA domain must supply the same complete list, order and
+ * granule. The first call maps the targets into one contiguous IOVA range;
+ * subsequent calls use the cached base. The array is consumed synchronously
+ * and is not retained.
+ *
+ * Each target must be aligned to @granule, which must match the DMA domain's
+ * granule and be at least PAGE_SIZE.
+ *
+ * Without a translated domain, @desc is left unchanged. Only DMA-IOMMU
+ * domains currently support translated MSI target lists.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int iommu_dma_prepare_msi_list(struct msi_desc *desc, const phys_addr_t *phys_addrs,
+ unsigned int nr_addrs, size_t granule)
+{
+ struct device *dev = msi_desc_to_dev(desc);
+ struct iommu_group *group = dev->iommu_group;
+ struct iommu_domain *domain;
+ int ret;
+
+ if (!group)
+ return 0;
+
+ ret = iommu_deferred_attach(dev, iommu_get_domain_for_dev(dev));
+ if (ret)
+ return ret;
+
+ guard(mutex)(&group->mutex);
+ domain = group->domain;
+ if (!domain || domain->type == IOMMU_DOMAIN_IDENTITY)
+ return 0;
+
+ return iommu_dma_sw_msi_list(domain, desc, phys_addrs, nr_addrs, granule);
+}
#endif /* CONFIG_IRQ_MSI_IOMMU */
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 95e32c78dcb7..cf33169ec3e3 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -1560,12 +1560,21 @@ static inline void pci_dev_reset_iommu_done(struct pci_dev *pdev)
#ifdef CONFIG_IRQ_MSI_IOMMU
#ifdef CONFIG_IOMMU_API
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr);
+int iommu_dma_prepare_msi_list(struct msi_desc *desc, const phys_addr_t *phys_addrs,
+ unsigned int nr_addrs, size_t granule);
#else
static inline int iommu_dma_prepare_msi(struct msi_desc *desc,
phys_addr_t msi_addr)
{
return 0;
}
+
+static inline int iommu_dma_prepare_msi_list(struct msi_desc *desc,
+ const phys_addr_t *phys_addrs,
+ unsigned int nr_addrs, size_t granule)
+{
+ return 0;
+}
#endif /* CONFIG_IOMMU_API */
#endif /* CONFIG_IRQ_MSI_IOMMU */
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 3/5] irqchip/riscv-imsic: Add MSI address list
2026-10-22 15:45 [PATCH v7 0/5] iommu/riscv: Enable MSI remapping and IOMMU_DMA Andrew Jones
2026-10-22 15:45 ` [PATCH v7 1/5] iommu/dma: Prepare MSI physical address lists Andrew Jones
2026-10-22 15:46 ` [PATCH v7 2/5] iommu/dma: Introduce iommu_dma_prepare_msi_list() Andrew Jones
@ 2026-10-22 15:46 ` Andrew Jones
2026-10-22 15:46 ` [PATCH v7 4/5] irqchip/riscv-imsic: Support IOMMU MSI address lists Andrew Jones
2026-10-22 15:46 ` [PATCH v7 5/5] iommu/dma: Enable IOMMU_DMA for 64-bit RISC-V Andrew Jones
4 siblings, 0 replies; 6+ messages in thread
From: Andrew Jones @ 2026-10-22 15:46 UTC (permalink / raw)
To: linux-riscv, iommu
Cc: linux-kernel, tomasz.jeznach, jgg, jgg, joro, will, robin.murphy,
pjw, palmer, anup, tglx, kevin.tian, fangyu.yu, nutty.liu
From: Andrew Jones <andrew.jones@oss.qualcomm.com>
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 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@oss.qualcomm.com>
Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
Tested-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Acked-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Acked-by: Anup Patel <anup@brainfault.org>
---
drivers/irqchip/irq-riscv-imsic-state.c | 32 +++++++++++++++++++++++++
drivers/irqchip/irq-riscv-imsic-state.h | 3 +++
2 files changed, 35 insertions(+)
diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
index b8d1bbbf42f7..eb525c324982 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.c
+++ b/drivers/irqchip/irq-riscv-imsic-state.c
@@ -687,6 +687,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_msi_pa_list(void)
+{
+ struct imsic_global_config *global = &imsic->global;
+ phys_addr_t *msi_pa_list;
+ unsigned int cpu;
+
+ msi_pa_list = kcalloc(num_possible_cpus(), sizeof(*msi_pa_list), GFP_KERNEL);
+ if (!msi_pa_list)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu) {
+ struct imsic_local_config *local = per_cpu_ptr(global->local, cpu);
+
+ if (!local->msi_va) {
+ kfree(msi_pa_list);
+ return -ENODEV;
+ }
+
+ msi_pa_list[cpu] = local->msi_pa;
+ }
+
+ imsic->msi_pa_list = msi_pa_list;
+ return 0;
+}
+
static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
struct imsic_global_config *global,
u32 *nr_parent_irqs,
@@ -937,6 +962,12 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
goto out_local_cleanup;
}
+ rc = imsic_init_msi_pa_list();
+ if (rc) {
+ pr_err("%pfwP: failed to initialize MSI address list\n", fwnode);
+ goto out_local_cleanup;
+ }
+
/* Initialize matrix allocator */
rc = imsic_matrix_init();
if (rc) {
@@ -962,6 +993,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->msi_pa_list);
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..e51c61dcced3 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.h
+++ b/drivers/irqchip/irq-riscv-imsic-state.h
@@ -50,6 +50,9 @@ struct imsic_priv {
/* Global configuration common for all HARTs */
struct imsic_global_config global;
+ /* MSI target physical addresses indexed by logical CPU for IOMMU mapping */
+ phys_addr_t *msi_pa_list;
+
/* Per-CPU state */
struct imsic_local_priv __percpu *lpriv;
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 4/5] irqchip/riscv-imsic: Support IOMMU MSI address lists
2026-10-22 15:45 [PATCH v7 0/5] iommu/riscv: Enable MSI remapping and IOMMU_DMA Andrew Jones
` (2 preceding siblings ...)
2026-10-22 15:46 ` [PATCH v7 3/5] irqchip/riscv-imsic: Add MSI address list Andrew Jones
@ 2026-10-22 15:46 ` Andrew Jones
2026-10-22 15:46 ` [PATCH v7 5/5] iommu/dma: Enable IOMMU_DMA for 64-bit RISC-V Andrew Jones
4 siblings, 0 replies; 6+ messages in thread
From: Andrew Jones @ 2026-10-22 15:46 UTC (permalink / raw)
To: linux-riscv, iommu
Cc: linux-kernel, tomasz.jeznach, jgg, jgg, joro, will, robin.murphy,
pjw, palmer, anup, tglx, kevin.tian, fangyu.yu, nutty.liu
From: Andrew Jones <andrew.jones@oss.qualcomm.com>
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@oss.qualcomm.com>
Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
Tested-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Acked-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Acked-by: Anup Patel <anup@brainfault.org>
---
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);
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 5/5] iommu/dma: Enable IOMMU_DMA for 64-bit RISC-V
2026-10-22 15:45 [PATCH v7 0/5] iommu/riscv: Enable MSI remapping and IOMMU_DMA Andrew Jones
` (3 preceding siblings ...)
2026-10-22 15:46 ` [PATCH v7 4/5] irqchip/riscv-imsic: Support IOMMU MSI address lists Andrew Jones
@ 2026-10-22 15:46 ` Andrew Jones
4 siblings, 0 replies; 6+ messages in thread
From: Andrew Jones @ 2026-10-22 15:46 UTC (permalink / raw)
To: linux-riscv, iommu
Cc: linux-kernel, tomasz.jeznach, jgg, jgg, joro, will, robin.murphy,
pjw, palmer, anup, tglx, kevin.tian, fangyu.yu, nutty.liu
From: Tomasz Jeznach <tomasz.jeznach@linux.dev>
Enable IOMMU_DMA for 64-bit RISC-V now that the RISC-V
IOMMU driver supports MSI remapping.
Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
Tested-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
---
drivers/iommu/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 85a8d7fdfa30..96b282ed38f9 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -151,7 +151,7 @@ config OF_IOMMU
# IOMMU-agnostic DMA-mapping layer
config IOMMU_DMA
- def_bool ARM64 || X86 || S390
+ def_bool ARM64 || X86 || S390 || (RISCV && 64BIT)
select DMA_OPS_HELPERS
select IOMMU_API
select IOMMU_IOVA
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-22 15:46 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22 15:45 [PATCH v7 0/5] iommu/riscv: Enable MSI remapping and IOMMU_DMA Andrew Jones
2026-10-22 15:45 ` [PATCH v7 1/5] iommu/dma: Prepare MSI physical address lists Andrew Jones
2026-10-22 15:46 ` [PATCH v7 2/5] iommu/dma: Introduce iommu_dma_prepare_msi_list() Andrew Jones
2026-10-22 15:46 ` [PATCH v7 3/5] irqchip/riscv-imsic: Add MSI address list Andrew Jones
2026-10-22 15:46 ` [PATCH v7 4/5] irqchip/riscv-imsic: Support IOMMU MSI address lists Andrew Jones
2026-10-22 15:46 ` [PATCH v7 5/5] iommu/dma: Enable IOMMU_DMA for 64-bit RISC-V Andrew Jones
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®