Commit 06792d06 authored by Lu Baolu's avatar Lu Baolu Committed by Joerg Roedel

iommu/vt-d: Cleanup use of iommu_flush_iotlb_psi()

Use cache_tag_flush_range() in switch_to_super_page() to invalidate the
necessary caches when switching mappings from normal to super pages. The
iommu_flush_iotlb_psi() call in intel_iommu_memory_notifier() is
unnecessary since there should be no cache invalidation for the identity
domain.

Clean up iommu_flush_iotlb_psi() after the last call site is removed.
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/20240416080656.60968-8-baolu.lu@linux.intel.comSigned-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 129dab6e
......@@ -1390,157 +1390,6 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
quirk_extra_dev_tlb_flush(info, addr, mask, IOMMU_NO_PASID, qdep);
}
static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
u64 addr, unsigned mask)
{
struct dev_pasid_info *dev_pasid;
struct device_domain_info *info;
unsigned long flags;
if (!domain->has_iotlb_device)
return;
spin_lock_irqsave(&domain->lock, flags);
list_for_each_entry(info, &domain->devices, link)
__iommu_flush_dev_iotlb(info, addr, mask);
list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
info = dev_iommu_priv_get(dev_pasid->dev);
if (!info->ats_enabled)
continue;
qi_flush_dev_iotlb_pasid(info->iommu,
PCI_DEVID(info->bus, info->devfn),
info->pfsid, dev_pasid->pasid,
info->ats_qdep, addr,
mask);
}
spin_unlock_irqrestore(&domain->lock, flags);
}
static void domain_flush_pasid_iotlb(struct intel_iommu *iommu,
struct dmar_domain *domain, u64 addr,
unsigned long npages, bool ih)
{
u16 did = domain_id_iommu(domain, iommu);
struct dev_pasid_info *dev_pasid;
unsigned long flags;
spin_lock_irqsave(&domain->lock, flags);
list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain)
qi_flush_piotlb(iommu, did, dev_pasid->pasid, addr, npages, ih);
if (!list_empty(&domain->devices))
qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih);
spin_unlock_irqrestore(&domain->lock, flags);
}
static void __iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
unsigned long pfn, unsigned int pages,
int ih)
{
unsigned int aligned_pages = __roundup_pow_of_two(pages);
unsigned long bitmask = aligned_pages - 1;
unsigned int mask = ilog2(aligned_pages);
u64 addr = (u64)pfn << VTD_PAGE_SHIFT;
/*
* PSI masks the low order bits of the base address. If the
* address isn't aligned to the mask, then compute a mask value
* needed to ensure the target range is flushed.
*/
if (unlikely(bitmask & pfn)) {
unsigned long end_pfn = pfn + pages - 1, shared_bits;
/*
* Since end_pfn <= pfn + bitmask, the only way bits
* higher than bitmask can differ in pfn and end_pfn is
* by carrying. This means after masking out bitmask,
* high bits starting with the first set bit in
* shared_bits are all equal in both pfn and end_pfn.
*/
shared_bits = ~(pfn ^ end_pfn) & ~bitmask;
mask = shared_bits ? __ffs(shared_bits) : BITS_PER_LONG;
}
/*
* Fallback to domain selective flush if no PSI support or
* the size is too big.
*/
if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
iommu->flush.flush_iotlb(iommu, did, 0, 0,
DMA_TLB_DSI_FLUSH);
else
iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
DMA_TLB_PSI_FLUSH);
}
static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
struct dmar_domain *domain,
unsigned long pfn, unsigned int pages,
int ih, int map)
{
unsigned int aligned_pages = __roundup_pow_of_two(pages);
unsigned int mask = ilog2(aligned_pages);
uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
u16 did = domain_id_iommu(domain, iommu);
if (WARN_ON(!pages))
return;
if (ih)
ih = 1 << 6;
if (domain->use_first_level)
domain_flush_pasid_iotlb(iommu, domain, addr, pages, ih);
else
__iommu_flush_iotlb_psi(iommu, did, pfn, pages, ih);
if (!map)
iommu_flush_dev_iotlb(domain, addr, mask);
}
/*
* Flush the relevant caches in nested translation if the domain
* also serves as a parent
*/
static void parent_domain_flush(struct dmar_domain *domain,
unsigned long pfn,
unsigned long pages, int ih)
{
struct dmar_domain *s1_domain;
spin_lock(&domain->s1_lock);
list_for_each_entry(s1_domain, &domain->s1_domains, s2_link) {
struct device_domain_info *device_info;
struct iommu_domain_info *info;
unsigned long flags;
unsigned long i;
xa_for_each(&s1_domain->iommu_array, i, info)
__iommu_flush_iotlb_psi(info->iommu, info->did,
pfn, pages, ih);
if (!s1_domain->has_iotlb_device)
continue;
spin_lock_irqsave(&s1_domain->lock, flags);
list_for_each_entry(device_info, &s1_domain->devices, link)
/*
* Address translation cache in device side caches the
* result of nested translation. There is no easy way
* to identify the exact set of nested translations
* affected by a change in S2. So just flush the entire
* device cache.
*/
__iommu_flush_dev_iotlb(device_info, 0,
MAX_AGAW_PFN_WIDTH);
spin_unlock_irqrestore(&s1_domain->lock, flags);
}
spin_unlock(&domain->s1_lock);
}
static void intel_flush_iotlb_all(struct iommu_domain *domain)
{
cache_tag_flush_all(to_dmar_domain(domain));
......@@ -1991,9 +1840,7 @@ static void switch_to_super_page(struct dmar_domain *domain,
unsigned long end_pfn, int level)
{
unsigned long lvl_pages = lvl_to_nr_pages(level);
struct iommu_domain_info *info;
struct dma_pte *pte = NULL;
unsigned long i;
while (start_pfn <= end_pfn) {
if (!pte)
......@@ -2005,13 +1852,8 @@ static void switch_to_super_page(struct dmar_domain *domain,
start_pfn + lvl_pages - 1,
level + 1);
xa_for_each(&domain->iommu_array, i, info)
iommu_flush_iotlb_psi(info->iommu, domain,
start_pfn, lvl_pages,
0, 0);
if (domain->nested_parent)
parent_domain_flush(domain, start_pfn,
lvl_pages, 0);
cache_tag_flush_range(domain, start_pfn << VTD_PAGE_SHIFT,
end_pfn << VTD_PAGE_SHIFT, 0);
}
pte++;
......@@ -3381,18 +3223,9 @@ static int intel_iommu_memory_notifier(struct notifier_block *nb,
case MEM_OFFLINE:
case MEM_CANCEL_ONLINE:
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
LIST_HEAD(freelist);
domain_unmap(si_domain, start_vpfn, last_vpfn, &freelist);
rcu_read_lock();
for_each_active_iommu(iommu, drhd)
iommu_flush_iotlb_psi(iommu, si_domain,
start_vpfn, mhp->nr_pages,
list_empty(&freelist), 0);
rcu_read_unlock();
put_pages_list(&freelist);
}
break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment