mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
dma-mapping updates for Linux 7.2:
- added more checks for DMA attributes in the debug code, especially to ensure that mappings are created and released with matching attributes (Leon Romanovsky) - better default configuration for CMA on NUMA machines (Feng Tang) - little code cleanup in dma benchmark tool (Rosen Penev) -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSrngzkoBtlA8uaaJ+Jp1EFxbsSRAUCajESmAAKCRCJp1EFxbsS RKEuAQCpRF+ifclSitwzKYEUX0OY+ZqBcP+L2wqQRkjqbicv7gD+OcE5BhoctdP1 sXUaoZRHHeQ+Pz5kjS2ppSmrG2tT8AQ= =t3Sk -----END PGP SIGNATURE----- Merge tag 'dma-mapping-7.2-2026-06-16' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux Pull dma-mapping updates from Marek Szyprowski: - added checks for DMA attributes in the debug code, especially to ensure that mappings are created and released with matching attributes (Leon Romanovsky) - better default configuration for CMA on NUMA machines (Feng Tang) - code cleanup in dma benchmark tool (Rosen Penev) * tag 'dma-mapping-7.2-2026-06-16' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux: dma: map_benchmark: turn dma_sg_map_param buf into a flexible array dma-contiguous: simplify numa cma area handling dma-contiguous: add kconfig option to setup numa cma area if not configured explicitly dma-debug: Ensure mappings are created and released with matching attributes dma-debug: Feed DMA attribute for unmapping flows too dma-debug: Record DMA attributes in debug entry dma-debug: Remove unused DMA attribute parameter ntb: Use consistent DMA attributes when freeing DMA mappings ntb: Store original DMA address for future release
This commit is contained in:
commit
4cc14386e3
|
|
@ -872,6 +872,10 @@ Kernel parameters
|
|||
contiguous memory allocations. It will reserve CMA
|
||||
area for the specified node.
|
||||
|
||||
If it is setup together with upper 'cmd_pernuma='
|
||||
(unlikely), its size setting takes priority for the
|
||||
specified numa nodes.
|
||||
|
||||
With numa CMA enabled, DMA users on node nid will
|
||||
first try to allocate buffer from the numa area
|
||||
which is located in node nid, if the allocation fails,
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ struct ntb_transport_mw {
|
|||
void *alloc_addr;
|
||||
void *virt_addr;
|
||||
dma_addr_t dma_addr;
|
||||
dma_addr_t original_dma_addr;
|
||||
};
|
||||
|
||||
struct ntb_transport_client_dev {
|
||||
|
|
@ -765,8 +766,8 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
|
|||
return;
|
||||
|
||||
ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
|
||||
dma_free_coherent(dma_dev, mw->alloc_size,
|
||||
mw->alloc_addr, mw->dma_addr);
|
||||
dma_free_attrs(dma_dev, mw->alloc_size, mw->alloc_addr,
|
||||
mw->original_dma_addr, DMA_ATTR_FORCE_CONTIGUOUS);
|
||||
mw->xlat_size = 0;
|
||||
mw->buff_size = 0;
|
||||
mw->alloc_size = 0;
|
||||
|
|
@ -802,6 +803,7 @@ static int ntb_alloc_mw_buffer(struct ntb_transport_mw *mw,
|
|||
return -ENOMEM;
|
||||
}
|
||||
virt_addr = alloc_addr;
|
||||
mw->original_dma_addr = dma_addr;
|
||||
|
||||
/*
|
||||
* we must ensure that the memory address allocated is BAR size
|
||||
|
|
@ -826,8 +828,8 @@ static int ntb_alloc_mw_buffer(struct ntb_transport_mw *mw,
|
|||
return 0;
|
||||
|
||||
err:
|
||||
dma_free_coherent(ntb_dev, mw->alloc_size, alloc_addr, dma_addr);
|
||||
|
||||
dma_free_attrs(ntb_dev, mw->alloc_size, alloc_addr, dma_addr,
|
||||
DMA_ATTR_FORCE_CONTIGUOUS);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:"
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
/* per-node numa setting has the priority */
|
||||
size = numa_cma_size[nid] ?: pernuma_size_bytes;
|
||||
if (!size)
|
||||
continue;
|
||||
|
||||
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]) {
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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,6 +1280,7 @@ 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);
|
||||
|
|
@ -1265,7 +1296,7 @@ void debug_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
|
|||
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)
|
||||
|
|
@ -1306,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,
|
||||
|
|
@ -1315,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()))
|
||||
|
|
@ -1352,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1379,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;
|
||||
|
|
@ -1397,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)
|
||||
|
|
@ -1447,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,
|
||||
|
|
@ -1460,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 */
|
||||
|
|
@ -1574,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;
|
||||
|
||||
|
|
@ -1593,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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(¶ms->sgt, params->npages, GFP_KERNEL))
|
||||
goto free_buf;
|
||||
goto free_params;
|
||||
|
||||
for_each_sgtable_sg(¶ms->sgt, sg, i) {
|
||||
params->buf[i] = (void *)__get_free_page(GFP_KERNEL);
|
||||
|
|
@ -166,9 +166,7 @@ static void *dma_sg_map_benchmark_prepare(struct map_benchmark_data *map)
|
|||
free_page((unsigned long)params->buf[i]);
|
||||
|
||||
sg_free_table(¶ms->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(¶ms->sgt);
|
||||
|
||||
kfree(params->buf);
|
||||
kfree(params);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -223,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);
|
||||
|
||||
|
|
@ -349,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);
|
||||
|
|
@ -687,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))
|
||||
|
|
@ -727,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);
|
||||
}
|
||||
|
|
@ -834,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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user