[RFC PATCH 1/3] iommu/riscv: Complete MRIF MSI PTE setup
Zhanpeng Zhang
zhangzhanpeng.jasper at bytedance.com
Tue Jun 30 21:00:14 PDT 2026
The MRIF path can retarget an existing MSI table entry, but it does
not fully handle installing a new MRIF MSI table entry. It also encodes
the MRIF target with the normal PPN helper even though a RISC-V IOMMU MSI
PTE uses MRIF_ADDR[53:7] in MRIF mode.
Add a dedicated MRIF PTE helper and use it for both the new-table and
retarget paths. This keeps the normal MSI PTE encoding unchanged while
programming the MRIF address and information fields when vCPU affinity
requests MRIF delivery.
Publish MRIF entries so the notice information is visible before the
valid PTE word is installed. When rewriting a live entry, clear the PTE
word first and order the mrif_info update before publishing the
replacement PTE, so a racing device MSI does not observe a valid MRIF PTE
with stale notice data.
Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com>
---
drivers/iommu/riscv/iommu-ir.c | 96 ++++++++++++++++++++++++++--------
1 file changed, 75 insertions(+), 21 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-ir.c b/drivers/iommu/riscv/iommu-ir.c
index ccbb7aa74a25..82fbb44d6df0 100644
--- a/drivers/iommu/riscv/iommu-ir.c
+++ b/drivers/iommu/riscv/iommu-ir.c
@@ -119,10 +119,11 @@ static void riscv_iommu_ir_set_pte(struct riscv_iommu_msipte *pte, u64 addr)
static void riscv_iommu_ir_set_mrif_pte(struct riscv_iommu_msipte *pte, u64 addr, u64 mrif_info)
{
+ pte->mrif_info = mrif_info;
+ dma_wmb();
pte->pte = FIELD_PREP(RISCV_IOMMU_MSIPTE_M, 1) |
- riscv_iommu_phys_to_ppn(addr) |
+ riscv_iommu_phys_to_mrif(addr) |
FIELD_PREP(RISCV_IOMMU_MSIPTE_V, 1);
- pte->mrif_info = mrif_info;
}
static void riscv_iommu_ir_clear_pte(struct riscv_iommu_msipte *pte)
@@ -131,6 +132,17 @@ static void riscv_iommu_ir_clear_pte(struct riscv_iommu_msipte *pte)
pte->mrif_info = 0;
}
+static void riscv_iommu_ir_update_pte(struct riscv_iommu_msipte *pte,
+ const struct riscv_iommu_msipte *pteval)
+{
+ /* Rewrite live entries without exposing stale MRIF notice data. */
+ pte->pte = 0;
+ dma_wmb();
+ pte->mrif_info = pteval->mrif_info;
+ dma_wmb();
+ pte->pte = pteval->pte;
+}
+
static void riscv_iommu_ir_msitbl_inval(struct riscv_iommu_domain *domain)
{
struct riscv_iommu_bond *bond;
@@ -337,14 +349,65 @@ static bool riscv_iommu_ir_vcpu_check_config(struct riscv_iommu_domain *domain,
domain->group_index_shift == vcpu_info->group_index_shift;
}
+static int riscv_iommu_ir_get_mrif_info(struct irq_data *data,
+ struct riscv_iommu_ir_vcpu_info *vcpu_info,
+ u64 *mrif_info)
+{
+ struct device *dev;
+ struct riscv_iommu_device *iommu;
+ struct msi_desc *desc;
+ struct irq_data *irqdata;
+ struct irq_chip *chip;
+
+ *mrif_info = 0;
+ if (!vcpu_info->mrif)
+ return 0;
+
+ if (!vcpu_info->host_msg)
+ return -EINVAL;
+
+ desc = irq_data_get_msi_desc(data);
+ if (!desc)
+ return -EINVAL;
+
+ dev = msi_desc_to_dev(desc);
+ if (!dev)
+ return -EINVAL;
+
+ iommu = dev_to_iommu(dev);
+ if (!iommu)
+ return -ENODEV;
+
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_MRIF)) {
+ irqdata = irq_get_irq_data(vcpu_info->host_irq);
+ chip = irqdata ? irq_data_get_irq_chip(irqdata) : NULL;
+ if (!chip || !chip->irq_write_msi_msg)
+ return -EOPNOTSUPP;
+
+ chip->irq_write_msi_msg(irqdata, vcpu_info->host_msg);
+ return -ENODEV;
+ }
+
+ *mrif_info = riscv_iommu_data_to_nid(vcpu_info->host_msg->data) |
+ riscv_iommu_phys_to_nppn((u64)vcpu_info->host_msg->address_hi << 32 |
+ vcpu_info->host_msg->address_lo);
+
+ return 0;
+}
+
static int riscv_iommu_ir_vcpu_new_config(struct riscv_iommu_domain *domain,
struct irq_data *data,
struct riscv_iommu_ir_vcpu_info *vcpu_info)
{
struct riscv_iommu_msipte *pte;
+ u64 mrif_info;
size_t idx;
int ret;
+ ret = riscv_iommu_ir_get_mrif_info(data, vcpu_info, &mrif_info);
+ if (ret)
+ return ret;
+
if (domain->pgd_mode)
riscv_iommu_ir_unmap_imsics(domain);
@@ -378,8 +441,10 @@ static int riscv_iommu_ir_vcpu_new_config(struct riscv_iommu_domain *domain,
idx = riscv_iommu_ir_compute_msipte_idx(domain, vcpu_info->gpa);
pte = &domain->msi_root[idx];
riscv_iommu_ir_irq_set_msitbl_info(data, idx, domain->msitbl_config);
- BUG_ON(vcpu_info->mrif);
- riscv_iommu_ir_set_pte(pte, vcpu_info->hpa);
+ if (vcpu_info->mrif)
+ riscv_iommu_ir_set_mrif_pte(pte, vcpu_info->hpa, mrif_info);
+ else
+ riscv_iommu_ir_set_pte(pte, vcpu_info->hpa);
riscv_iommu_ir_msitbl_inval(domain);
refcount_set(&domain->msi_pte_counts[idx], 1);
@@ -393,15 +458,13 @@ static int riscv_iommu_ir_irq_set_vcpu_affinity(struct irq_data *data, void *arg
struct riscv_iommu_info *info = data->domain->host_data;
struct riscv_iommu_domain *domain = info->domain;
struct riscv_iommu_ir_vcpu_info *vcpu_info = arg;
- struct device *dev = msi_desc_to_dev(irq_data_get_msi_desc(data));
- struct riscv_iommu_device *iommu = dev_to_iommu(dev);
struct riscv_iommu_msipte pteval;
struct riscv_iommu_msipte *pte;
bool inc = false, dec = false;
size_t old_idx, new_idx;
u32 old_config;
u64 mrif_info = 0;
- bool mrif_support = (iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_MRIF);
+ int ret;
if (!domain->msi_root)
return -EOPNOTSUPP;
@@ -422,18 +485,9 @@ static int riscv_iommu_ir_irq_set_vcpu_affinity(struct irq_data *data, void *arg
if (!riscv_iommu_ir_vcpu_check_config(domain, vcpu_info))
return riscv_iommu_ir_vcpu_new_config(domain, data, vcpu_info);
- if (vcpu_info->mrif) {
- if (!mrif_support) {
- struct irq_data *irqdata = irq_get_irq_data(vcpu_info->host_irq);
- irq_data_get_irq_chip(irqdata)->irq_write_msi_msg(irqdata,
- vcpu_info->host_msg);
- return -ENODEV;
- }
- mrif_info = riscv_iommu_data_to_nid(vcpu_info->host_msg->data) |
- riscv_iommu_phys_to_nppn(
- (u64)vcpu_info->host_msg->address_hi << 32 |
- vcpu_info->host_msg->address_lo);
- }
+ ret = riscv_iommu_ir_get_mrif_info(data, vcpu_info, &mrif_info);
+ if (ret)
+ return ret;
new_idx = riscv_iommu_ir_compute_msipte_idx(domain, vcpu_info->gpa);
riscv_iommu_ir_irq_set_msitbl_info(data, new_idx, domain->msitbl_config);
@@ -444,8 +498,8 @@ static int riscv_iommu_ir_irq_set_vcpu_affinity(struct irq_data *data, void *arg
else
riscv_iommu_ir_set_pte(&pteval, vcpu_info->hpa);
- if (pteval.pte != pte->pte) {
- *pte = pteval;
+ if (pteval.pte != pte->pte || pteval.mrif_info != pte->mrif_info) {
+ riscv_iommu_ir_update_pte(pte, &pteval);
riscv_iommu_ir_msitbl_inval(domain);
}
--
2.50.1 (Apple Git-155)
More information about the linux-riscv
mailing list