Skip to content

Commit 6043257

Browse files
jgunthorpejoergroedel
authored andcommitted
iommu: Introduce the domain op enforce_cache_coherency()
This new mechanism will replace using IOMMU_CAP_CACHE_COHERENCY and IOMMU_CACHE to control the no-snoop blocking behavior of the IOMMU. Currently only Intel and AMD IOMMUs are known to support this feature. They both implement it as an IOPTE bit, that when set, will cause PCIe TLPs to that IOVA with the no-snoop bit set to be treated as though the no-snoop bit was clear. The new API is triggered by calling enforce_cache_coherency() before mapping any IOVA to the domain which globally switches on no-snoop blocking. This allows other implementations that might block no-snoop globally and outside the IOPTE - AMD also documents such a HW capability. Leave AMD out of sync with Intel and have it block no-snoop even for in-kernel users. This can be trivially resolved in a follow up patch. Only VFIO needs to call this API because it does not have detailed control over the device to avoid requesting no-snoop behavior at the device level. Other places using domains with real kernel drivers should simply avoid asking their devices to set the no-snoop bit. Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Acked-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/1-v3-2cf356649677+a32-intel_no_snoop_jgg@nvidia.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 5b1553b commit 6043257

4 files changed

Lines changed: 25 additions & 1 deletion

File tree

drivers/iommu/amd/iommu.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,6 +2266,12 @@ static int amd_iommu_def_domain_type(struct device *dev)
22662266
return 0;
22672267
}
22682268

2269+
static bool amd_iommu_enforce_cache_coherency(struct iommu_domain *domain)
2270+
{
2271+
/* IOMMU_PTE_FC is always set */
2272+
return true;
2273+
}
2274+
22692275
const struct iommu_ops amd_iommu_ops = {
22702276
.capable = amd_iommu_capable,
22712277
.domain_alloc = amd_iommu_domain_alloc,
@@ -2288,6 +2294,7 @@ const struct iommu_ops amd_iommu_ops = {
22882294
.flush_iotlb_all = amd_iommu_flush_iotlb_all,
22892295
.iotlb_sync = amd_iommu_iotlb_sync,
22902296
.free = amd_iommu_domain_free,
2297+
.enforce_cache_coherency = amd_iommu_enforce_cache_coherency,
22912298
}
22922299
};
22932300

drivers/iommu/intel/iommu.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4422,7 +4422,8 @@ static int intel_iommu_map(struct iommu_domain *domain,
44224422
prot |= DMA_PTE_READ;
44234423
if (iommu_prot & IOMMU_WRITE)
44244424
prot |= DMA_PTE_WRITE;
4425-
if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4425+
if (((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping) ||
4426+
dmar_domain->force_snooping)
44264427
prot |= DMA_PTE_SNP;
44274428

44284429
max_addr = iova + size;
@@ -4545,6 +4546,16 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
45454546
return phys;
45464547
}
45474548

4549+
static bool intel_iommu_enforce_cache_coherency(struct iommu_domain *domain)
4550+
{
4551+
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
4552+
4553+
if (!dmar_domain->iommu_snooping)
4554+
return false;
4555+
dmar_domain->force_snooping = true;
4556+
return true;
4557+
}
4558+
45484559
static bool intel_iommu_capable(enum iommu_cap cap)
45494560
{
45504561
if (cap == IOMMU_CAP_CACHE_COHERENCY)
@@ -4900,6 +4911,7 @@ const struct iommu_ops intel_iommu_ops = {
49004911
.iotlb_sync = intel_iommu_tlb_sync,
49014912
.iova_to_phys = intel_iommu_iova_to_phys,
49024913
.free = intel_iommu_domain_free,
4914+
.enforce_cache_coherency = intel_iommu_enforce_cache_coherency,
49034915
}
49044916
};
49054917

include/linux/intel-iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ struct dmar_domain {
540540
u8 has_iotlb_device: 1;
541541
u8 iommu_coherency: 1; /* indicate coherency of iommu access */
542542
u8 iommu_snooping: 1; /* indicate snooping control feature */
543+
u8 force_snooping : 1; /* Create IOPTEs with snoop control */
543544

544545
struct list_head devices; /* all devices' list */
545546
struct iova_domain iovad; /* iova's that belong to this domain */

include/linux/iommu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ struct iommu_ops {
274274
* @iotlb_sync: Flush all queued ranges from the hardware TLBs and empty flush
275275
* queue
276276
* @iova_to_phys: translate iova to physical address
277+
* @enforce_cache_coherency: Prevent any kind of DMA from bypassing IOMMU_CACHE,
278+
* including no-snoop TLPs on PCIe or other platform
279+
* specific mechanisms.
277280
* @enable_nesting: Enable nesting
278281
* @set_pgtable_quirks: Set io page table quirks (IO_PGTABLE_QUIRK_*)
279282
* @free: Release the domain after use.
@@ -302,6 +305,7 @@ struct iommu_domain_ops {
302305
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain,
303306
dma_addr_t iova);
304307

308+
bool (*enforce_cache_coherency)(struct iommu_domain *domain);
305309
int (*enable_nesting)(struct iommu_domain *domain);
306310
int (*set_pgtable_quirks)(struct iommu_domain *domain,
307311
unsigned long quirks);

0 commit comments

Comments
 (0)