dmaengine: idxd: Add enable/disable device IOPF feature
authorLu Baolu <baolu.lu@linux.intel.com>
Thu, 13 Apr 2023 04:06:29 +0000 (12:06 +0800)
committerJoerg Roedel <jroedel@suse.de>
Thu, 13 Apr 2023 10:05:46 +0000 (12:05 +0200)
The iommu subsystem requires IOMMU_DEV_FEAT_IOPF must be enabled before
and disabled after IOMMU_DEV_FEAT_SVA, if device's I/O page faults rely
on the IOMMU. Add explicit IOMMU_DEV_FEAT_IOPF enabling/disabling in this
driver.

At present, missing IOPF enabling/disabling doesn't cause any real issue,
because the IOMMU driver places the IOPF enabling/disabling in the path
of SVA feature handling. But this may change.

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Fenghua Yu <fenghua.yu@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Link: https://lore.kernel.org/r/20230324120234.313643-2-baolu.lu@linux.intel.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/dma/idxd/init.c

index 640d3048368e98fe67d53ce51bb5f62f417e0993..09ef62aa06350ff49137673795c7a7f21de63864 100644 (file)
@@ -516,6 +516,27 @@ static void idxd_disable_system_pasid(struct idxd_device *idxd)
        idxd->sva = NULL;
 }
 
+static int idxd_enable_sva(struct pci_dev *pdev)
+{
+       int ret;
+
+       ret = iommu_dev_enable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF);
+       if (ret)
+               return ret;
+
+       ret = iommu_dev_enable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA);
+       if (ret)
+               iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF);
+
+       return ret;
+}
+
+static void idxd_disable_sva(struct pci_dev *pdev)
+{
+       iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA);
+       iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF);
+}
+
 static int idxd_probe(struct idxd_device *idxd)
 {
        struct pci_dev *pdev = idxd->pdev;
@@ -530,7 +551,7 @@ static int idxd_probe(struct idxd_device *idxd)
        dev_dbg(dev, "IDXD reset complete\n");
 
        if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) {
-               if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA)) {
+               if (idxd_enable_sva(pdev)) {
                        dev_warn(dev, "Unable to turn on user SVA feature.\n");
                } else {
                        set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
@@ -578,21 +599,19 @@ static int idxd_probe(struct idxd_device *idxd)
        if (device_pasid_enabled(idxd))
                idxd_disable_system_pasid(idxd);
        if (device_user_pasid_enabled(idxd))
-               iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
+               idxd_disable_sva(pdev);
        return rc;
 }
 
 static void idxd_cleanup(struct idxd_device *idxd)
 {
-       struct device *dev = &idxd->pdev->dev;
-
        perfmon_pmu_remove(idxd);
        idxd_cleanup_interrupts(idxd);
        idxd_cleanup_internals(idxd);
        if (device_pasid_enabled(idxd))
                idxd_disable_system_pasid(idxd);
        if (device_user_pasid_enabled(idxd))
-               iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
+               idxd_disable_sva(idxd->pdev);
 }
 
 static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -710,7 +729,7 @@ static void idxd_remove(struct pci_dev *pdev)
        pci_free_irq_vectors(pdev);
        pci_iounmap(pdev, idxd->reg_base);
        if (device_user_pasid_enabled(idxd))
-               iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA);
+               idxd_disable_sva(pdev);
        pci_disable_device(pdev);
        destroy_workqueue(idxd->wq);
        perfmon_pmu_remove(idxd);