iommu/vt-d: Fix incorrect domain ID in context flush helper
The helper intel_context_flush_present() is designed to flush all related
caches when a context entry with the present bit set is modified. It
currently retrieves the domain ID from the context entry and uses it to
flush the IOTLB and context caches. This is incorrect when the context
entry transitions from present to non-present, as the domain ID field is
cleared before calling the helper.
Fix it by passing the domain ID programmed in the context entry before the
change to intel_context_flush_present(). This ensures that the correct
domain ID is used for cache invalidation.
Fixes: f90584f4be
("iommu/vt-d: Add helper to flush caches for context change")
Reported-by: Alex Williamson <alex.williamson@redhat.com>
Closes: https://lore.kernel.org/linux-iommu/20240814162726.5efe1a6e.alex.williamson@redhat.com/
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Alex Williamson <alex.williamson@redhat.com>
Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Reviewed-by: Jacob Pan <jacob.pan@linux.microsoft.com>
Link: https://lore.kernel.org/r/20240815124857.70038-1-baolu.lu@linux.intel.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
b58b133e68
commit
7af6c72041
@ -1944,6 +1944,7 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8
|
||||
{
|
||||
struct intel_iommu *iommu = info->iommu;
|
||||
struct context_entry *context;
|
||||
u16 did;
|
||||
|
||||
spin_lock(&iommu->lock);
|
||||
context = iommu_context_addr(iommu, bus, devfn, 0);
|
||||
@ -1952,10 +1953,11 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8
|
||||
return;
|
||||
}
|
||||
|
||||
did = context_domain_id(context);
|
||||
context_clear_entry(context);
|
||||
__iommu_flush_cache(iommu, context, sizeof(*context));
|
||||
spin_unlock(&iommu->lock);
|
||||
intel_context_flush_present(info, context, true);
|
||||
intel_context_flush_present(info, context, did, true);
|
||||
}
|
||||
|
||||
static int domain_setup_first_level(struct intel_iommu *iommu,
|
||||
@ -4249,6 +4251,7 @@ 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;
|
||||
u16 did;
|
||||
|
||||
spin_lock(&iommu->lock);
|
||||
if (context_copied(iommu, bus, devfn)) {
|
||||
@ -4261,6 +4264,7 @@ static int context_flip_pri(struct device_domain_info *info, bool enable)
|
||||
spin_unlock(&iommu->lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
did = context_domain_id(context);
|
||||
|
||||
if (enable)
|
||||
context_set_sm_pre(context);
|
||||
@ -4269,7 +4273,7 @@ static int context_flip_pri(struct device_domain_info *info, bool enable)
|
||||
|
||||
if (!ecap_coherent(iommu->ecap))
|
||||
clflush_cache_range(context, sizeof(*context));
|
||||
intel_context_flush_present(info, context, true);
|
||||
intel_context_flush_present(info, context, did, true);
|
||||
spin_unlock(&iommu->lock);
|
||||
|
||||
return 0;
|
||||
|
@ -1154,7 +1154,7 @@ void cache_tag_flush_range_np(struct dmar_domain *domain, unsigned long start,
|
||||
|
||||
void intel_context_flush_present(struct device_domain_info *info,
|
||||
struct context_entry *context,
|
||||
bool affect_domains);
|
||||
u16 did, bool affect_domains);
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU_SVM
|
||||
void intel_svm_check(struct intel_iommu *iommu);
|
||||
|
@ -683,6 +683,7 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn)
|
||||
struct device_domain_info *info = dev_iommu_priv_get(dev);
|
||||
struct intel_iommu *iommu = info->iommu;
|
||||
struct context_entry *context;
|
||||
u16 did;
|
||||
|
||||
spin_lock(&iommu->lock);
|
||||
context = iommu_context_addr(iommu, bus, devfn, false);
|
||||
@ -691,10 +692,11 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn)
|
||||
return;
|
||||
}
|
||||
|
||||
did = context_domain_id(context);
|
||||
context_clear_entry(context);
|
||||
__iommu_flush_cache(iommu, context, sizeof(*context));
|
||||
spin_unlock(&iommu->lock);
|
||||
intel_context_flush_present(info, context, false);
|
||||
intel_context_flush_present(info, context, did, false);
|
||||
}
|
||||
|
||||
static int pci_pasid_table_teardown(struct pci_dev *pdev, u16 alias, void *data)
|
||||
@ -885,10 +887,9 @@ static void __context_flush_dev_iotlb(struct device_domain_info *info)
|
||||
*/
|
||||
void intel_context_flush_present(struct device_domain_info *info,
|
||||
struct context_entry *context,
|
||||
bool flush_domains)
|
||||
u16 did, bool flush_domains)
|
||||
{
|
||||
struct intel_iommu *iommu = info->iommu;
|
||||
u16 did = context_domain_id(context);
|
||||
struct pasid_entry *pte;
|
||||
int i;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user