Commit 3753311c authored by Lu Baolu's avatar Lu Baolu Committed by Will Deacon
Browse files

iommu/vt-d: Refactor PCI PRI enabling/disabling callbacks



Commit 0095bf83 ("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: default avatarLu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: default avatarKevin 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: default avatarWill Deacon <will@kernel.org>
parent f90584f4
Loading
Loading
Loading
Loading
+52 −5
Original line number Diff line number Diff line
@@ -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;
}
+9 −0
Original line number Diff line number Diff line
@@ -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)
{
+0 −2
Original line number Diff line number Diff line
@@ -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);