提交 239deb9f 编写于 作者: L Lu Baolu 提交者: Xiaochen Shen

iommu/vt-d: Add pasid private data helpers

mainline inclusion
from mainline-v5.13
commit 100b8a14
category: feature
bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I596WO
CVE: NA

Intel-SIG: commit 100b8a14 iommu/vt-d: Add pasid private data helpers.
Incremental backporting patches for DSA/IAA on Intel Xeon platform.

--------------------------------

We are about to use iommu_sva_alloc/free_pasid() helpers in iommu core.
That means the pasid life cycle will be managed by iommu core. Use a
local array to save the per pasid private data instead of attaching it
the real pasid.
Signed-off-by: NLu Baolu <baolu.lu@linux.intel.com>
Link: https://lore.kernel.org/r/20210520031531.712333-1-baolu.lu@linux.intel.com
Link: https://lore.kernel.org/r/20210610020115.1637656-7-baolu.lu@linux.intel.comSigned-off-by: NJoerg Roedel <jroedel@suse.de>
Signed-off-by: NXiaochen Shen <xiaochen.shen@intel.com>
上级 5cec0ffa
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/dmar.h> #include <linux/dmar.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mm_types.h> #include <linux/mm_types.h>
#include <linux/xarray.h>
#include <linux/ioasid.h> #include <linux/ioasid.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/fpu/api.h> #include <asm/fpu/api.h>
...@@ -28,6 +29,23 @@ static void intel_svm_drain_prq(struct device *dev, u32 pasid); ...@@ -28,6 +29,23 @@ static void intel_svm_drain_prq(struct device *dev, u32 pasid);
#define PRQ_ORDER 0 #define PRQ_ORDER 0
static DEFINE_XARRAY_ALLOC(pasid_private_array);
static int pasid_private_add(ioasid_t pasid, void *priv)
{
return xa_alloc(&pasid_private_array, &pasid, priv,
XA_LIMIT(pasid, pasid), GFP_ATOMIC);
}
static void pasid_private_remove(ioasid_t pasid)
{
xa_erase(&pasid_private_array, pasid);
}
static void *pasid_private_find(ioasid_t pasid)
{
return xa_load(&pasid_private_array, pasid);
}
int intel_svm_enable_prq(struct intel_iommu *iommu) int intel_svm_enable_prq(struct intel_iommu *iommu)
{ {
struct page *pages; struct page *pages;
...@@ -224,7 +242,7 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid, ...@@ -224,7 +242,7 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
if (pasid == INVALID_IOASID || pasid >= PASID_MAX) if (pasid == INVALID_IOASID || pasid >= PASID_MAX)
return -EINVAL; return -EINVAL;
svm = ioasid_find(NULL, pasid, NULL); svm = pasid_private_find(pasid);
if (IS_ERR(svm)) if (IS_ERR(svm))
return PTR_ERR(svm); return PTR_ERR(svm);
...@@ -334,7 +352,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev, ...@@ -334,7 +352,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
svm->gpasid = data->gpasid; svm->gpasid = data->gpasid;
svm->flags |= SVM_FLAG_GUEST_PASID; svm->flags |= SVM_FLAG_GUEST_PASID;
} }
ioasid_set_data(data->hpasid, svm); pasid_private_add(data->hpasid, svm);
INIT_LIST_HEAD_RCU(&svm->devs); INIT_LIST_HEAD_RCU(&svm->devs);
mmput(svm->mm); mmput(svm->mm);
} }
...@@ -388,7 +406,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev, ...@@ -388,7 +406,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
list_add_rcu(&sdev->list, &svm->devs); list_add_rcu(&sdev->list, &svm->devs);
out: out:
if (!IS_ERR_OR_NULL(svm) && list_empty(&svm->devs)) { if (!IS_ERR_OR_NULL(svm) && list_empty(&svm->devs)) {
ioasid_set_data(data->hpasid, NULL); pasid_private_remove(data->hpasid);
kfree(svm); kfree(svm);
} }
...@@ -431,7 +449,7 @@ int intel_svm_unbind_gpasid(struct device *dev, u32 pasid) ...@@ -431,7 +449,7 @@ int intel_svm_unbind_gpasid(struct device *dev, u32 pasid)
* the unbind, IOMMU driver will get notified * the unbind, IOMMU driver will get notified
* and perform cleanup. * and perform cleanup.
*/ */
ioasid_set_data(pasid, NULL); pasid_private_remove(pasid);
kfree(svm); kfree(svm);
} }
} }
...@@ -547,8 +565,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags, ...@@ -547,8 +565,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
svm = kzalloc(sizeof(*svm), GFP_KERNEL); svm = kzalloc(sizeof(*svm), GFP_KERNEL);
if (!svm) { if (!svm) {
ret = -ENOMEM; ret = -ENOMEM;
kfree(sdev); goto sdev_err;
goto out;
} }
if (pasid_max > intel_pasid_max_id) if (pasid_max > intel_pasid_max_id)
...@@ -556,13 +573,16 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags, ...@@ -556,13 +573,16 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
/* Do not use PASID 0, reserved for RID to PASID */ /* Do not use PASID 0, reserved for RID to PASID */
svm->pasid = ioasid_alloc(NULL, PASID_MIN, svm->pasid = ioasid_alloc(NULL, PASID_MIN,
pasid_max - 1, svm); pasid_max - 1, NULL);
if (svm->pasid == INVALID_IOASID) { if (svm->pasid == INVALID_IOASID) {
kfree(svm);
kfree(sdev);
ret = -ENOSPC; ret = -ENOSPC;
goto out; goto svm_err;
} }
ret = pasid_private_add(svm->pasid, svm);
if (ret)
goto pasid_err;
svm->notifier.ops = &intel_mmuops; svm->notifier.ops = &intel_mmuops;
svm->mm = mm; svm->mm = mm;
svm->flags = flags; svm->flags = flags;
...@@ -571,12 +591,8 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags, ...@@ -571,12 +591,8 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
ret = -ENOMEM; ret = -ENOMEM;
if (mm) { if (mm) {
ret = mmu_notifier_register(&svm->notifier, mm); ret = mmu_notifier_register(&svm->notifier, mm);
if (ret) { if (ret)
ioasid_put(svm->pasid); goto priv_err;
kfree(svm);
kfree(sdev);
goto out;
}
} }
spin_lock_irqsave(&iommu->lock, iflags); spin_lock_irqsave(&iommu->lock, iflags);
...@@ -590,8 +606,13 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags, ...@@ -590,8 +606,13 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
if (ret) { if (ret) {
if (mm) if (mm)
mmu_notifier_unregister(&svm->notifier, mm); mmu_notifier_unregister(&svm->notifier, mm);
priv_err:
pasid_private_remove(svm->pasid);
pasid_err:
ioasid_put(svm->pasid); ioasid_put(svm->pasid);
svm_err:
kfree(svm); kfree(svm);
sdev_err:
kfree(sdev); kfree(sdev);
goto out; goto out;
} }
...@@ -614,10 +635,8 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags, ...@@ -614,10 +635,8 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
(cpu_feature_enabled(X86_FEATURE_LA57) ? (cpu_feature_enabled(X86_FEATURE_LA57) ?
PASID_FLAG_FL5LP : 0)); PASID_FLAG_FL5LP : 0));
spin_unlock_irqrestore(&iommu->lock, iflags); spin_unlock_irqrestore(&iommu->lock, iflags);
if (ret) { if (ret)
kfree(sdev); goto sdev_err;
goto out;
}
} }
list_add_rcu(&sdev->list, &svm->devs); list_add_rcu(&sdev->list, &svm->devs);
success: success:
...@@ -670,6 +689,7 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid) ...@@ -670,6 +689,7 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
load_pasid(svm->mm, PASID_DISABLED); load_pasid(svm->mm, PASID_DISABLED);
} }
list_del(&svm->list); list_del(&svm->list);
pasid_private_remove(svm->pasid);
/* We mandate that no page faults may be outstanding /* We mandate that no page faults may be outstanding
* for the PASID when intel_svm_unbind_mm() is called. * for the PASID when intel_svm_unbind_mm() is called.
* If that is not obeyed, subtle errors will happen. * If that is not obeyed, subtle errors will happen.
...@@ -925,7 +945,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) ...@@ -925,7 +945,7 @@ static irqreturn_t prq_event_thread(int irq, void *d)
} }
if (!svm || svm->pasid != req->pasid) { if (!svm || svm->pasid != req->pasid) {
rcu_read_lock(); rcu_read_lock();
svm = ioasid_find(NULL, req->pasid, NULL); svm = pasid_private_find(req->pasid);
/* It *can't* go away, because the driver is not permitted /* It *can't* go away, because the driver is not permitted
* to unbind the mm while any page faults are outstanding. * to unbind the mm while any page faults are outstanding.
* So we only need RCU to protect the internal idr code. */ * So we only need RCU to protect the internal idr code. */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册