iommu/vt-d: Helper function to query if a pasid has any active users
authorCQ Tang <cq.tang@intel.com>
Wed, 10 May 2017 18:39:03 +0000 (11:39 -0700)
committerJoerg Roedel <jroedel@suse.de>
Wed, 17 May 2017 12:57:56 +0000 (14:57 +0200)
A driver would need to know if there are any active references to a
a PASID before cleaning up its resources. This function helps check
if there are any active users of a PASID before it can perform any
recovery on that device.

To: Joerg Roedel <joro@8bytes.org>
To: linux-kernel@vger.kernel.org
To: David Woodhouse <dwmw2@infradead.org>
Cc: Jean-Phillipe Brucker <jean-philippe.brucker@arm.com>
Cc: iommu@lists.linux-foundation.org
Signed-off-by: CQ Tang <cq.tang@intel.com>
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel-svm.c
include/linux/intel-svm.h

index 23c427602c55ba10a546737edabb1bfb24497304..f167c0d84ebfb7f5937eb798c9cdbd8bd9abe6c6 100644 (file)
@@ -489,6 +489,36 @@ int intel_svm_unbind_mm(struct device *dev, int pasid)
 }
 EXPORT_SYMBOL_GPL(intel_svm_unbind_mm);
 
+int intel_svm_is_pasid_valid(struct device *dev, int pasid)
+{
+       struct intel_iommu *iommu;
+       struct intel_svm *svm;
+       int ret = -EINVAL;
+
+       mutex_lock(&pasid_mutex);
+       iommu = intel_svm_device_to_iommu(dev);
+       if (!iommu || !iommu->pasid_table)
+               goto out;
+
+       svm = idr_find(&iommu->pasid_idr, pasid);
+       if (!svm)
+               goto out;
+
+       /* init_mm is used in this case */
+       if (!svm->mm)
+               ret = 1;
+       else if (atomic_read(&svm->mm->mm_users) > 0)
+               ret = 1;
+       else
+               ret = 0;
+
+ out:
+       mutex_unlock(&pasid_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(intel_svm_is_pasid_valid);
+
 /* Page request queue descriptor */
 struct page_req_dsc {
        u64 srr:1;
index 3c25794042f937b4d3a184a669b98f9acc4b29a5..99bc5b3ae26e1622f07558c52510c5e351e3cad6 100644 (file)
@@ -102,6 +102,21 @@ extern int intel_svm_bind_mm(struct device *dev, int *pasid, int flags,
  */
 extern int intel_svm_unbind_mm(struct device *dev, int pasid);
 
+/**
+ * intel_svm_is_pasid_valid() - check if pasid is valid
+ * @dev:       Device for which PASID was allocated
+ * @pasid:     PASID value to be checked
+ *
+ * This function checks if the specified pasid is still valid. A
+ * valid pasid means the backing mm is still having a valid user.
+ * For kernel callers init_mm is always valid. for other mm, if mm->mm_users
+ * is non-zero, it is valid.
+ *
+ * returns -EINVAL if invalid pasid, 0 if pasid ref count is invalid
+ * 1 if pasid is valid.
+ */
+extern int intel_svm_is_pasid_valid(struct device *dev, int pasid);
+
 #else /* CONFIG_INTEL_IOMMU_SVM */
 
 static inline int intel_svm_bind_mm(struct device *dev, int *pasid,
@@ -114,6 +129,11 @@ static inline int intel_svm_unbind_mm(struct device *dev, int pasid)
 {
        BUG();
 }
+
+static int intel_svm_is_pasid_valid(struct device *dev, int pasid)
+{
+       return -EINVAL;
+}
 #endif /* CONFIG_INTEL_IOMMU_SVM */
 
 #define intel_svm_available(dev) (!intel_svm_bind_mm((dev), NULL, 0, NULL))