Skip to content

Commit

Permalink
iommu/vt-d: Support enforce_cache_coherency only for empty domains
Browse files Browse the repository at this point in the history
[ Upstream commit e645c20 ]

The enforce_cache_coherency callback ensures DMA cache coherency for
devices attached to the domain.

Intel IOMMU supports enforced DMA cache coherency when the Snoop
Control bit in the IOMMU's extended capability register is set.
Supporting it differs between legacy and scalable modes.

In legacy mode, it's supported page-level by setting the SNP field
in second-stage page-table entries. In scalable mode, it's supported
in PASID-table granularity by setting the PGSNP field in PASID-table
entries.

In legacy mode, mappings before attaching to a device have SNP
fields cleared, while mappings after the callback have them set.
This means partial DMAs are cache coherent while others are not.

One possible fix is replaying mappings and flipping SNP bits when
attaching a domain to a device. But this seems to be over-engineered,
given that all real use cases just attach an empty domain to a device.

To meet practical needs while reducing mode differences, only support
enforce_cache_coherency on a domain without mappings if SNP field is
used.

Fixes: fc0051c ("iommu/vt-d: Check domain force_snooping against attached devices")
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20231114011036.70142-1-baolu.lu@linux.intel.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
LuBaolu authored and gregkh committed Jan 10, 2024
1 parent 41294f9 commit 9cdfbfc
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 1 deletion.
5 changes: 4 additions & 1 deletion drivers/iommu/intel/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2204,6 +2204,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
attr |= DMA_FL_PTE_DIRTY;
}

domain->has_mappings = true;

pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | attr;

while (nr_pages > 0) {
Expand Down Expand Up @@ -4309,7 +4311,8 @@ static bool intel_iommu_enforce_cache_coherency(struct iommu_domain *domain)
return true;

spin_lock_irqsave(&dmar_domain->lock, flags);
if (!domain_support_force_snooping(dmar_domain)) {
if (!domain_support_force_snooping(dmar_domain) ||
(!dmar_domain->use_first_level && dmar_domain->has_mappings)) {
spin_unlock_irqrestore(&dmar_domain->lock, flags);
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/iommu/intel/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,9 @@ struct dmar_domain {
* otherwise, goes through the second
* level.
*/
u8 has_mappings:1; /* Has mappings configured through
* iommu_map() interface.
*/

spinlock_t lock; /* Protect device tracking lists */
struct list_head devices; /* all devices' list */
Expand Down

0 comments on commit 9cdfbfc

Please sign in to comment.