From: Jian Zhang zhangjian210@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I931MI CVE: NA
----------------------------------
When using svm_svsp_bind_core, the expected pasid is the pasid of the origin mm with its highest bit set, so we need to check and get the expected pasid instead of allocating a new one.
Signed-off-by: Jian Zhang zhangjian210@huawei.com Signed-off-by: Yuan Can yuancan@huawei.com --- drivers/iommu/iommu-sva.c | 4 ++++ drivers/iommu/iommu.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/iommu.h | 3 +++ 3 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index b78671a8a914..99b2977ff708 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -25,6 +25,10 @@ static int iommu_sva_alloc_pasid(struct mm_struct *mm, struct device *dev) if (mm_valid_pasid(mm)) { if (mm->pasid >= dev->iommu->max_pasids) ret = -EOVERFLOW; +#ifdef CONFIG_ASCEND_SVSP + else + ret = iommu_reserve_svsp_pasid(mm, dev); +#endif goto out; }
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 32f0f6c461b3..594d9e984d57 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -3697,20 +3697,54 @@ struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, return domain; }
+#ifdef CONFIG_ASCEND_SVSP +int iommu_reserve_svsp_pasid(struct mm_struct *mm, struct device *dev) +{ + int ret; + int max_pasids = dev->iommu->max_pasids; + + /* This should never happen. */ + if (!max_pasids) + return -ENOSPC; + + /* Do nothing if the given PASID not in SVSP pasid range. */ + if (mm->pasid < max_pasids >> 1) + return 0; + + /* Reserve the given SVSP pasid. */ + ret = ida_alloc_range(&iommu_global_pasid_ida, mm->pasid, mm->pasid, + GFP_KERNEL); + if (ret == -ENOMEM) + return -ENOSPC; + + return 0; +} +#endif + ioasid_t iommu_alloc_global_pasid(struct device *dev) { int ret; + int max_pasids;
/* max_pasids == 0 means that the device does not support PASID */ if (!dev->iommu->max_pasids) return IOMMU_PASID_INVALID;
+ max_pasids = dev->iommu->max_pasids - 1; +#ifdef CONFIG_ASCEND_SVSP + /* + * When SVSP feature is enabled, the pasid space is divided into two + * equal parts, the normal pasids are distributed in the range with + * smaller value. + */ + max_pasids = max_pasids >> 1; +#endif /* * max_pasids is set up by vendor driver based on number of PASID bits * supported but the IDA allocation is inclusive. */ ret = ida_alloc_range(&iommu_global_pasid_ida, IOMMU_FIRST_GLOBAL_PASID, - dev->iommu->max_pasids - 1, GFP_KERNEL); + max_pasids, GFP_KERNEL); return ret < 0 ? IOMMU_PASID_INVALID : ret; } EXPORT_SYMBOL_GPL(iommu_alloc_global_pasid); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index a1be18a687b6..e6f22dfa0205 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -833,6 +833,9 @@ iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid, unsigned int type); ioasid_t iommu_alloc_global_pasid(struct device *dev); void iommu_free_global_pasid(ioasid_t pasid); +#ifdef CONFIG_ASCEND_SVSP +int iommu_reserve_svsp_pasid(struct mm_struct *mm, struct device *dev); +#endif #else /* CONFIG_IOMMU_API */
struct iommu_ops {};