iommu/vt-d: Add pasid private data helpers
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: Lu 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.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
521f546b4e
commit
100b8a14a3
|
@ -17,6 +17,7 @@
|
|||
#include <linux/dmar.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/xarray.h>
|
||||
#include <linux/ioasid.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/fpu/api.h>
|
||||
|
@ -28,6 +29,23 @@ static void intel_svm_drain_prq(struct device *dev, u32 pasid);
|
|||
|
||||
#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)
|
||||
{
|
||||
struct page *pages;
|
||||
|
@ -224,7 +242,7 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
|
|||
if (pasid == INVALID_IOASID || pasid >= PASID_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
svm = ioasid_find(NULL, pasid, NULL);
|
||||
svm = pasid_private_find(pasid);
|
||||
if (IS_ERR(svm))
|
||||
return PTR_ERR(svm);
|
||||
|
||||
|
@ -334,7 +352,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
|
|||
svm->gpasid = data->gpasid;
|
||||
svm->flags |= SVM_FLAG_GUEST_PASID;
|
||||
}
|
||||
ioasid_set_data(data->hpasid, svm);
|
||||
pasid_private_add(data->hpasid, svm);
|
||||
INIT_LIST_HEAD_RCU(&svm->devs);
|
||||
mmput(svm->mm);
|
||||
}
|
||||
|
@ -388,7 +406,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
|
|||
list_add_rcu(&sdev->list, &svm->devs);
|
||||
out:
|
||||
if (!IS_ERR_OR_NULL(svm) && list_empty(&svm->devs)) {
|
||||
ioasid_set_data(data->hpasid, NULL);
|
||||
pasid_private_remove(data->hpasid);
|
||||
kfree(svm);
|
||||
}
|
||||
|
||||
|
@ -431,7 +449,7 @@ int intel_svm_unbind_gpasid(struct device *dev, u32 pasid)
|
|||
* the unbind, IOMMU driver will get notified
|
||||
* and perform cleanup.
|
||||
*/
|
||||
ioasid_set_data(pasid, NULL);
|
||||
pasid_private_remove(pasid);
|
||||
kfree(svm);
|
||||
}
|
||||
}
|
||||
|
@ -547,8 +565,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||
svm = kzalloc(sizeof(*svm), GFP_KERNEL);
|
||||
if (!svm) {
|
||||
ret = -ENOMEM;
|
||||
kfree(sdev);
|
||||
goto out;
|
||||
goto sdev_err;
|
||||
}
|
||||
|
||||
if (pasid_max > intel_pasid_max_id)
|
||||
|
@ -556,13 +573,16 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||
|
||||
/* Do not use PASID 0, reserved for RID to PASID */
|
||||
svm->pasid = ioasid_alloc(NULL, PASID_MIN,
|
||||
pasid_max - 1, svm);
|
||||
pasid_max - 1, NULL);
|
||||
if (svm->pasid == INVALID_IOASID) {
|
||||
kfree(svm);
|
||||
kfree(sdev);
|
||||
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->mm = mm;
|
||||
svm->flags = flags;
|
||||
|
@ -571,12 +591,8 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||
ret = -ENOMEM;
|
||||
if (mm) {
|
||||
ret = mmu_notifier_register(&svm->notifier, mm);
|
||||
if (ret) {
|
||||
ioasid_put(svm->pasid);
|
||||
kfree(svm);
|
||||
kfree(sdev);
|
||||
goto out;
|
||||
}
|
||||
if (ret)
|
||||
goto priv_err;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&iommu->lock, iflags);
|
||||
|
@ -590,8 +606,13 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||
if (ret) {
|
||||
if (mm)
|
||||
mmu_notifier_unregister(&svm->notifier, mm);
|
||||
priv_err:
|
||||
pasid_private_remove(svm->pasid);
|
||||
pasid_err:
|
||||
ioasid_put(svm->pasid);
|
||||
svm_err:
|
||||
kfree(svm);
|
||||
sdev_err:
|
||||
kfree(sdev);
|
||||
goto out;
|
||||
}
|
||||
|
@ -614,10 +635,8 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||
(cpu_feature_enabled(X86_FEATURE_LA57) ?
|
||||
PASID_FLAG_FL5LP : 0));
|
||||
spin_unlock_irqrestore(&iommu->lock, iflags);
|
||||
if (ret) {
|
||||
kfree(sdev);
|
||||
goto out;
|
||||
}
|
||||
if (ret)
|
||||
goto sdev_err;
|
||||
}
|
||||
list_add_rcu(&sdev->list, &svm->devs);
|
||||
success:
|
||||
|
@ -670,6 +689,7 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
|
|||
load_pasid(svm->mm, PASID_DISABLED);
|
||||
}
|
||||
list_del(&svm->list);
|
||||
pasid_private_remove(svm->pasid);
|
||||
/* We mandate that no page faults may be outstanding
|
||||
* for the PASID when intel_svm_unbind_mm() is called.
|
||||
* If that is not obeyed, subtle errors will happen.
|
||||
|
@ -924,7 +944,7 @@ static irqreturn_t prq_event_thread(int irq, void *d)
|
|||
}
|
||||
if (!svm || svm->pasid != req->pasid) {
|
||||
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
|
||||
* to unbind the mm while any page faults are outstanding.
|
||||
* So we only need RCU to protect the internal idr code. */
|
||||
|
|
Loading…
Reference in New Issue