iommu/vt-d: Refactor PCI PRI enabling/disabling callbacks
Commit 0095bf8355
("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>
This commit is contained in:
parent
f90584f4be
commit
3753311c91
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user