Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm/hmm: Indicate that HMM requires DMA coherency

HMM is fundamentally about allowing a sophisticated device to perform DMA
directly to a process’s memory while the CPU accesses that same memory at
the same time. It is similar to SVA but does not rely on IOMMU support.
Because the entire model depends on concurrent access to shared memory, it
fails as a uAPI if SWIOTLB substitutes the memory or if the CPU caches are
not coherent with DMA.

Until now, there has been no reliable way to report this, and various
approximations have been used:

int hmm_dma_map_alloc(struct device *dev, struct hmm_dma_map *map,
size_t nr_entries, size_t dma_entry_size)
{
<...>
/*
* The HMM API violates our normal DMA buffer ownership rules and can't
* transfer buffer ownership. The dma_addressing_limited() check is a
* best approximation to ensure no swiotlb buffering happens.
*/
dma_need_sync = !dev->dma_skip_sync;
if (dma_need_sync || dma_addressing_limited(dev))
return -EOPNOTSUPP;

So let's mark mapped buffers with DMA_ATTR_REQUIRE_COHERENT attribute
to prevent silent data corruption if someone tries to use hmm in a system
with swiotlb or incoherent DMA

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/r/20260316-dma-debug-overlap-v3-8-1dde90a7f08b@nvidia.com

authored by

Leon Romanovsky and committed by
Marek Szyprowski
f5ebf241 d9d43a3f

+2 -2
+2 -2
mm/hmm.c
··· 778 778 struct page *page = hmm_pfn_to_page(pfns[idx]); 779 779 phys_addr_t paddr = hmm_pfn_to_phys(pfns[idx]); 780 780 size_t offset = idx * map->dma_entry_size; 781 - unsigned long attrs = 0; 781 + unsigned long attrs = DMA_ATTR_REQUIRE_COHERENT; 782 782 dma_addr_t dma_addr; 783 783 int ret; 784 784 ··· 871 871 struct dma_iova_state *state = &map->state; 872 872 dma_addr_t *dma_addrs = map->dma_list; 873 873 unsigned long *pfns = map->pfn_list; 874 - unsigned long attrs = 0; 874 + unsigned long attrs = DMA_ATTR_REQUIRE_COHERENT; 875 875 876 876 if ((pfns[idx] & valid_dma) != valid_dma) 877 877 return false;