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 --- 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)