]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/vt-d: Check if SVA is supported when attaching the SVA domain
authorJason Gunthorpe <jgg@nvidia.com>
Mon, 10 Mar 2025 02:47:46 +0000 (10:47 +0800)
committerJoerg Roedel <jroedel@suse.de>
Mon, 10 Mar 2025 08:31:03 +0000 (09:31 +0100)
Attach of a SVA domain should fail if SVA is not supported, move the check
for SVA support out of IOMMU_DEV_FEAT_SVA and into attach.

Also check when allocating a SVA domain to match other drivers.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Link: https://lore.kernel.org/r/20250228092631.3425464-3-baolu.lu@linux.intel.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel/iommu.c
drivers/iommu/intel/svm.c

index 0050f9cc37ac835a58440be6aa4a8f9d2c4d7e9c..743212b8d9a6ce191f9b408341efc8b02540c50f 100644 (file)
@@ -3855,41 +3855,6 @@ static struct iommu_group *intel_iommu_device_group(struct device *dev)
        return generic_device_group(dev);
 }
 
-static int intel_iommu_enable_sva(struct device *dev)
-{
-       struct device_domain_info *info = dev_iommu_priv_get(dev);
-       struct intel_iommu *iommu;
-
-       if (!info || dmar_disabled)
-               return -EINVAL;
-
-       iommu = info->iommu;
-       if (!iommu)
-               return -EINVAL;
-
-       if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE))
-               return -ENODEV;
-
-       if (!info->pasid_enabled || !info->ats_enabled)
-               return -EINVAL;
-
-       /*
-        * Devices having device-specific I/O fault handling should not
-        * support PCI/PRI. The IOMMU side has no means to check the
-        * capability of device-specific IOPF.  Therefore, IOMMU can only
-        * default that if the device driver enables SVA on a non-PRI
-        * device, it will handle IOPF in its own way.
-        */
-       if (!info->pri_supported)
-               return 0;
-
-       /* Devices supporting PRI should have it enabled. */
-       if (!info->pri_enabled)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int context_flip_pri(struct device_domain_info *info, bool enable)
 {
        struct intel_iommu *iommu = info->iommu;
@@ -4010,7 +3975,7 @@ intel_iommu_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
                return intel_iommu_enable_iopf(dev);
 
        case IOMMU_DEV_FEAT_SVA:
-               return intel_iommu_enable_sva(dev);
+               return 0;
 
        default:
                return -ENODEV;
index f5569347591f268fd383fc39f786de31be2d29f3..ba93123cb4ebadaa0726d3c93dcb172598dd8b25 100644 (file)
@@ -110,6 +110,41 @@ static const struct mmu_notifier_ops intel_mmuops = {
        .free_notifier = intel_mm_free_notifier,
 };
 
+static int intel_iommu_sva_supported(struct device *dev)
+{
+       struct device_domain_info *info = dev_iommu_priv_get(dev);
+       struct intel_iommu *iommu;
+
+       if (!info || dmar_disabled)
+               return -EINVAL;
+
+       iommu = info->iommu;
+       if (!iommu)
+               return -EINVAL;
+
+       if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE))
+               return -ENODEV;
+
+       if (!info->pasid_enabled || !info->ats_enabled)
+               return -EINVAL;
+
+       /*
+        * Devices having device-specific I/O fault handling should not
+        * support PCI/PRI. The IOMMU side has no means to check the
+        * capability of device-specific IOPF.  Therefore, IOMMU can only
+        * default that if the device driver enables SVA on a non-PRI
+        * device, it will handle IOPF in its own way.
+        */
+       if (!info->pri_supported)
+               return 0;
+
+       /* Devices supporting PRI should have it enabled. */
+       if (!info->pri_enabled)
+               return -EINVAL;
+
+       return 0;
+}
+
 static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
                                   struct device *dev, ioasid_t pasid,
                                   struct iommu_domain *old)
@@ -121,6 +156,10 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
        unsigned long sflags;
        int ret = 0;
 
+       ret = intel_iommu_sva_supported(dev);
+       if (ret)
+               return ret;
+
        dev_pasid = domain_add_dev_pasid(domain, dev, pasid);
        if (IS_ERR(dev_pasid))
                return PTR_ERR(dev_pasid);
@@ -161,6 +200,10 @@ struct iommu_domain *intel_svm_domain_alloc(struct device *dev,
        struct dmar_domain *domain;
        int ret;
 
+       ret = intel_iommu_sva_supported(dev);
+       if (ret)
+               return ERR_PTR(ret);
+
        domain = kzalloc(sizeof(*domain), GFP_KERNEL);
        if (!domain)
                return ERR_PTR(-ENOMEM);