summaryrefslogtreecommitdiff
path: root/kernel/dma
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@kernel.org>2026-08-17 10:29:52 +0200
committerThomas Gleixner <tglx@kernel.org>2026-08-17 10:29:52 +0200
commit0eaed89c18aeedf0898baf2dbf5ff027c6795152 (patch)
tree4422cb10597581af05704ba6510018aabf25b268 /kernel/dma
parentc66494c79ede1af529dbf67f9ed6fdbf42e05ef3 (diff)
parent8b4127f6db40381229f3564d34ac35f36311c201 (diff)
Merge tag 'timers-v7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/daniel.lezcano/linux into timers/clocksource
- Use designated initializers for sh_mtu2, sh_cmt, and sh_tmu, and drop the unused initializer in the platform_device_id table for sh_mtu2 (Uwe Kleine-König) - Remove redundant dev_err()/dev_err_probe() messages when devm_request_*_irq() fails, as the helper already logs an error message (Pan Chuang) - Fix a boot hang on Allwinner D1 when a forced minimum delta is used with the sun4i timer (Felix Yan) - Fix an IRQ leak in the cpuhp_setup_state() error path by freeing the IRQ on failure in the NXP PIT driver (WenTao Liang) - Fix incorrect unmapping of shared MMIO between the clocksource and clockevent drivers. If one of them fails to initialize, the error path unmaps the shared MMIO region, leaving the other driver with an invalid mapping on clps711x (Guangshuo Li) - Make the samsung_pwm driver compatible with PREEMPT_RT by replacing regular spinlocks with raw_spinlock_t in atomic contexts (Marek Szyprowski) - Use __raw_readl() and __raw_writel() instead of ioread32() and iowrite32() to support SWAP_IO_SPACE in the rtl-otto driver (Rustam Adilov) - Fix a missing clk_disable_unprepare() call in the timer initialization error path of the Armada driver (Yuho Choi) Link: https://lore.kernel.org/lkml/75feea31-683d-45a1-87f4-ab045e0152ae@oss.qualcomm.com
Diffstat (limited to 'kernel/dma')
-rw-r--r--kernel/dma/Kconfig14
-rw-r--r--kernel/dma/contiguous.c58
-rw-r--r--kernel/dma/debug.c98
-rw-r--r--kernel/dma/debug.h25
-rw-r--r--kernel/dma/direct.c6
-rw-r--r--kernel/dma/map_benchmark.c27
-rw-r--r--kernel/dma/mapping.c26
7 files changed, 143 insertions, 111 deletions
diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig
index bfef21b4a9ae..0a4ba21a57a7 100644
--- a/kernel/dma/Kconfig
+++ b/kernel/dma/Kconfig
@@ -179,7 +179,19 @@ config DMA_NUMA_CMA
You can set the size of pernuma CMA by specifying "cma_pernuma=size"
or set the node id and its size of CMA by specifying "numa_cma=
- <node>:size[,<node>:size]" on the kernel's command line.
+ <node>:size[,<node>:size]" on the kernel's command line. And in
+ rare case that the above 2 are both setup, then the "numa_cma="
+ takes priority for the specified numa nodes.
+
+config CMA_SIZE_PERNUMA
+ bool "Default CMA area per NUMA node"
+ depends on DMA_NUMA_CMA
+ default y
+ help
+ On systems with more than one NUMA node, the selected CMA
+ area size will be also allocated on each additional node,
+ so that most devices may have benefit from better DMA
+ locality without an explicit command-line opt-in.
comment "Default contiguous memory area size:"
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index 03f52bd17120..f754079a287d 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -134,8 +134,8 @@ EXPORT_SYMBOL_GPL(dev_get_cma_area);
static struct cma *dma_contiguous_numa_area[MAX_NUMNODES];
static phys_addr_t numa_cma_size[MAX_NUMNODES] __initdata;
-static struct cma *dma_contiguous_pernuma_area[MAX_NUMNODES];
static phys_addr_t pernuma_size_bytes __initdata;
+static bool numa_cma_configured __initdata;
static int __init early_numa_cma(char *p)
{
@@ -164,6 +164,7 @@ static int __init early_numa_cma(char *p)
break;
}
+ numa_cma_configured = true;
return 0;
}
early_param("numa_cma", early_numa_cma);
@@ -171,6 +172,7 @@ early_param("numa_cma", early_numa_cma);
static int __init early_cma_pernuma(char *p)
{
pernuma_size_bytes = memparse(p, &p);
+ numa_cma_configured = true;
return 0;
}
early_param("cma_pernuma", early_cma_pernuma);
@@ -199,8 +201,13 @@ static void __init dma_numa_cma_reserve(void)
{
int nid;
+ if (IS_ENABLED(CONFIG_CMA_SIZE_PERNUMA) &&
+ !numa_cma_configured && dma_contiguous_default_area &&
+ nr_online_nodes > 1)
+ pernuma_size_bytes = cma_get_size(dma_contiguous_default_area);
+
for_each_node(nid) {
- int ret;
+ int size, ret;
char name[CMA_MAX_NAME];
struct cma **cma;
@@ -210,27 +217,17 @@ static void __init dma_numa_cma_reserve(void)
continue;
}
- if (pernuma_size_bytes) {
-
- cma = &dma_contiguous_pernuma_area[nid];
- snprintf(name, sizeof(name), "pernuma%d", nid);
- ret = cma_declare_contiguous_nid(0, pernuma_size_bytes, 0, 0,
- 0, false, name, cma, nid);
- if (ret)
- pr_warn("%s: reservation failed: err %d, node %d", __func__,
- ret, nid);
- }
-
- if (numa_cma_size[nid]) {
+ /* per-node numa setting has the priority */
+ size = numa_cma_size[nid] ?: pernuma_size_bytes;
+ if (!size)
+ continue;
- cma = &dma_contiguous_numa_area[nid];
- snprintf(name, sizeof(name), "numa%d", nid);
- ret = cma_declare_contiguous_nid(0, numa_cma_size[nid], 0, 0, 0, false,
- name, cma, nid);
- if (ret)
- pr_warn("%s: reservation failed: err %d, node %d", __func__,
- ret, nid);
- }
+ cma = &dma_contiguous_numa_area[nid];
+ snprintf(name, sizeof(name), "numa%d", nid);
+ ret = cma_declare_contiguous_nid(0, size, 0, 0, 0, false, name, cma, nid);
+ if (ret)
+ pr_warn("%s: reservation failed: err %d, node %d", __func__,
+ ret, nid);
}
}
#else
@@ -255,8 +252,6 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
phys_addr_t selected_limit = limit;
bool fixed = false;
- dma_numa_cma_reserve();
-
pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
if (size_cmdline != -1) {
@@ -312,6 +307,8 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
if (ret)
pr_warn("Couldn't queue default CMA region for heap creation.");
}
+
+ dma_numa_cma_reserve();
}
void __weak
@@ -429,16 +426,8 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
#ifdef CONFIG_DMA_NUMA_CMA
if (nid != NUMA_NO_NODE && !(gfp & (GFP_DMA | GFP_DMA32))) {
- struct cma *cma = dma_contiguous_pernuma_area[nid];
+ struct cma *cma = dma_contiguous_numa_area[nid];
struct page *page;
-
- if (cma) {
- page = cma_alloc_aligned(cma, size, gfp);
- if (page)
- return page;
- }
-
- cma = dma_contiguous_numa_area[nid];
if (cma) {
page = cma_alloc_aligned(cma, size, gfp);
if (page)
@@ -476,9 +465,6 @@ void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
* otherwise, page is from either per-numa cma or default cma
*/
#ifdef CONFIG_DMA_NUMA_CMA
- if (cma_release(dma_contiguous_pernuma_area[page_to_nid(page)],
- page, count))
- return;
if (cma_release(dma_contiguous_numa_area[page_to_nid(page)],
page, count))
return;
diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c
index 1a725edbbbf6..026d50de340e 100644
--- a/kernel/dma/debug.c
+++ b/kernel/dma/debug.c
@@ -63,7 +63,7 @@ enum map_err_types {
* @sg_mapped_ents: 'mapped_ents' from dma_map_sg
* @paddr: physical start address of the mapping
* @map_err_type: track whether dma_mapping_error() was checked
- * @is_cache_clean: driver promises not to write to buffer while mapped
+ * @attrs: dma attributes
* @stack_len: number of backtrace entries in @stack_entries
* @stack_entries: stack of backtrace history
*/
@@ -78,7 +78,7 @@ struct dma_debug_entry {
int sg_mapped_ents;
phys_addr_t paddr;
enum map_err_types map_err_type;
- bool is_cache_clean;
+ unsigned long attrs;
#ifdef CONFIG_STACKTRACE
unsigned int stack_len;
unsigned long stack_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
@@ -478,6 +478,9 @@ static int active_cacheline_insert(struct dma_debug_entry *entry,
bool *overlap_cache_clean)
{
phys_addr_t cln = to_cacheline_number(entry);
+ bool is_cache_clean = entry->attrs &
+ (DMA_ATTR_DEBUGGING_IGNORE_CACHELINES |
+ DMA_ATTR_REQUIRE_COHERENT);
unsigned long flags;
int rc;
@@ -495,12 +498,15 @@ static int active_cacheline_insert(struct dma_debug_entry *entry,
if (rc == -EEXIST) {
struct dma_debug_entry *existing;
- active_cacheline_inc_overlap(cln, entry->is_cache_clean);
+ active_cacheline_inc_overlap(cln, is_cache_clean);
existing = radix_tree_lookup(&dma_active_cacheline, cln);
/* A lookup failure here after we got -EEXIST is unexpected. */
WARN_ON(!existing);
if (existing)
- *overlap_cache_clean = existing->is_cache_clean;
+ *overlap_cache_clean =
+ existing->attrs &
+ (DMA_ATTR_DEBUGGING_IGNORE_CACHELINES |
+ DMA_ATTR_REQUIRE_COHERENT);
}
spin_unlock_irqrestore(&radix_lock, flags);
@@ -544,12 +550,13 @@ void debug_dma_dump_mappings(struct device *dev)
if (!dev || dev == entry->dev) {
cln = to_cacheline_number(entry);
dev_info(entry->dev,
- "%s idx %d P=%pa D=%llx L=%llx cln=%pa %s %s\n",
+ "%s idx %d P=%pa D=%llx L=%llx cln=%pa %s %s attrs=0x%lx\n",
type2name[entry->type], idx,
&entry->paddr, entry->dev_addr,
entry->size, &cln,
dir2name[entry->direction],
- maperr2str[entry->map_err_type]);
+ maperr2str[entry->map_err_type],
+ entry->attrs);
}
}
spin_unlock_irqrestore(&bucket->lock, flags);
@@ -575,14 +582,15 @@ static int dump_show(struct seq_file *seq, void *v)
list_for_each_entry(entry, &bucket->list, list) {
cln = to_cacheline_number(entry);
seq_printf(seq,
- "%s %s %s idx %d P=%pa D=%llx L=%llx cln=%pa %s %s\n",
+ "%s %s %s idx %d P=%pa D=%llx L=%llx cln=%pa %s %s attrs=0x%lx\n",
dev_driver_string(entry->dev),
dev_name(entry->dev),
type2name[entry->type], idx,
&entry->paddr, entry->dev_addr,
entry->size, &cln,
dir2name[entry->direction],
- maperr2str[entry->map_err_type]);
+ maperr2str[entry->map_err_type],
+ entry->attrs);
}
spin_unlock_irqrestore(&bucket->lock, flags);
}
@@ -594,16 +602,14 @@ DEFINE_SHOW_ATTRIBUTE(dump);
* Wrapper function for adding an entry to the hash.
* This function takes care of locking itself.
*/
-static void add_dma_entry(struct dma_debug_entry *entry, unsigned long attrs)
+static void add_dma_entry(struct dma_debug_entry *entry)
{
+ unsigned long attrs = entry->attrs;
bool overlap_cache_clean;
struct hash_bucket *bucket;
unsigned long flags;
int rc;
- entry->is_cache_clean = attrs & (DMA_ATTR_DEBUGGING_IGNORE_CACHELINES |
- DMA_ATTR_REQUIRE_COHERENT);
-
bucket = get_hash_bucket(entry, &flags);
hash_bucket_add(bucket, entry);
put_hash_bucket(bucket, flags);
@@ -612,9 +618,10 @@ static void add_dma_entry(struct dma_debug_entry *entry, unsigned long attrs)
if (rc == -ENOMEM) {
pr_err_once("cacheline tracking ENOMEM, dma-debug disabled\n");
global_disable = true;
- } else if (rc == -EEXIST &&
- !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
- !(entry->is_cache_clean && overlap_cache_clean) &&
+ } else if (rc == -EEXIST && !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+ !(attrs & (DMA_ATTR_DEBUGGING_IGNORE_CACHELINES |
+ DMA_ATTR_REQUIRE_COHERENT) &&
+ overlap_cache_clean) &&
dma_get_cache_alignment() >= L1_CACHE_BYTES &&
!(IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) &&
is_swiotlb_active(entry->dev))) {
@@ -1067,6 +1074,29 @@ static void check_unmap(struct dma_debug_entry *ref)
type2name[entry->type]);
}
+ /*
+ * This may be no bug in reality - but DMA API still expects
+ * that entry is unmapped with same attributes as it was mapped.
+ *
+ * DMA_ATTR_UNMAP_VALID lists the attributes that must be identical
+ * between map and unmap. Any attribute outside this set (e.g.
+ * DMA_ATTR_NO_WARN, DMA_ATTR_SKIP_CPU_SYNC) is allowed to differ.
+ */
+#define DMA_ATTR_UNMAP_VALID \
+ (DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_FORCE_CONTIGUOUS | \
+ DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT | DMA_ATTR_PRIVILEGED | \
+ DMA_ATTR_CC_SHARED)
+ if ((ref->attrs & DMA_ATTR_UNMAP_VALID) !=
+ (entry->attrs & DMA_ATTR_UNMAP_VALID)) {
+ err_printk(ref->dev, entry,
+ "device driver frees "
+ "DMA memory with different attributes "
+ "[device address=0x%016llx] [size=%llu bytes] "
+ "[mapped with 0x%lx] [unmapped with 0x%lx]\n",
+ ref->dev_addr, ref->size, entry->attrs, ref->attrs);
+ }
+#undef DMA_ATTR_UNMAP_VALID
+
hash_bucket_del(entry);
put_hash_bucket(bucket, flags);
@@ -1250,15 +1280,23 @@ void debug_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
entry->size = size;
entry->direction = direction;
entry->map_err_type = MAP_ERR_NOT_CHECKED;
+ entry->attrs = attrs;
+
+ if (attrs & DMA_ATTR_MMIO) {
+ unsigned long pfn = PHYS_PFN(phys);
- if (!(attrs & DMA_ATTR_MMIO)) {
+ if (pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn)))
+ err_printk(dev, entry,
+ "dma_map_resource called for RAM address %pa\n",
+ &phys);
+ } else {
check_for_stack(dev, phys);
if (!PhysHighMem(phys))
check_for_illegal_area(dev, phys_to_virt(phys), size);
}
- add_dma_entry(entry, attrs);
+ add_dma_entry(entry);
}
void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
@@ -1299,8 +1337,8 @@ void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
}
EXPORT_SYMBOL(debug_dma_mapping_error);
-void debug_dma_unmap_phys(struct device *dev, dma_addr_t dma_addr,
- size_t size, int direction)
+void debug_dma_unmap_phys(struct device *dev, dma_addr_t dma_addr, size_t size,
+ int direction, unsigned long attrs)
{
struct dma_debug_entry ref = {
.type = dma_debug_phy,
@@ -1308,6 +1346,7 @@ void debug_dma_unmap_phys(struct device *dev, dma_addr_t dma_addr,
.dev_addr = dma_addr,
.size = size,
.direction = direction,
+ .attrs = attrs,
};
if (unlikely(dma_debug_disabled()))
@@ -1345,10 +1384,11 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
entry->direction = direction;
entry->sg_call_ents = nents;
entry->sg_mapped_ents = mapped_ents;
+ entry->attrs = attrs;
check_sg_segment(dev, s);
- add_dma_entry(entry, attrs);
+ add_dma_entry(entry);
}
}
@@ -1372,7 +1412,7 @@ static int get_nr_mapped_entries(struct device *dev,
}
void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
- int nelems, int dir)
+ int nelems, int dir, unsigned long attrs)
{
struct scatterlist *s;
int mapped_ents = 0, i;
@@ -1390,6 +1430,7 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
.size = sg_dma_len(s),
.direction = dir,
.sg_call_ents = nelems,
+ .attrs = attrs,
};
if (mapped_ents && i >= mapped_ents)
@@ -1440,12 +1481,13 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
entry->size = size;
entry->dev_addr = dma_addr;
entry->direction = DMA_BIDIRECTIONAL;
+ entry->attrs = attrs;
- add_dma_entry(entry, attrs);
+ add_dma_entry(entry);
}
-void debug_dma_free_coherent(struct device *dev, size_t size,
- void *virt, dma_addr_t dma_addr)
+void debug_dma_free_coherent(struct device *dev, size_t size, void *virt,
+ dma_addr_t dma_addr, unsigned long attrs)
{
struct dma_debug_entry ref = {
.type = dma_debug_coherent,
@@ -1453,6 +1495,7 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
.dev_addr = dma_addr,
.size = size,
.direction = DMA_BIDIRECTIONAL,
+ .attrs = attrs,
};
/* handle vmalloc and linear addresses */
@@ -1549,7 +1592,7 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
struct dma_debug_entry ref = {
.type = dma_debug_sg,
.dev = dev,
- .paddr = sg_phys(sg),
+ .paddr = sg_phys(s),
.dev_addr = sg_dma_address(s),
.size = sg_dma_len(s),
.direction = direction,
@@ -1567,8 +1610,7 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
void debug_dma_alloc_pages(struct device *dev, struct page *page,
size_t size, int direction,
- dma_addr_t dma_addr,
- unsigned long attrs)
+ dma_addr_t dma_addr)
{
struct dma_debug_entry *entry;
@@ -1586,7 +1628,7 @@ void debug_dma_alloc_pages(struct device *dev, struct page *page,
entry->dev_addr = dma_addr;
entry->direction = direction;
- add_dma_entry(entry, attrs);
+ add_dma_entry(entry);
}
void debug_dma_free_pages(struct device *dev, struct page *page,
diff --git a/kernel/dma/debug.h b/kernel/dma/debug.h
index da7be0bddcf6..13e384633c32 100644
--- a/kernel/dma/debug.h
+++ b/kernel/dma/debug.h
@@ -14,21 +14,22 @@ extern void debug_dma_map_phys(struct device *dev, phys_addr_t phys,
unsigned long attrs);
extern void debug_dma_unmap_phys(struct device *dev, dma_addr_t addr,
- size_t size, int direction);
+ size_t size, int direction,
+ unsigned long attrs);
extern void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
int nents, int mapped_ents, int direction,
unsigned long attrs);
extern void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
- int nelems, int dir);
+ int nelems, int dir, unsigned long attrs);
extern void debug_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t dma_addr, void *virt,
unsigned long attrs);
-extern void debug_dma_free_coherent(struct device *dev, size_t size,
- void *virt, dma_addr_t addr);
+extern void debug_dma_free_coherent(struct device *dev, size_t size, void *virt,
+ dma_addr_t addr, unsigned long attrs);
extern void debug_dma_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
@@ -47,8 +48,7 @@ extern void debug_dma_sync_sg_for_device(struct device *dev,
int nelems, int direction);
extern void debug_dma_alloc_pages(struct device *dev, struct page *page,
size_t size, int direction,
- dma_addr_t dma_addr,
- unsigned long attrs);
+ dma_addr_t dma_addr);
extern void debug_dma_free_pages(struct device *dev, struct page *page,
size_t size, int direction,
dma_addr_t dma_addr);
@@ -60,7 +60,8 @@ static inline void debug_dma_map_phys(struct device *dev, phys_addr_t phys,
}
static inline void debug_dma_unmap_phys(struct device *dev, dma_addr_t addr,
- size_t size, int direction)
+ size_t size, int direction,
+ unsigned long attrs)
{
}
@@ -71,8 +72,8 @@ static inline void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
}
static inline void debug_dma_unmap_sg(struct device *dev,
- struct scatterlist *sglist,
- int nelems, int dir)
+ struct scatterlist *sglist, int nelems,
+ int dir, unsigned long attrs)
{
}
@@ -83,7 +84,8 @@ static inline void debug_dma_alloc_coherent(struct device *dev, size_t size,
}
static inline void debug_dma_free_coherent(struct device *dev, size_t size,
- void *virt, dma_addr_t addr)
+ void *virt, dma_addr_t addr,
+ unsigned long attrs)
{
}
@@ -113,8 +115,7 @@ static inline void debug_dma_sync_sg_for_device(struct device *dev,
static inline void debug_dma_alloc_pages(struct device *dev, struct page *page,
size_t size, int direction,
- dma_addr_t dma_addr,
- unsigned long attrs)
+ dma_addr_t dma_addr)
{
}
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index ec887f443741..4391b797d4db 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -39,7 +39,7 @@ static inline struct page *dma_direct_to_page(struct device *dev,
u64 dma_direct_get_required_mask(struct device *dev)
{
- phys_addr_t phys = (phys_addr_t)(max_pfn - 1) << PAGE_SHIFT;
+ phys_addr_t phys = ((phys_addr_t)max_pfn << PAGE_SHIFT) - 1;
u64 max_dma = phys_to_dma_direct(dev, phys);
return (1ULL << (fls64(max_dma) - 1)) * 2 - 1;
@@ -476,7 +476,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
* must be mapped with CPU physical address and not PCI
* bus addresses.
*/
- break;
+ fallthrough;
case PCI_P2PDMA_MAP_NONE:
need_sync = true;
sg->dma_address = dma_direct_map_phys(dev, sg_phys(sg),
@@ -553,7 +553,7 @@ int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma,
int dma_direct_supported(struct device *dev, u64 mask)
{
- u64 min_mask = (max_pfn - 1) << PAGE_SHIFT;
+ u64 min_mask = ((u64)max_pfn << PAGE_SHIFT) - 1;
/*
* Because 32-bit DMA masks are so common we expect every architecture
diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c
index 29eeb5fdf199..fdc070f419f6 100644
--- a/kernel/dma/map_benchmark.c
+++ b/kernel/dma/map_benchmark.c
@@ -121,35 +121,35 @@ static struct map_benchmark_ops dma_single_map_benchmark_ops = {
struct dma_sg_map_param {
struct sg_table sgt;
struct device *dev;
- void **buf;
u32 npages;
u32 dma_dir;
+ void *buf[] __counted_by(npages);
};
static void *dma_sg_map_benchmark_prepare(struct map_benchmark_data *map)
{
+ struct dma_sg_map_param *params;
struct scatterlist *sg;
+ u32 npages;
int i;
- struct dma_sg_map_param *params = kzalloc(sizeof(*params), GFP_KERNEL);
-
- if (!params)
- return NULL;
/*
* Set the number of scatterlist entries based on the granule.
* In SG mode, 'granule' represents the number of scatterlist entries.
* Each scatterlist entry corresponds to a single page.
*/
- params->npages = map->bparam.granule;
+ npages = map->bparam.granule;
+
+ params = kzalloc_flex(*params, buf, npages);
+ if (!params)
+ return NULL;
+
+ params->npages = npages;
params->dma_dir = map->bparam.dma_dir;
params->dev = map->dev;
- params->buf = kmalloc_array(params->npages, sizeof(*params->buf),
- GFP_KERNEL);
- if (!params->buf)
- goto out;
if (sg_alloc_table(&params->sgt, params->npages, GFP_KERNEL))
- goto free_buf;
+ goto free_params;
for_each_sgtable_sg(&params->sgt, sg, i) {
params->buf[i] = (void *)__get_free_page(GFP_KERNEL);
@@ -166,9 +166,7 @@ free_page:
free_page((unsigned long)params->buf[i]);
sg_free_table(&params->sgt);
-free_buf:
- kfree(params->buf);
-out:
+free_params:
kfree(params);
return NULL;
}
@@ -183,7 +181,6 @@ static void dma_sg_map_benchmark_unprepare(void *mparam)
sg_free_table(&params->sgt);
- kfree(params->buf);
kfree(params);
}
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index 23ed8eb9233e..4fe04669e5e6 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -126,11 +126,9 @@ static bool dma_go_direct(struct device *dev, dma_addr_t mask,
if (likely(!ops))
return true;
-#ifdef CONFIG_DMA_OPS_BYPASS
- if (dev->dma_ops_bypass)
+ if (IS_ENABLED(CONFIG_DMA_OPS_BYPASS) && dev_dma_ops_bypass(dev))
return min_not_zero(mask, dev->bus_dma_limit) >=
dma_direct_get_required_mask(dev);
-#endif
return false;
}
@@ -225,7 +223,7 @@ void dma_unmap_phys(struct device *dev, dma_addr_t addr, size_t size,
else if (ops->unmap_phys)
ops->unmap_phys(dev, addr, size, dir, attrs);
trace_dma_unmap_phys(dev, addr, size, dir, attrs);
- debug_dma_unmap_phys(dev, addr, size, dir);
+ debug_dma_unmap_phys(dev, addr, size, dir, attrs);
}
EXPORT_SYMBOL_GPL(dma_unmap_phys);
@@ -351,7 +349,7 @@ void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
BUG_ON(!valid_dma_direction(dir));
trace_dma_unmap_sg(dev, sg, nents, dir, attrs);
- debug_dma_unmap_sg(dev, sg, nents, dir);
+ debug_dma_unmap_sg(dev, sg, nents, dir, attrs);
if (dma_map_direct(dev, ops) ||
arch_dma_unmap_sg_direct(dev, sg, nents))
dma_direct_unmap_sg(dev, sg, nents, dir, attrs);
@@ -365,10 +363,6 @@ EXPORT_SYMBOL(dma_unmap_sg_attrs);
dma_addr_t dma_map_resource(struct device *dev, phys_addr_t phys_addr,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
- if (IS_ENABLED(CONFIG_DMA_API_DEBUG) &&
- WARN_ON_ONCE(pfn_valid(PHYS_PFN(phys_addr))))
- return DMA_MAPPING_ERROR;
-
return dma_map_phys(dev, phys_addr, size, dir, attrs | DMA_ATTR_MMIO);
}
EXPORT_SYMBOL(dma_map_resource);
@@ -476,7 +470,7 @@ bool dma_need_unmap(struct device *dev)
{
if (!dma_map_direct(dev, get_dma_ops(dev)))
return true;
- if (!dev->dma_skip_sync)
+ if (!dev_dma_skip_sync(dev))
return true;
return IS_ENABLED(CONFIG_DMA_API_DEBUG);
}
@@ -492,16 +486,16 @@ static void dma_setup_need_sync(struct device *dev)
* mapping, if any. During the device initialization, it's
* enough to check only for the DMA coherence.
*/
- dev->dma_skip_sync = dev_is_dma_coherent(dev);
+ dev_assign_dma_skip_sync(dev, dev_is_dma_coherent(dev));
else if (!ops->sync_single_for_device && !ops->sync_single_for_cpu &&
!ops->sync_sg_for_device && !ops->sync_sg_for_cpu)
/*
* Synchronization is not possible when none of DMA sync ops
* is set.
*/
- dev->dma_skip_sync = true;
+ dev_set_dma_skip_sync(dev);
else
- dev->dma_skip_sync = false;
+ dev_clear_dma_skip_sync(dev);
}
#else /* !CONFIG_DMA_NEED_SYNC */
static inline void dma_setup_need_sync(struct device *dev) { }
@@ -693,7 +687,7 @@ void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
if (!cpu_addr)
return;
- debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
+ debug_dma_free_coherent(dev, size, cpu_addr, dma_handle, attrs);
if (dma_alloc_direct(dev, ops) || arch_dma_free_direct(dev, dma_handle))
dma_direct_free(dev, size, cpu_addr, dma_handle, attrs);
else if (use_dma_iommu(dev))
@@ -733,7 +727,7 @@ struct page *dma_alloc_pages(struct device *dev, size_t size,
if (page) {
trace_dma_alloc_pages(dev, page_to_virt(page), *dma_handle,
size, dir, gfp, 0);
- debug_dma_alloc_pages(dev, page, size, dir, *dma_handle, 0);
+ debug_dma_alloc_pages(dev, page, size, dir, *dma_handle);
} else {
trace_dma_alloc_pages(dev, NULL, 0, size, dir, gfp, 0);
}
@@ -840,7 +834,7 @@ void dma_free_noncontiguous(struct device *dev, size_t size,
struct sg_table *sgt, enum dma_data_direction dir)
{
trace_dma_free_sgt(dev, sgt, size, dir);
- debug_dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
+ debug_dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir, 0);
if (use_dma_iommu(dev))
iommu_dma_free_noncontiguous(dev, size, sgt, dir);