Skip to content

Commit dabb83e

Browse files
committed
Merge tag 'dma-mapping-7.0-2026-03-25' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux
Pull dma-mapping fixes from Marek Szyprowski: "A set of fixes for DMA-mapping subsystem, which resolve false- positive warnings from KMSAN and DMA-API debug (Shigeru Yoshida and Leon Romanovsky) as well as a simple build fix (Miguel Ojeda)" * tag 'dma-mapping-7.0-2026-03-25' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux: dma-mapping: add missing `inline` for `dma_free_attrs` mm/hmm: Indicate that HMM requires DMA coherency RDMA/umem: Tell DMA mapping that UMEM requires coherency iommu/dma: add support for DMA_ATTR_REQUIRE_COHERENT attribute dma-direct: prevent SWIOTLB path when DMA_ATTR_REQUIRE_COHERENT is set dma-mapping: Introduce DMA require coherency attribute dma-mapping: Clarify valid conditions for CPU cache line overlap dma-mapping: handle DMA_ATTR_CPU_CACHE_CLEAN in trace output dma-debug: Allow multiple invocations of overlapping entries dma: swiotlb: add KMSAN annotations to swiotlb_bounce()
2 parents 0138af2 + 2cdaff2 commit dabb83e

11 files changed

Lines changed: 107 additions & 37 deletions

File tree

Documentation/core-api/dma-attributes.rst

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,33 @@ For architectures that require cache flushing for DMA coherence
149149
DMA_ATTR_MMIO will not perform any cache flushing. The address
150150
provided must never be mapped cacheable into the CPU.
151151

152-
DMA_ATTR_CPU_CACHE_CLEAN
153-
------------------------
154-
155-
This attribute indicates the CPU will not dirty any cacheline overlapping this
156-
DMA_FROM_DEVICE/DMA_BIDIRECTIONAL buffer while it is mapped. This allows
157-
multiple small buffers to safely share a cacheline without risk of data
158-
corruption, suppressing DMA debug warnings about overlapping mappings.
159-
All mappings sharing a cacheline should have this attribute.
152+
DMA_ATTR_DEBUGGING_IGNORE_CACHELINES
153+
------------------------------------
154+
155+
This attribute indicates that CPU cache lines may overlap for buffers mapped
156+
with DMA_FROM_DEVICE or DMA_BIDIRECTIONAL.
157+
158+
Such overlap may occur when callers map multiple small buffers that reside
159+
within the same cache line. In this case, callers must guarantee that the CPU
160+
will not dirty these cache lines after the mappings are established. When this
161+
condition is met, multiple buffers can safely share a cache line without risking
162+
data corruption.
163+
164+
All mappings that share a cache line must set this attribute to suppress DMA
165+
debug warnings about overlapping mappings.
166+
167+
DMA_ATTR_REQUIRE_COHERENT
168+
-------------------------
169+
170+
DMA mapping requests with the DMA_ATTR_REQUIRE_COHERENT fail on any
171+
system where SWIOTLB or cache management is required. This should only
172+
be used to support uAPI designs that require continuous HW DMA
173+
coherence with userspace processes, for example RDMA and DRM. At a
174+
minimum the memory being mapped must be userspace memory from
175+
pin_user_pages() or similar.
176+
177+
Drivers should consider using dma_mmap_pages() instead of this
178+
interface when building their uAPIs, when possible.
179+
180+
It must never be used in an in-kernel driver that only works with
181+
kernel memory.

drivers/infiniband/core/umem.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
5555

5656
if (dirty)
5757
ib_dma_unmap_sgtable_attrs(dev, &umem->sgt_append.sgt,
58-
DMA_BIDIRECTIONAL, 0);
58+
DMA_BIDIRECTIONAL,
59+
DMA_ATTR_REQUIRE_COHERENT);
5960

