Merge tag 'dma-mapping-7.4-2026-10-21' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux

Pull dma-mapping updates from Marek Szyprowski:

 - several SWIOTLB initialization cleanups (Aneesh Kumar K.V, Francesco
   Valla)

 - exact page allocation for DMA pages (Qingfang Deng)

 - tools/dma build fixes (Sasha Levin)

 - minor fixes for various corner cases (Marek Szyprowski, Leon
   Romanovsky) and code cleanup (John Garry)

* tag 'dma-mapping-7.4-2026-10-21' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux:
  dma-debug: Skip cacheline tracking for MMIO mappings
  tools/dma: fix building from the top level with O=
  tools/dma: fix building with O=
  dma: swiotlb: Track whether the pool size was explicitly set
  dma: swiotlb: Consolidate slab rounding
  dma: swiotlb: Rename swiotlb_size_or_default()
  dma: swiotlb: use KiB in restricted pool allocation log
  dma-direct: Restore arch_dma_alloc() for the DMA_ATTR_NO_KERNEL_MAPPING case
  MAINTAINERS: Add files to the DMA MAPPING HELPERS entry
  dma-mapping: use exact allocation for DMA pages
  dma-mapping: rename dma_opt_mapping_size()
This commit is contained in:
Linus Torvalds committed 2026-10-23 14:31:51 -10:00
commit 906b6e1d8c
22 files changed
+106 -77

No files matched your search

