[PATCH 21/24] iommu/amd: Add translation DTE and VFctrl TransDevID helpers
Suravee Suthikulpanit <[email protected]> Mon, 27 Jul 2026 13:29:10 +0000
| Newsgroups | dev.linux.lists.iommu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
The hardware vIOMMU uses a per-vIOMMU translate device ID (TransDevID) to index the host device table when guest IOMMU traffic needs GPA->SPA translation. The VF Control guest miscellaneous register tells the IOMMU which TransDevID to use; the corresponding device table entry (DTE) points at the nest parent v1 page table that performs the walk from guest physical to system physical addresses. Add amd_iommu_set_translate_dte() and amd_iommu_clear_translate_dte() to install or clear that DTE for a given TransDevID slot through iommu_dev_data and the existing DTE update path, restoring IVRS persistent bits via amd_iommu_make_clear_dte() on teardown. Add amd_iommu_update_vfctrl_mmio_translate_devid() to publish the TransDevID in VFctrl guest-misc MMIO, and VIOMMU_VFCTRL_GUEST_MISC_CONTROL_OFFSET for the register offset. Signed-off-by: Suravee Suthikulpanit <[email protected]> --- drivers/iommu/amd/amd_iommu.h | 5 ++ drivers/iommu/amd/amd_iommu_types.h | 2 + drivers/iommu/amd/iommu.c | 82 ++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index f61cc51ef9a2..200640ed0ef6 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -232,6 +232,11 @@ static inline void amd_iommu_pci_seg_trans_devid_fini(struct amd_iommu_pci_seg *pci_seg) { } #endif +int amd_iommu_set_translate_dte(struct iommufd_viommu *viommu); +void amd_iommu_clear_translate_dte(struct amd_iommu *iommu, u32 trans_devid); +void amd_iommu_update_vfctrl_mmio_translate_devid(struct amd_iommu *iommu, + u16 gid, u32 trans_devid); + static inline void amd_iommu_make_clear_dte(struct amd_iommu *iommu, u16 devid, struct dev_table_entry *new) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index c102d059964a..f288a7b384d0 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -495,6 +495,7 @@ extern bool amdr_ivrs_remap_support; /* VIOMMU stuff */ #define VIOMMU_VF_MMIO_ENTRY_SIZE 4096 #define VIOMMU_VFCTRL_MMIO_ENTRY_SIZE 64 +#define VIOMMU_VFCTRL_GUEST_MISC_CONTROL_OFFSET 0x10 /* Host ioremap/request_mem_region sizes for VF / VF_CNTL BARs */ #define VIOMMU_VF_MMIO_MAP_SIZE 0x10000000UL @@ -556,6 +557,7 @@ struct amd_iommu_viommu { u64 *devid_table; u64 *domid_table; + u16 trans_devid; /* Offset for mmap() of guest VF MMIO; set after iommufd_viommu_alloc_mmap(). */ unsigned long vfmmio_mmap_offset; diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 6207879528bf..ad592c8aa455 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -213,7 +213,12 @@ void amd_iommu_update_dte(struct amd_iommu *iommu, struct dev_table_entry *new) { update_dte256(iommu, dev_data, new); - clone_aliases(iommu, dev_data->dev); + /* + * The dev_data for trans_devid does not have struct dev. + * So clone_aliases is not supported for translate-device-id. + */ + if (dev_data->dev) + clone_aliases(iommu, dev_data->dev); device_flush_dte(iommu, dev_data); amd_iommu_completion_wait(iommu); } @@ -1747,7 +1752,11 @@ static int device_flush_dte(struct amd_iommu *iommu, struct iommu_dev_data *dev_ u16 alias; int ret; - if (dev_is_pci(dev_data->dev)) + /* + * The dev_data for trans_devid does not have struct dev. + * So, it is not considered as a PCI device. + */ + if (dev_data->dev && dev_is_pci(dev_data->dev)) pdev = to_pci_dev(dev_data->dev); if (pdev) @@ -3275,6 +3284,75 @@ static bool amd_iommu_enforce_cache_coherency(struct iommu_domain *domain) return true; } +#if IS_ENABLED(CONFIG_AMD_IOMMU_IOMMUFD) + +void amd_iommu_update_vfctrl_mmio_translate_devid(struct amd_iommu *iommu, + u16 gid, u32 devid) +{ + writeq((devid & 0xFFFFULL) << 16, + VIOMMU_VFCTRL_MMIO_BASE(iommu, gid) + + VIOMMU_VFCTRL_GUEST_MISC_CONTROL_OFFSET); +} + +int amd_iommu_set_translate_dte(struct iommufd_viommu *viommu) +{ + struct amd_iommu_viommu *aviommu = + container_of(viommu, struct amd_iommu_viommu, core); + struct amd_iommu *iommu = + container_of(viommu->iommu_dev, struct amd_iommu, iommu); + struct protection_domain *pdom = aviommu->parent; + u16 gid = aviommu->gid; + u32 trans_devid = aviommu->trans_devid; + struct dev_table_entry new = {}; + struct iommu_dev_data *trans_dev_data; + struct pt_iommu_amdv1_hw_info pt_info; + + trans_dev_data = search_dev_data(iommu, trans_devid); + if (!trans_dev_data) { + trans_dev_data = amd_iommu_alloc_dev_data(iommu, trans_devid); + if (!trans_dev_data) { + pr_err("%s: Failed to allocate dev_data for translate-device-id %#x\n", + __func__, trans_devid); + return -ENOMEM; + } + } + + trans_dev_data->dev = NULL; + trans_dev_data->devid = trans_devid; + trans_dev_data->domain = pdom; + + amd_iommu_make_clear_dte(iommu, trans_devid, &new); + /* Setup DTE for v1 page table at the offset specified by trans_devid */ + pt_iommu_amdv1_hw_info(&pdom->amdv1, &pt_info); + + pr_debug("%s: gid=%#x, iommu_devid=%#x, devid=%#x, host_pt_root=%#llx, mode=%#x\n", + __func__, gid, iommu->devid, trans_devid, pt_info.host_pt_root, pt_info.mode); + + amd_iommu_set_dte_v1(trans_dev_data, pdom, pdom->id, &pt_info, &new); + amd_iommu_update_dte(iommu, trans_dev_data, &new); + return 0; +} + +void amd_iommu_clear_translate_dte(struct amd_iommu *iommu, u32 trans_devid) +{ + struct dev_table_entry new = {}; + struct iommu_dev_data *trans_dev_data; + + pr_debug("%s: iommu_devid=%#x, trans_devid=%#x\n", + __func__, iommu->devid, trans_devid); + + trans_dev_data = search_dev_data(iommu, trans_devid); + if (!trans_dev_data) { + WARN_ON_ONCE(1); + return; + } + + amd_iommu_make_clear_dte(iommu, trans_devid, &new); + amd_iommu_update_dte(iommu, trans_dev_data, &new); + amd_iommu_free_dev_data(iommu, trans_dev_data); +} +#endif /* CONFIG_AMD_IOMMU_IOMMUFD */ + const struct iommu_ops amd_iommu_ops = { .capable = amd_iommu_capable, .hw_info = amd_iommufd_hw_info, -- 2.34.1