]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
iommu/vt-d: Refactor PCI PRI enabling/disabling callbacks
authorLu Baolu <baolu.lu@linux.intel.com>
Tue, 2 Jul 2024 13:08:39 +0000 (21:08 +0800)
committerWill Deacon <will@kernel.org>
Wed, 3 Jul 2024 15:39:26 +0000 (16:39 +0100)
Commit 0095bf83554f8 ("iommu: Improve iopf_queue_remove_device()")
specified the flow for disabling the PRI on a device. Refactor the
PRI callbacks in the intel iommu driver to better manage PRI
enabling and disabling and align it with the device queue interfaces
in the iommu core.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20240701112317.94022-3-baolu.lu@linux.intel.com
Link: https://lore.kernel.org/r/20240702130839.108139-8-baolu.lu@linux.intel.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/intel/iommu.c
drivers/iommu/intel/iommu.h
drivers/iommu/intel/pasid.c

index e84b0fdca107dcb8364f4d5d9d8b7b86784d422d..523407f6f6b20d697ccee948827fd91181696feb 100644 (file)
@@ -4244,6 +4244,37 @@ static int intel_iommu_enable_sva(struct device *dev)
        return 0;
 }
 
+static int context_flip_pri(struct device_domain_info *info, bool enable)
+{
+       struct intel_iommu *iommu = info->iommu;
+       u8 bus = info->bus, devfn = info->devfn;
+       struct context_entry *context;
+
+       spin_lock(&iommu->lock);
+       if (context_copied(iommu, bus, devfn)) {
+               spin_unlock(&iommu->lock);
+               return -EINVAL;
+       }
+
+       context = iommu_context_addr(iommu, bus, devfn, false);
+       if (!context || !context_present(context)) {
+               spin_unlock(&iommu->lock);
+               return -ENODEV;
+       }
+
+       if (enable)
+               context_set_sm_pre(context);
+       else
+               context_clear_sm_pre(context);
+
+       if (!ecap_coherent(iommu->ecap))
+               clflush_cache_range(context, sizeof(*context));
+       intel_context_flush_present(info, context, true);
+       spin_unlock(&iommu->lock);
+
+       return 0;
+}
+
 static int intel_iommu_enable_iopf(struct device *dev)
 {
        struct pci_dev *pdev = dev_is_pci(dev) ? to_pci_dev(dev) : NULL;
@@ -4273,15 +4304,23 @@ static int intel_iommu_enable_iopf(struct device *dev)
        if (ret)
                return ret;
 
+       ret = context_flip_pri(info, true);
+       if (ret)
+               goto err_remove_device;
+
        ret = pci_enable_pri(pdev, PRQ_DEPTH);
-       if (ret) {
-               iopf_queue_remove_device(iommu->iopf_queue, dev);
-               return ret;
-       }
+       if (ret)
+               goto err_clear_pri;
 
        info->pri_enabled = 1;
 
        return 0;
+err_clear_pri:
+       context_flip_pri(info, false);
+err_remove_device:
+       iopf_queue_remove_device(iommu->iopf_queue, dev);
+
+       return ret;
 }
 
 static int intel_iommu_disable_iopf(struct device *dev)
@@ -4292,6 +4331,15 @@ static int intel_iommu_disable_iopf(struct device *dev)
        if (!info->pri_enabled)
                return -EINVAL;
 
+       /* Disable new PRI reception: */
+       context_flip_pri(info, false);
+
+       /*
+        * Remove device from fault queue and acknowledge all outstanding
+        * PRQs to the device:
+        */
+       iopf_queue_remove_device(iommu->iopf_queue, dev);
+
        /*
         * PCIe spec states that by clearing PRI enable bit, the Page
         * Request Interface will not issue new page requests, but has
@@ -4302,7 +4350,6 @@ static int intel_iommu_disable_iopf(struct device *dev)
         */
        pci_disable_pri(to_pci_dev(dev));
        info->pri_enabled = 0;
-       iopf_queue_remove_device(iommu->iopf_queue, dev);
 
        return 0;
 }
index 63eb3306c0259029de8dc8cad61e411af4d149f5..b67c14da12408b22c0907215629244b61fa6e8ea 100644 (file)
@@ -1045,6 +1045,15 @@ static inline void context_set_sm_pre(struct context_entry *context)
        context->lo |= BIT_ULL(4);
 }
 
+/*
+ * Clear the PRE(Page Request Enable) field of a scalable mode context
+ * entry.
+ */
+static inline void context_clear_sm_pre(struct context_entry *context)
+{
+       context->lo &= ~BIT_ULL(4);
+}
+
 /* Returns a number of VTD pages, but aligned to MM page size */
 static inline unsigned long aligned_nrpages(unsigned long host_addr, size_t size)
 {
index 3d23cc6d3214849e792fe156ddf9c5d0bd209103..5792c817cefa56872cf3434368e967a5a62e6dd9 100644 (file)
@@ -752,8 +752,6 @@ static int context_entry_set_pasid_table(struct context_entry *context,
 
        if (info->ats_supported)
                context_set_sm_dte(context);
-       if (info->pri_supported)
-               context_set_sm_pre(context);
        if (info->pasid_supported)
                context_set_pasid(context);