+1 -1
View File
@@ -154,7 +154,7 @@ others should not be larger than the returned value.
::
size_t
dma_opt_mapping_size(struct device *dev);
dma_max_opt_mapping_size(struct device *dev);
Returns the maximum optimal size of a mapping for the device.
+1
View File
@@ -7772,6 +7772,7 @@ F: include/linux/dma-direct.h
F: include/linux/dma-map-ops.h
F: include/linux/dma-mapping.h
F: include/linux/swiotlb.h
F: include/trace/events/dma.h
F: kernel/dma/
DMA MAPPING & SCATTERLIST API [RUST]
+1 -1
View File
@@ -125,7 +125,7 @@ static int __init xen_mm_init(void)
return 0;
/* we can work with the default swiotlb */
rc = swiotlb_init_late(swiotlb_size_or_default(),
rc = swiotlb_init_late(swiotlb_default_pool_size(),
xen_swiotlb_gfp(), NULL);
if (rc < 0)
return rc;
+1 -1
View File
@@ -349,7 +349,7 @@ void __init arch_mm_preinit(void)
unsigned long size =
DIV_ROUND_UP(memblock_phys_mem_size(), 1024);
swiotlb_adjust_size(min(swiotlb_size_or_default(), size));
swiotlb_adjust_size(min(swiotlb_default_pool_size(), size));
}
swiotlb_init(true, flags);
+1 -1
View File
@@ -186,7 +186,7 @@ void __init arch_mm_preinit(void)
*/
unsigned long size =
DIV_ROUND_UP(memblock_phys_mem_size(), 1024);
swiotlb_adjust_size(min(swiotlb_size_or_default(), size));
swiotlb_adjust_size(min(swiotlb_default_pool_size(), size));
swiotlb = true;
swiotlb_flags |= SWIOTLB_ANY;
}
+2 -2
View File
@@ -18,7 +18,7 @@
* no good way to detect the paging mode of the target kernel which will be
* loaded for dumping.
*/
extern unsigned long swiotlb_size_or_default(void);
extern unsigned long swiotlb_default_pool_size(void);
#ifdef CONFIG_X86_32
# define CRASH_ADDR_LOW_MAX SZ_512M
@@ -33,7 +33,7 @@ extern unsigned long swiotlb_size_or_default(void);
static inline unsigned long crash_low_size_default(void)
{
#ifdef CONFIG_X86_64
return max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20);
return max(swiotlb_default_pool_size() + (8UL << 20), 256UL << 20);
#else
return 0;
#endif
+7 -5
View File
@@ -1628,10 +1628,12 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
void *cpu_addr;
page = dma_alloc_contiguous(dev, alloc_size, gfp);
if (!page)
page = alloc_pages_node(node, gfp, get_order(alloc_size));
if (!page)
return NULL;
if (!page) {
cpu_addr = alloc_pages_exact_nid(node, alloc_size, gfp);
if (!cpu_addr)
return NULL;
page = virt_to_page(cpu_addr);
}
if (!coherent || PageHighMem(page)) {
pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
@@ -1762,7 +1764,7 @@ unsigned long iommu_dma_get_merge_boundary(struct device *dev)
return (1UL << __ffs(domain->pgsize_bitmap)) - 1;
}
size_t iommu_dma_opt_mapping_size(void)
size_t iommu_dma_max_opt_mapping_size(void)
{
return iova_rcache_range();
}
+1 -1
View File
@@ -3747,7 +3747,7 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev,
*/
dev->ctrl.max_hw_sectors = min_t(u32,
NVME_MAX_BYTES >> SECTOR_SHIFT,
dma_opt_mapping_size(&pdev->dev) >> 9);
dma_max_opt_mapping_size(&pdev->dev) >> SECTOR_SHIFT);
dev->ctrl.max_segments = NVME_MAX_SEGS;
dev->ctrl.max_integrity_segments = 1;
return dev;
+6 -6
View File
@@ -225,8 +225,8 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
/*
* Set shost->opt_sectors from the DMA optimal mapping size, but only
* when dma_opt_mapping_size() is strictly less than dma_max_mapping_size(),
* indicating a genuine optimization hint from an IOMMU or DMA backend.
* when dma_max_opt_mapping_size() is strictly less than
* dma_max_mapping_size(), indicating a genuine optimization hint.
* When the two are equal (e.g. IOMMU disabled / passthrough), no real
* hint exists, so leave opt_sectors at 0 to avoid bogus optimal_io_size
* values that break filesystem geometry (e.g. mkfs.xfs stripe alignment).
@@ -234,16 +234,16 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
static void sas_dma_setup_opt_sectors(struct Scsi_Host *shost)
{
struct device *dma_dev = shost->dma_dev;
size_t opt = dma_opt_mapping_size(dma_dev);
size_t max_opt = dma_max_opt_mapping_size(dma_dev);
size_t max = dma_max_mapping_size(dma_dev);
unsigned int opt_sectors;
/* opt >= max means no real hint was provided by the DMA layer */
if (opt >= max)
/* max_opt >= max means no real hint was provided by the DMA layer */
if (max_opt >= max)
return;
/* Clamp to max_sectors to avoid overflow in sector arithmetic */
opt_sectors = min_t(unsigned int, opt >> SECTOR_SHIFT,
opt_sectors = min_t(unsigned int, max_opt >> SECTOR_SHIFT,
shost->max_sectors);
/* Guard against zero before rounddown_pow_of_two() */
+2 -2
View File
@@ -60,7 +60,7 @@ struct dma_map_ops {
int (*dma_supported)(struct device *dev, u64 mask);
u64 (*get_required_mask)(struct device *dev);
size_t (*max_mapping_size)(struct device *dev);
size_t (*opt_mapping_size)(void);
size_t (*max_opt_mapping_size)(void);
unsigned long (*get_merge_boundary)(struct device *dev);
};
@@ -143,7 +143,7 @@ static inline struct page *dma_alloc_contiguous(struct device *dev, size_t size,
static inline void dma_free_contiguous(struct device *dev, struct page *page,
size_t size)
{
__free_pages(page, get_order(size));
free_pages_exact(page_address(page), size);
}
#endif /* CONFIG_DMA_CMA*/
+2 -2
View File
@@ -207,7 +207,7 @@ int dma_set_coherent_mask(struct device *dev, u64 mask);
u64 dma_get_required_mask(struct device *dev);
bool dma_addressing_limited(struct device *dev);
size_t dma_max_mapping_size(struct device *dev);
size_t dma_opt_mapping_size(struct device *dev);
size_t dma_max_opt_mapping_size(struct device *dev);
unsigned long dma_get_merge_boundary(struct device *dev);
struct sg_table *dma_alloc_noncontiguous(struct device *dev, size_t size,
enum dma_data_direction dir, gfp_t gfp, unsigned long attrs);
@@ -326,7 +326,7 @@ static inline size_t dma_max_mapping_size(struct device *dev)
{
return 0;
}
static inline size_t dma_opt_mapping_size(struct device *dev)
static inline size_t dma_max_opt_mapping_size(struct device *dev)
{
return 0;
}
+1 -1
View File
@@ -325,7 +325,7 @@ void *alloc_pages_exact_noprof(size_t size, gfp_t gfp_mask) __alloc_size(1);
void free_pages_exact(void *virt, size_t size);
__meminit void *alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mask) __alloc_size(2);
void *alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mask) __alloc_size(2);
#define alloc_pages_exact_nid(...) \
alloc_hooks(alloc_pages_exact_nid_noprof(__VA_ARGS__))
+1 -1
View File
@@ -39,7 +39,7 @@ int iommu_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs);
unsigned long iommu_dma_get_merge_boundary(struct device *dev);
size_t iommu_dma_opt_mapping_size(void);
size_t iommu_dma_max_opt_mapping_size(void);
size_t iommu_dma_max_mapping_size(struct device *dev);
void iommu_dma_free(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, unsigned long attrs);
+1 -1
View File
@@ -38,7 +38,7 @@ struct scatterlist;
#define IO_TLB_DEFAULT_SIZE (64UL << 20)
#endif
unsigned long swiotlb_size_or_default(void);
unsigned long swiotlb_default_pool_size(void);
void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,
int (*remap)(void *tlb, unsigned long nslabs));
int swiotlb_init_late(size_t size, gfp_t gfp_mask,
+3 -3
View File
@@ -451,8 +451,8 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
*
* This function releases memory allocated by dma_alloc_contiguous(). As the
* cma_release returns false when provided pages do not belong to contiguous
* area and true otherwise, this function then does a fallback __free_pages()
* upon a false-return.
* area and true otherwise, this function then does a fallback
* free_pages_exact() upon a false-return.
*/
void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
{
@@ -476,7 +476,7 @@ void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
}
/* not in any cma, free from buddy */
__free_pages(page, get_order(size));
free_pages_exact(page_address(page), size);
}
/*
+5 -2
View File
@@ -489,8 +489,10 @@ static int active_cacheline_insert(struct dma_debug_entry *entry,
/* If the device is not writing memory then we don't have any
* concerns about the cpu consuming stale data. This mitigates
* legitimate usages of overlapping mappings.
* MMIO mappings are never CPU-cacheable and do not need tracking either.
*/
if (entry->direction == DMA_TO_DEVICE)
if (entry->direction == DMA_TO_DEVICE ||
entry->attrs & DMA_ATTR_MMIO)
return 0;
spin_lock_irqsave(&radix_lock, flags);
@@ -519,7 +521,8 @@ static void active_cacheline_remove(struct dma_debug_entry *entry)
unsigned long flags;
/* ...mirror the insert case */
if (entry->direction == DMA_TO_DEVICE)
if (entry->direction == DMA_TO_DEVICE ||
entry->attrs & DMA_ATTR_MMIO)
return;
spin_lock_irqsave(&radix_lock, flags);
+23 -7
View File
@@ -120,6 +120,7 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
int node = dev_to_node(dev);
struct page *page;
u64 phys_limit;
void *va;
WARN_ON_ONCE(!PAGE_ALIGNED(size));
@@ -133,9 +134,9 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
dma_free_contiguous(dev, page, size);
}
while ((page = alloc_pages_node(node, gfp, get_order(size)))
&& !dma_coherent_ok(dev, page_to_phys(page), size)) {
__free_pages(page, get_order(size));
while ((va = alloc_pages_exact_nid(node, size, gfp)) &&
!dma_coherent_ok(dev, virt_to_phys(va), size)) {
free_pages_exact(va, size);
if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
phys_limit < DMA_BIT_MASK(64) &&
@@ -146,6 +147,7 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
else
return NULL;
}
page = va ? virt_to_page(va) : NULL;
return page;
}
@@ -179,6 +181,22 @@ static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size,
return page;
}
/*
* Check if the allocation can skip the kernel mapping and return the page
* pointer as the cookie.
*/
static bool dma_direct_use_no_mapping(struct device *dev, unsigned long attrs)
{
if ((attrs & (DMA_ATTR_NO_KERNEL_MAPPING | __DMA_ATTR_ALLOC_CC_SHARED)) !=
DMA_ATTR_NO_KERNEL_MAPPING)
return false;
if (is_swiotlb_for_alloc(dev))
return false;
if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_ALLOC) && !dev_is_dma_coherent(dev))
return false;
return true;
}
static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp)
{
@@ -226,8 +244,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
if (attrs & DMA_ATTR_NO_WARN)
gfp |= __GFP_NOWARN;
if (((attrs & (DMA_ATTR_NO_KERNEL_MAPPING | __DMA_ATTR_ALLOC_CC_SHARED)) ==
DMA_ATTR_NO_KERNEL_MAPPING) && !is_swiotlb_for_alloc(dev))
if (dma_direct_use_no_mapping(dev, attrs))
return dma_direct_alloc_no_mapping(dev, size, dma_handle, gfp);
if (!dev_is_dma_coherent(dev)) {
@@ -374,8 +391,7 @@ void dma_direct_free(struct device *dev, size_t size,
if (attrs & __DMA_ATTR_ALLOC_CC_SHARED)
mark_mem_encrypted = true;
if (((attrs & (DMA_ATTR_NO_KERNEL_MAPPING | __DMA_ATTR_ALLOC_CC_SHARED)) ==
DMA_ATTR_NO_KERNEL_MAPPING) && !is_swiotlb_for_alloc(dev)) {
if (dma_direct_use_no_mapping(dev, attrs)) {
/* cpu_addr is a struct page cookie, not a kernel address */
dma_free_contiguous(dev, cpu_addr, size);
return;
+5 -5
View File
@@ -1012,19 +1012,19 @@ size_t dma_max_mapping_size(struct device *dev)
}
EXPORT_SYMBOL_GPL(dma_max_mapping_size);
size_t dma_opt_mapping_size(struct device *dev)
size_t dma_max_opt_mapping_size(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
size_t size = SIZE_MAX;
if (use_dma_iommu(dev))
size = iommu_dma_opt_mapping_size();
else if (ops && ops->opt_mapping_size)
size = ops->opt_mapping_size();
size = iommu_dma_max_opt_mapping_size();
else if (ops && ops->max_opt_mapping_size)
size = ops->max_opt_mapping_size();
return min(dma_max_mapping_size(dev), size);
}
EXPORT_SYMBOL_GPL(dma_opt_mapping_size);
EXPORT_SYMBOL_GPL(dma_max_opt_mapping_size);
unsigned long dma_get_merge_boundary(struct device *dev)
{
+7 -4
View File
@@ -67,10 +67,13 @@ struct page *dma_common_alloc_pages(struct device *dev, size_t size,
phys_addr_t phys;
page = dma_alloc_contiguous(dev, size, gfp);
if (!page)
page = alloc_pages_node(dev_to_node(dev), gfp, get_order(size));
if (!page)
return NULL;
if (!page) {
void *va = alloc_pages_exact_nid(dev_to_node(dev), size, gfp);
if (!va)
return NULL;
page = virt_to_page(va);
}
phys = page_to_phys(page);
if (use_dma_iommu(dev))
+26 -28
View File
@@ -100,6 +100,7 @@ static struct io_tlb_mem io_tlb_default_mem;
static unsigned long default_nslabs = IO_TLB_DEFAULT_SIZE >> IO_TLB_SHIFT;
static unsigned long default_nareas;
static bool swiotlb_cmdline_size_set __initdata;
/**
* struct io_tlb_area - IO TLB memory area descriptor
@@ -117,27 +118,20 @@ struct io_tlb_area {
spinlock_t lock;
};
/*
* Round up number of slabs to the next power of 2. The last area is going
* be smaller than the rest if default_nslabs is not power of two.
* The number of slot in an area should be a multiple of IO_TLB_SEGSIZE,
* otherwise a segment may span two or more areas. It conflicts with free
* contiguous slots tracking: free slots are treated contiguous no matter
* whether they cross an area boundary.
*
* Return true if default_nslabs is rounded up.
*/
static bool round_up_default_nslabs(void)
/* Return a power-of-two number of slabs that can be split between areas. */
static unsigned long swiotlb_calc_nslabs(unsigned long size,
unsigned long nareas)
{
if (!default_nareas)
return false;
unsigned long nslabs;
if (default_nslabs < IO_TLB_SEGSIZE * default_nareas)
default_nslabs = IO_TLB_SEGSIZE * default_nareas;
else if (is_power_of_2(default_nslabs))
return false;
default_nslabs = roundup_pow_of_two(default_nslabs);
return true;
nslabs = ALIGN(DIV_ROUND_UP(size, IO_TLB_SIZE), IO_TLB_SEGSIZE);
if (nareas && nslabs < IO_TLB_SEGSIZE * nareas)
nslabs = IO_TLB_SEGSIZE * nareas;
if (!is_power_of_2(nslabs))
nslabs = roundup_pow_of_two(nslabs);
return nslabs;
}
/**
@@ -150,6 +144,8 @@ static bool round_up_default_nslabs(void)
*/
static void swiotlb_adjust_nareas(unsigned int nareas)
{
unsigned long nslabs;
if (!nareas)
nareas = 1;
else if (!is_power_of_2(nareas))
@@ -158,9 +154,12 @@ static void swiotlb_adjust_nareas(unsigned int nareas)
default_nareas = nareas;
pr_info("area num %d.\n", nareas);
if (round_up_default_nslabs())
nslabs = swiotlb_calc_nslabs(default_nslabs << IO_TLB_SHIFT, nareas);
if (nslabs != default_nslabs) {
default_nslabs = nslabs;
pr_info("SWIOTLB bounce buffer size roundup to %luMB",
(default_nslabs << IO_TLB_SHIFT) >> 20);
}
}
/**
@@ -255,6 +254,7 @@ setup_io_tlb_npages(char *str)
/* avoid tail segment of size < IO_TLB_SEGSIZE */
default_nslabs =
ALIGN(simple_strtoul(str, &str, 0), IO_TLB_SEGSIZE);
swiotlb_cmdline_size_set = true;
}
if (*str == ',')
++str;
@@ -285,7 +285,7 @@ setup_io_tlb_npages(char *str)
}
early_param("swiotlb", setup_io_tlb_npages);
unsigned long swiotlb_size_or_default(void)
unsigned long swiotlb_default_pool_size(void)
{
return default_nslabs << IO_TLB_SHIFT;
}
@@ -297,13 +297,11 @@ void __init swiotlb_adjust_size(unsigned long size)
* architectures such as those supporting memory encryption to
* adjust/expand SWIOTLB size for their use.
*/
if (default_nslabs != IO_TLB_DEFAULT_SIZE >> IO_TLB_SHIFT)
if (swiotlb_cmdline_size_set)
return;
size = ALIGN(size, IO_TLB_SIZE);
default_nslabs = ALIGN(size >> IO_TLB_SHIFT, IO_TLB_SEGSIZE);
if (round_up_default_nslabs())
size = default_nslabs << IO_TLB_SHIFT;
default_nslabs = swiotlb_calc_nslabs(size, default_nareas);
size = default_nslabs << IO_TLB_SHIFT;
pr_info("SWIOTLB bounce buffer size adjusted to %luMB", size >> 20);
}
@@ -2083,8 +2081,8 @@ static int __init rmem_swiotlb_setup(unsigned long node,
of_get_flat_dt_prop(node, "no-map", NULL))
return -EINVAL;
pr_info("Reserved memory: created restricted DMA pool at %pa, size %ld MiB\n",
&rmem->base, (unsigned long)rmem->size / SZ_1M);
pr_info("Reserved memory: created restricted DMA pool at %pa, size %llu KiB\n",
&rmem->base, (unsigned long long)(rmem->size / SZ_1K));
return 0;
}
+1 -1
View File
@@ -5648,7 +5648,7 @@ EXPORT_SYMBOL(alloc_pages_exact_noprof);
*
* Return: pointer to the allocated area or %NULL in case of error.
*/
void * __meminit alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mask)
void *alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mask)
{
unsigned int order = get_order(size);
struct page *p;
+8 -2
View File
@@ -7,7 +7,13 @@ bindir ?= /usr/bin
# isn't set and when invoked from selftests build, where srctree
# is set to ".". building_out_of_srctree is undefined for in srctree
# builds
ifeq ($(srctree),)
update_srctree := 1
endif
ifndef building_out_of_srctree
update_srctree := 1
endif
ifeq ($(update_srctree),1)
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
endif
@@ -38,8 +44,8 @@ prepare: $(OUTPUT)include/linux/map_benchmark.h
FORCE:
DMA_MAP_BENCHMARK = dma_map_benchmark
$(DMA_MAP_BENCHMARK): prepare FORCE
$(CC) $(CFLAGS) $(DMA_MAP_BENCHMARK).c -o $(DMA_MAP_BENCHMARK)
$(OUTPUT)$(DMA_MAP_BENCHMARK): prepare FORCE
$(CC) $(CFLAGS) $(DMA_MAP_BENCHMARK).c -o $@
clean:
rm -f $(ALL_PROGRAMS)