From a2735cd15160a62065a0a0b39af405c7b0f3fae8 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 22 Jun 2022 14:41:27 -0700 Subject: [PATCH] hw/arm/smmu-common: Add iommufd helpers Add a set of helper functions for IOMMUFD and new "struct SMMUS1Hwpt" to store the nested hwpt information. Signed-off-by: Nicolin Chen --- hw/arm/smmu-common.c | 108 +++++++++++++++++++++++++++++++++++ include/hw/arm/smmu-common.h | 20 +++++++ 2 files changed, 128 insertions(+) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 038ae857d8..a79eb34277 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -838,6 +838,114 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid) return NULL; } +/* IOMMUFD helpers */ +int smmu_dev_get_info(SMMUDevice *sdev, uint32_t *data_type, + uint32_t data_len, void *data) +{ + uint64_t caps; + + if (!sdev || !sdev->idev) { + return -ENOENT; + } + + return !iommufd_backend_get_device_info(sdev->idev->iommufd, + sdev->idev->devid, data_type, data, + data_len, &caps, NULL); +} + +void smmu_dev_uninstall_nested_ste(SMMUDevice *sdev, bool abort) +{ + HostIOMMUDeviceIOMMUFD *idev = sdev->idev; + SMMUS1Hwpt *s1_hwpt = sdev->s1_hwpt; + uint32_t hwpt_id; + + if (!s1_hwpt || !sdev->viommu) { + return; + } + + if (abort) { + hwpt_id = sdev->viommu->abort_hwpt_id; + } else { + hwpt_id = sdev->viommu->bypass_hwpt_id; + } + + if (!host_iommu_device_iommufd_attach_hwpt(idev, hwpt_id, NULL)) { + return; + } + + iommufd_backend_free_id(idev->iommufd, s1_hwpt->hwpt_id); + sdev->s1_hwpt = NULL; + g_free(s1_hwpt); +} + +int smmu_dev_install_nested_ste(SMMUDevice *sdev, uint32_t data_type, + uint32_t data_len, void *data) +{ + SMMUViommu *viommu = sdev->viommu; + SMMUS1Hwpt *s1_hwpt = sdev->s1_hwpt; + HostIOMMUDeviceIOMMUFD *idev = sdev->idev; + + if (!idev || !viommu) { + return -ENOENT; + } + + if (s1_hwpt) { + smmu_dev_uninstall_nested_ste(sdev, false); + } + + s1_hwpt = g_new0(SMMUS1Hwpt, 1); + if (!s1_hwpt) { + return -ENOMEM; + } + + s1_hwpt->smmu = sdev->smmu; + s1_hwpt->viommu = viommu; + s1_hwpt->iommufd = idev->iommufd; + + if (!iommufd_backend_alloc_hwpt(idev->iommufd, idev->devid, + viommu->core->viommu_id, 0, data_type, + data_len, data, &s1_hwpt->hwpt_id, NULL)) { + goto free; + } + + if (!host_iommu_device_iommufd_attach_hwpt(idev, s1_hwpt->hwpt_id, NULL)) { + goto free_hwpt; + } + + sdev->s1_hwpt = s1_hwpt; + + return 0; +free_hwpt: + iommufd_backend_free_id(idev->iommufd, s1_hwpt->hwpt_id); +free: + sdev->s1_hwpt = NULL; + g_free(s1_hwpt); + + return -EINVAL; +} + +int smmu_hwpt_invalidate_cache(SMMUS1Hwpt *s1_hwpt, uint32_t type, uint32_t len, + uint32_t *num, void *reqs) +{ + if (!s1_hwpt) { + return -ENOENT; + } + + return iommufd_backend_invalidate_cache(s1_hwpt->iommufd, s1_hwpt->hwpt_id, + type, len, num, reqs); +} + +int smmu_viommu_invalidate_cache(IOMMUFDViommu *viommu, uint32_t type, + uint32_t len, uint32_t *num, void *reqs) +{ + if (!viommu) { + return -ENOENT; + } + + return iommufd_viommu_invalidate_cache(viommu->iommufd, viommu->viommu_id, + type, len, num, reqs); +} + /* Unmap all notifiers attached to @mr */ static void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr) { diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 3bfb68cef6..66dc7206ea 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -125,6 +125,15 @@ typedef struct SMMUViommu { QLIST_ENTRY(SMMUViommu) next; } SMMUViommu; +typedef struct SMMUS1Hwpt { + void *smmu; + IOMMUFDBackend *iommufd; + SMMUViommu *viommu; + uint32_t hwpt_id; + QLIST_HEAD(, SMMUDevice) device_list; + QLIST_ENTRY(SMMUViommu) next; +} SMMUS1Hwpt; + typedef struct SMMUDevice { void *smmu; PCIBus *bus; @@ -132,6 +141,7 @@ typedef struct SMMUDevice { IOMMUMemoryRegion iommu; HostIOMMUDeviceIOMMUFD *idev; SMMUViommu *viommu; + SMMUS1Hwpt *s1_hwpt; AddressSpace as; uint32_t cfg_cache_hits; uint32_t cfg_cache_misses; @@ -225,4 +235,14 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova, /* Unmap the range of all the notifiers registered to any IOMMU mr */ void smmu_inv_notifiers_all(SMMUState *s); +/* IOMMUFD helpers */ +int smmu_dev_get_info(SMMUDevice *sdev, uint32_t *data_type, + uint32_t data_len, void *data); +void smmu_dev_uninstall_nested_ste(SMMUDevice *sdev, bool abort); +int smmu_dev_install_nested_ste(SMMUDevice *sdev, uint32_t data_type, + uint32_t data_len, void *data); +int smmu_hwpt_invalidate_cache(SMMUS1Hwpt *s1_hwpt, uint32_t type, uint32_t len, + uint32_t *num, void *reqs); +int smmu_viommu_invalidate_cache(IOMMUFDViommu *viommu, uint32_t type, + uint32_t len, uint32_t *num, void *reqs); #endif /* HW_ARM_SMMU_COMMON_H */ -- 2.41.0.windows.1