[PATCH v4 15/21] iommu/riscv: Remap IMSIC targets during MSI composition
Andrew Jones <[email protected]>
| Newsgroups | dev.linux.lists.iommu,org.infradead.lists.linux-riscv,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Translate composed IMSIC target addresses through the attached paging domain's pre-mapped IOVA table. This keeps affinity updates on the interrupt hierarchy while directing device MSI writes through the IOMMU. MSI composition may run in atomic context, so publish each fully built table with release ordering and consume it with acquire ordering under RCU. This permits lockless lookup without exposing incomplete table state. When no translated table is available, retain the physical IMSIC target for domains that do not use MSI address translation. Signed-off-by: Andrew Jones <[email protected]> --- drivers/iommu/riscv/iommu-ir.c | 41 +++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/riscv/iommu-ir.c b/drivers/iommu/riscv/iommu-ir.c index f61b65f29888..dacaefa62859 100644 --- a/drivers/iommu/riscv/iommu-ir.c +++ b/drivers/iommu/riscv/iommu-ir.c @@ -99,7 +99,8 @@ static int riscv_iommu_ir_build_msi_iova(struct riscv_iommu_domain *domain, stru } } - domain->msi_iova = msi_iova; + /* Pair with smp_load_acquire() in riscv_iommu_ir_compose_msi_msg() */ + smp_store_release(&domain->msi_iova, msi_iova); return 0; @@ -108,12 +109,50 @@ static int riscv_iommu_ir_build_msi_iova(struct riscv_iommu_domain *domain, stru return ret; } +static void riscv_iommu_ir_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct riscv_iommu_info *info = data->domain->host_data; + struct riscv_iommu_domain *domain; + dma_addr_t *msi_iova; + struct msi_desc *desc; + phys_addr_t pa; + size_t idx; + + BUG_ON(irq_chip_compose_msi_msg(data->parent_data, msg)); + + desc = irq_data_get_msi_desc(data); + if (WARN_ON_ONCE(!desc)) + return; + + guard(rcu)(); + + domain = rcu_dereference(info->domain); + if (!domain) { + msi_desc_set_iommu_msi_iova(desc, 0, 0); + return; + } + + /* Pair with smp_store_release() in riscv_iommu_ir_build_msi_iova() */ + msi_iova = smp_load_acquire(&domain->msi_iova); + if (!msi_iova) { + msi_desc_set_iommu_msi_iova(desc, 0, 0); + return; + } + + pa = ((u64)msg->address_hi << 32) | msg->address_lo; + idx = riscv_iommu_ir_msi_iova_idx(pa); + + msi_desc_set_iommu_msi_iova(desc, msi_iova[idx], IMSIC_MMIO_PAGE_SHIFT); + msi_msg_set_addr(desc, msg, pa); +} + static struct irq_chip riscv_iommu_ir_irq_chip = { .name = "IOMMU-IR", .irq_ack = irq_chip_ack_parent, .irq_mask = irq_chip_mask_parent, .irq_unmask = irq_chip_unmask_parent, .irq_set_affinity = irq_chip_set_affinity_parent, + .irq_compose_msi_msg = riscv_iommu_ir_compose_msi_msg, }; static int riscv_iommu_ir_irq_domain_alloc_irqs(struct irq_domain *irqdomain, -- 2.43.0