6061
for_each_sgtable_sg(&umem->sgt_append.sgt, sg, i) {
6162
unpin_user_page_range_dirty_lock(sg_page(sg),
@@ -169,7 +170,7 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
169170
unsigned long lock_limit;
170171
unsigned long new_pinned;
171172
unsigned long cur_base;
172-
unsigned long dma_attr = 0;
173+
unsigned long dma_attr = DMA_ATTR_REQUIRE_COHERENT;
173174
struct mm_struct *mm;
174175
unsigned long npages;
175176
int pinned, ret;

drivers/iommu/dma-iommu.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,7 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
12111211
*/
12121212
if (dev_use_swiotlb(dev, size, dir) &&
12131213
iova_unaligned(iovad, phys, size)) {
1214-
if (attrs & DMA_ATTR_MMIO)
1214+
if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
12151215
return DMA_MAPPING_ERROR;
12161216

12171217
phys = iommu_dma_map_swiotlb(dev, phys, size, dir, attrs);
@@ -1223,7 +1223,8 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
12231223
arch_sync_dma_for_device(phys, size, dir);
12241224

12251225
iova = __iommu_dma_map(dev, phys, size, prot, dma_mask);
1226-
if (iova == DMA_MAPPING_ERROR && !(attrs & DMA_ATTR_MMIO))
1226+
if (iova == DMA_MAPPING_ERROR &&
1227+
!(attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)))
12271228
swiotlb_tbl_unmap_single(dev, phys, size, dir, attrs);
12281229
return iova;
12291230
}
@@ -1233,7 +1234,7 @@ void iommu_dma_unmap_phys(struct device *dev, dma_addr_t dma_handle,
12331234
{
12341235
phys_addr_t phys;
12351236

1236-
if (attrs & DMA_ATTR_MMIO) {
1237+
if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)) {
12371238
__iommu_dma_unmap(dev, dma_handle, size);
12381239
return;
12391240
}
@@ -1945,9 +1946,21 @@ int dma_iova_link(struct device *dev, struct dma_iova_state *state,
19451946
if (WARN_ON_ONCE(iova_start_pad && offset > 0))
19461947
return -EIO;
19471948

1949+
/*
1950+
* DMA_IOVA_USE_SWIOTLB is set on state after some entry
1951+
* took SWIOTLB path, which we were supposed to prevent
1952+
* for DMA_ATTR_REQUIRE_COHERENT attribute.
1953+
*/
1954+
if (WARN_ON_ONCE((state->__size & DMA_IOVA_USE_SWIOTLB) &&
1955+
(attrs & DMA_ATTR_REQUIRE_COHERENT)))
1956+
return -EOPNOTSUPP;
1957+
1958+
if (!dev_is_dma_coherent(dev) && (attrs & DMA_ATTR_REQUIRE_COHERENT))
1959+
return -EOPNOTSUPP;
1960+
19481961
if (dev_use_swiotlb(dev, size, dir) &&
19491962
iova_unaligned(iovad, phys, size)) {
1950-
if (attrs & DMA_ATTR_MMIO)
1963+
if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
19511964
return -EPERM;
19521965

19531966
return iommu_dma_iova_link_swiotlb(dev, state, phys, offset,

drivers/virtio/virtio_ring.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,10 +2912,10 @@ EXPORT_SYMBOL_GPL(virtqueue_add_inbuf);
29122912
* @data: the token identifying the buffer.
29132913
* @gfp: how to do memory allocations (if necessary).
29142914
*
2915-
* Same as virtqueue_add_inbuf but passes DMA_ATTR_CPU_CACHE_CLEAN to indicate
2916-
* that the CPU will not dirty any cacheline overlapping this buffer while it
2917-
* is available, and to suppress overlapping cacheline warnings in DMA debug
2918-
* builds.
2915+
* Same as virtqueue_add_inbuf but passes DMA_ATTR_DEBUGGING_IGNORE_CACHELINES
2916+
* to indicate that the CPU will not dirty any cacheline overlapping this buffer
2917+
* while it is available, and to suppress overlapping cacheline warnings in DMA
2918+
* debug builds.
29192919
*
29202920
* Caller must ensure we don't call this with other virtqueue operations
29212921
* at the same time (except where noted).
@@ -2928,7 +2928,7 @@ int virtqueue_add_inbuf_cache_clean(struct virtqueue *vq,
29282928
gfp_t gfp)
29292929
{
29302930
return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, false, gfp,
2931-
DMA_ATTR_CPU_CACHE_CLEAN);
2931+
DMA_ATTR_DEBUGGING_IGNORE_CACHELINES);
29322932
}
29332933
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_cache_clean);
29342934

include/linux/dma-mapping.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,18 @@
8080
#define DMA_ATTR_MMIO (1UL << 10)
8181

8282
/*
83-
* DMA_ATTR_CPU_CACHE_CLEAN: Indicates the CPU will not dirty any cacheline
84-
* overlapping this buffer while it is mapped for DMA. All mappings sharing
85-
* a cacheline must have this attribute for this to be considered safe.
83+
* DMA_ATTR_DEBUGGING_IGNORE_CACHELINES: Indicates the CPU cache line can be
84+
* overlapped. All mappings sharing a cacheline must have this attribute for
85+
* this to be considered safe.
8686
*/
87-
#define DMA_ATTR_CPU_CACHE_CLEAN (1UL << 11)
87+
#define DMA_ATTR_DEBUGGING_IGNORE_CACHELINES (1UL << 11)
88+
89+
/*
90+
* DMA_ATTR_REQUIRE_COHERENT: Indicates that DMA coherency is required.
91+
* All mappings that carry this attribute can't work with SWIOTLB and cache
92+
* flushing.
93+
*/
94+
#define DMA_ATTR_REQUIRE_COHERENT (1UL << 12)
8895

8996
/*
9097
* A dma_addr_t can hold any valid DMA or bus address for the platform. It can
@@ -248,8 +255,8 @@ static inline void *dma_alloc_attrs(struct device *dev, size_t size,
248255
{
249256
return NULL;
250257
}
251-
static void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
252-
dma_addr_t dma_handle, unsigned long attrs)
258+
static inline void dma_free_attrs(struct device *dev, size_t size,
259+
void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
253260
{
254261
}
255262
static inline void *dmam_alloc_attrs(struct device *dev, size_t size,

include/trace/events/dma.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ TRACE_DEFINE_ENUM(DMA_NONE);
3232
{ DMA_ATTR_ALLOC_SINGLE_PAGES, "ALLOC_SINGLE_PAGES" }, \
3333
{ DMA_ATTR_NO_WARN, "NO_WARN" }, \
3434
{ DMA_ATTR_PRIVILEGED, "PRIVILEGED" }, \
35-
{ DMA_ATTR_MMIO, "MMIO" })
35+
{ DMA_ATTR_MMIO, "MMIO" }, \
36+
{ DMA_ATTR_DEBUGGING_IGNORE_CACHELINES, "CACHELINES_OVERLAP" }, \
37+
{ DMA_ATTR_REQUIRE_COHERENT, "REQUIRE_COHERENT" })
3638

3739
DECLARE_EVENT_CLASS(dma_map,
3840
TP_PROTO(struct device *dev, phys_addr_t phys_addr, dma_addr_t dma_addr,

kernel/dma/debug.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ static int active_cacheline_set_overlap(phys_addr_t cln, int overlap)
453453
return overlap;
454454
}
455455

456-
static void active_cacheline_inc_overlap(phys_addr_t cln)
456+
static void active_cacheline_inc_overlap(phys_addr_t cln, bool is_cache_clean)
457457
{
458458
int overlap = active_cacheline_read_overlap(cln);
459459

@@ -462,7 +462,7 @@ static void active_cacheline_inc_overlap(phys_addr_t cln)
462462
/* If we overflowed the overlap counter then we're potentially
463463
* leaking dma-mappings.
464464
*/
465-
WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
465+
WARN_ONCE(!is_cache_clean && overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
466466
pr_fmt("exceeded %d overlapping mappings of cacheline %pa\n"),
467467
ACTIVE_CACHELINE_MAX_OVERLAP, &cln);
468468
}
@@ -495,7 +495,7 @@ static int active_cacheline_insert(struct dma_debug_entry *entry,
495495
if (rc == -EEXIST) {
496496
struct dma_debug_entry *existing;
497497

498-
active_cacheline_inc_overlap(cln);
498+
active_cacheline_inc_overlap(cln, entry->is_cache_clean);
499499
existing = radix_tree_lookup(&dma_active_cacheline, cln);
500500
/* A lookup failure here after we got -EEXIST is unexpected. */
501501
WARN_ON(!existing);
@@ -601,7 +601,8 @@ static void add_dma_entry(struct dma_debug_entry *entry, unsigned long attrs)
601601
unsigned long flags;
602602
int rc;
603603

604-
entry->is_cache_clean = !!(attrs & DMA_ATTR_CPU_CACHE_CLEAN);
604+
entry->is_cache_clean = attrs & (DMA_ATTR_DEBUGGING_IGNORE_CACHELINES |
605+
DMA_ATTR_REQUIRE_COHERENT);
605606

606607
bucket = get_hash_bucket(entry, &flags);
607608
hash_bucket_add(bucket, entry);

kernel/dma/direct.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
8484
dma_addr_t dma_addr;
8585

8686
if (is_swiotlb_force_bounce(dev)) {
87-
if (attrs & DMA_ATTR_MMIO)
87+
if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
8888
return DMA_MAPPING_ERROR;
8989

9090
return swiotlb_map(dev, phys, size, dir, attrs);
@@ -98,7 +98,8 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
9898
dma_addr = phys_to_dma(dev, phys);
9999
if (unlikely(!dma_capable(dev, dma_addr, size, true)) ||
100100
dma_kmalloc_needs_bounce(dev, size, dir)) {
101-
if (is_swiotlb_active(dev))
101+
if (is_swiotlb_active(dev) &&
102+
!(attrs & DMA_ATTR_REQUIRE_COHERENT))
102103
return swiotlb_map(dev, phys, size, dir, attrs);
103104

104105
goto err_overflow;
@@ -123,7 +124,7 @@ static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
123124
{
124125
phys_addr_t phys;
125126

126-
if (attrs & DMA_ATTR_MMIO)
127+
if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
127128
/* nothing to do: uncached and no swiotlb */
128129
return;
129130

kernel/dma/mapping.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
164164
if (WARN_ON_ONCE(!dev->dma_mask))
165165
return DMA_MAPPING_ERROR;
166166

167+
if (!dev_is_dma_coherent(dev) && (attrs & DMA_ATTR_REQUIRE_COHERENT))
168+
return DMA_MAPPING_ERROR;
169+
167170
if (dma_map_direct(dev, ops) ||
168171
(!is_mmio && arch_dma_map_phys_direct(dev, phys + size)))
169172
addr = dma_direct_map_phys(dev, phys, size, dir, attrs);
@@ -235,6 +238,9 @@ static int __dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
235238

236239
BUG_ON(!valid_dma_direction(dir));
237240

241+
if (!dev_is_dma_coherent(dev) && (attrs & DMA_ATTR_REQUIRE_COHERENT))
242+
return -EOPNOTSUPP;
243+
238244
if (WARN_ON_ONCE(!dev->dma_mask))
239245
return 0;
240246

kernel/dma/swiotlb.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/gfp.h>
3131
#include <linux/highmem.h>
3232
#include <linux/io.h>
33+
#include <linux/kmsan-checks.h>
3334
#include <linux/iommu-helper.h>
3435
#include <linux/init.h>
3536
#include <linux/memblock.h>
@@ -901,10 +902,19 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
901902

902903
local_irq_save(flags);
903904
page = pfn_to_page(pfn);
904-
if (dir == DMA_TO_DEVICE)
905+
if (dir == DMA_TO_DEVICE) {
906+
/*
907+
* Ideally, kmsan_check_highmem_page()
908+
* could be used here to detect infoleaks,
909+
* but callers may map uninitialized buffers
910+
* that will be written by the device,
911+
* causing false positives.
912+
*/
905913
memcpy_from_page(vaddr, page, offset, sz);
906-
else
914+
} else {
915+
kmsan_unpoison_memory(vaddr, sz);
907916
memcpy_to_page(page, offset, vaddr, sz);
917+
}
908918
local_irq_restore(flags);
909919

910920
size -= sz;
@@ -913,8 +923,15 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
913923
offset = 0;
914924
}
915925
} else if (dir == DMA_TO_DEVICE) {
926+
/*
927+
* Ideally, kmsan_check_memory() could be used here to detect
928+
* infoleaks (uninitialized data being sent to device), but
929+
* callers may map uninitialized buffers that will be written
930+
* by the device, causing false positives.
931+
*/
916932
memcpy(vaddr, phys_to_virt(orig_addr), size);
917933
} else {
934+
kmsan_unpoison_memory(vaddr, size);
918935
memcpy(phys_to_virt(orig_addr), vaddr, size);
919936
}
920937
}

0 commit comments

Comments
 (0)