Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux; tag 'dma-mapping-5.5' of git://git.infradead.org/users/hch/dma-mapping
Pull dma-mapping updates from Christoph Hellwig: - improve dma-debug scalability (Eric Dumazet) - tiny dma-debug cleanup (Dan Carpenter) - check for vmap memory in dma_map_single (Kees Cook) - check for dma_addr_t overflows in dma-direct when using DMA offsets (Nicolas Saenz Julienne) - switch the x86 sta2x11 SOC to use more generic DMA code (Nicolas Saenz Julienne) - fix arm-nommu dma-ranges handling (Vladimir Murzin) - use __initdata in CMA (Shyam Saini) - replace the bus dma mask with a limit (Nicolas Saenz Julienne) - merge the remapping helpers into the main dma-direct flow (me) - switch xtensa to the generic dma remap handling (me) - various cleanups around dma_capable (me) - remove unused dev arguments to various dma-noncoherent helpers (me) * 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux: * tag 'dma-mapping-5.5' of git://git.infradead.org/users/hch/dma-mapping: (22 commits) dma-mapping: treat dev->bus_dma_mask as a DMA limit dma-direct: exclude dma_direct_map_resource from the min_low_pfn check dma-direct: don't check swiotlb=force in dma_direct_map_resource dma-debug: clean up put_hash_bucket() powerpc: remove support for NULL dev in __phys_to_dma / __dma_to_phys dma-direct: avoid a forward declaration for phys_to_dma dma-direct: unify the dma_capable definitions dma-mapping: drop the dev argument to arch_sync_dma_for_* x86/PCI: sta2x11: use default DMA address translation dma-direct: check for overflows on 32 bit DMA addresses dma-debug: increase HASH_SIZE dma-debug: reorder struct dma_debug_entry fields xtensa: use the generic uncached segment support dma-mapping: merge the generic remapping helpers into dma-direct dma-direct: provide mmap and get_sgtable method overrides dma-direct: remove the dma_handle argument to __dma_direct_alloc_pages dma-direct: remove __dma_direct_free_pages usb: core: Remove redundant vmap checks kernel: dma-contiguous: mark CMA parameters __initdata/__initconst dma-debug: add a schedule point in debug_dma_dump_mappings() ...
This commit is contained in:
@@ -51,9 +51,6 @@ config ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
|
||||
config ARCH_HAS_DMA_PREP_COHERENT
|
||||
bool
|
||||
|
||||
config ARCH_HAS_DMA_COHERENT_TO_PFN
|
||||
bool
|
||||
|
||||
config ARCH_HAS_FORCE_DMA_UNENCRYPTED
|
||||
bool
|
||||
|
||||
@@ -68,9 +65,18 @@ config SWIOTLB
|
||||
bool
|
||||
select NEED_DMA_MAP_STATE
|
||||
|
||||
#
|
||||
# Should be selected if we can mmap non-coherent mappings to userspace.
|
||||
# The only thing that is really required is a way to set an uncached bit
|
||||
# in the pagetables
|
||||
#
|
||||
config DMA_NONCOHERENT_MMAP
|
||||
bool
|
||||
|
||||
config DMA_REMAP
|
||||
depends on MMU
|
||||
select GENERIC_ALLOCATOR
|
||||
select DMA_NONCOHERENT_MMAP
|
||||
bool
|
||||
|
||||
config DMA_DIRECT_REMAP
|
||||
|
@@ -123,8 +123,9 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem,
|
||||
ssize_t size, dma_addr_t *dma_handle)
|
||||
static void *__dma_alloc_from_coherent(struct device *dev,
|
||||
struct dma_coherent_mem *mem,
|
||||
ssize_t size, dma_addr_t *dma_handle)
|
||||
{
|
||||
int order = get_order(size);
|
||||
unsigned long flags;
|
||||
@@ -143,7 +144,7 @@ static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem,
|
||||
/*
|
||||
* Memory was found in the coherent area.
|
||||
*/
|
||||
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
|
||||
*dma_handle = dma_get_device_base(dev, mem) + (pageno << PAGE_SHIFT);
|
||||
ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
||||
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||
memset(ret, 0, size);
|
||||
@@ -175,17 +176,18 @@ int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
|
||||
if (!mem)
|
||||
return 0;
|
||||
|
||||
*ret = __dma_alloc_from_coherent(mem, size, dma_handle);
|
||||
*ret = __dma_alloc_from_coherent(dev, mem, size, dma_handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *dma_alloc_from_global_coherent(ssize_t size, dma_addr_t *dma_handle)
|
||||
void *dma_alloc_from_global_coherent(struct device *dev, ssize_t size,
|
||||
dma_addr_t *dma_handle)
|
||||
{
|
||||
if (!dma_coherent_default_memory)
|
||||
return NULL;
|
||||
|
||||
return __dma_alloc_from_coherent(dma_coherent_default_memory, size,
|
||||
dma_handle);
|
||||
return __dma_alloc_from_coherent(dev, dma_coherent_default_memory, size,
|
||||
dma_handle);
|
||||
}
|
||||
|
||||
static int __dma_release_from_coherent(struct dma_coherent_mem *mem,
|
||||
|
@@ -42,10 +42,11 @@ struct cma *dma_contiguous_default_area;
|
||||
* Users, who want to set the size of global CMA area for their system
|
||||
* should use cma= kernel parameter.
|
||||
*/
|
||||
static const phys_addr_t size_bytes = (phys_addr_t)CMA_SIZE_MBYTES * SZ_1M;
|
||||
static phys_addr_t size_cmdline = -1;
|
||||
static phys_addr_t base_cmdline;
|
||||
static phys_addr_t limit_cmdline;
|
||||
static const phys_addr_t size_bytes __initconst =
|
||||
(phys_addr_t)CMA_SIZE_MBYTES * SZ_1M;
|
||||
static phys_addr_t size_cmdline __initdata = -1;
|
||||
static phys_addr_t base_cmdline __initdata;
|
||||
static phys_addr_t limit_cmdline __initdata;
|
||||
|
||||
static int __init early_cma(char *p)
|
||||
{
|
||||
|
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <asm/sections.h>
|
||||
|
||||
#define HASH_SIZE 1024ULL
|
||||
#define HASH_SIZE 16384ULL
|
||||
#define HASH_FN_SHIFT 13
|
||||
#define HASH_FN_MASK (HASH_SIZE - 1)
|
||||
|
||||
@@ -54,40 +54,40 @@ enum map_err_types {
|
||||
* struct dma_debug_entry - track a dma_map* or dma_alloc_coherent mapping
|
||||
* @list: node on pre-allocated free_entries list
|
||||
* @dev: 'dev' argument to dma_map_{page|single|sg} or dma_alloc_coherent
|
||||
* @type: single, page, sg, coherent
|
||||
* @pfn: page frame of the start address
|
||||
* @offset: offset of mapping relative to pfn
|
||||
* @size: length of the mapping
|
||||
* @type: single, page, sg, coherent
|
||||
* @direction: enum dma_data_direction
|
||||
* @sg_call_ents: 'nents' from dma_map_sg
|
||||
* @sg_mapped_ents: 'mapped_ents' from dma_map_sg
|
||||
* @pfn: page frame of the start address
|
||||
* @offset: offset of mapping relative to pfn
|
||||
* @map_err_type: track whether dma_mapping_error() was checked
|
||||
* @stacktrace: support backtraces when a violation is detected
|
||||
*/
|
||||
struct dma_debug_entry {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
int type;
|
||||
unsigned long pfn;
|
||||
size_t offset;
|
||||
u64 dev_addr;
|
||||
u64 size;
|
||||
int type;
|
||||
int direction;
|
||||
int sg_call_ents;
|
||||
int sg_mapped_ents;
|
||||
unsigned long pfn;
|
||||
size_t offset;
|
||||
enum map_err_types map_err_type;
|
||||
#ifdef CONFIG_STACKTRACE
|
||||
unsigned int stack_len;
|
||||
unsigned long stack_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
|
||||
#endif
|
||||
};
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
typedef bool (*match_fn)(struct dma_debug_entry *, struct dma_debug_entry *);
|
||||
|
||||
struct hash_bucket {
|
||||
struct list_head list;
|
||||
spinlock_t lock;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
};
|
||||
|
||||
/* Hash list to save the allocated dma addresses */
|
||||
static struct hash_bucket dma_entry_hash[HASH_SIZE];
|
||||
@@ -255,12 +255,10 @@ static struct hash_bucket *get_hash_bucket(struct dma_debug_entry *entry,
|
||||
* Give up exclusive access to the hash bucket
|
||||
*/
|
||||
static void put_hash_bucket(struct hash_bucket *bucket,
|
||||
unsigned long *flags)
|
||||
unsigned long flags)
|
||||
__releases(&bucket->lock)
|
||||
{
|
||||
unsigned long __flags = *flags;
|
||||
|
||||
spin_unlock_irqrestore(&bucket->lock, __flags);
|
||||
spin_unlock_irqrestore(&bucket->lock, flags);
|
||||
}
|
||||
|
||||
static bool exact_match(struct dma_debug_entry *a, struct dma_debug_entry *b)
|
||||
@@ -359,7 +357,7 @@ static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
|
||||
/*
|
||||
* Nothing found, go back a hash bucket
|
||||
*/
|
||||
put_hash_bucket(*bucket, flags);
|
||||
put_hash_bucket(*bucket, *flags);
|
||||
range += (1 << HASH_FN_SHIFT);
|
||||
index.dev_addr -= (1 << HASH_FN_SHIFT);
|
||||
*bucket = get_hash_bucket(&index, flags);
|
||||
@@ -420,6 +418,7 @@ void debug_dma_dump_mappings(struct device *dev)
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&bucket->lock, flags);
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,7 +607,7 @@ static void add_dma_entry(struct dma_debug_entry *entry)
|
||||
|
||||
bucket = get_hash_bucket(entry, &flags);
|
||||
hash_bucket_add(bucket, entry);
|
||||
put_hash_bucket(bucket, &flags);
|
||||
put_hash_bucket(bucket, flags);
|
||||
|
||||
rc = active_cacheline_insert(entry);
|
||||
if (rc == -ENOMEM) {
|
||||
@@ -1001,7 +1000,7 @@ static void check_unmap(struct dma_debug_entry *ref)
|
||||
|
||||
if (!entry) {
|
||||
/* must drop lock before calling dma_mapping_error */
|
||||
put_hash_bucket(bucket, &flags);
|
||||
put_hash_bucket(bucket, flags);
|
||||
|
||||
if (dma_mapping_error(ref->dev, ref->dev_addr)) {
|
||||
err_printk(ref->dev, NULL,
|
||||
@@ -1083,7 +1082,7 @@ static void check_unmap(struct dma_debug_entry *ref)
|
||||
hash_bucket_del(entry);
|
||||
dma_entry_free(entry);
|
||||
|
||||
put_hash_bucket(bucket, &flags);
|
||||
put_hash_bucket(bucket, flags);
|
||||
}
|
||||
|
||||
static void check_for_stack(struct device *dev,
|
||||
@@ -1203,7 +1202,7 @@ static void check_sync(struct device *dev,
|
||||
}
|
||||
|
||||
out:
|
||||
put_hash_bucket(bucket, &flags);
|
||||
put_hash_bucket(bucket, flags);
|
||||
}
|
||||
|
||||
static void check_sg_segment(struct device *dev, struct scatterlist *sg)
|
||||
@@ -1318,7 +1317,7 @@ void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
|
||||
}
|
||||
}
|
||||
|
||||
put_hash_bucket(bucket, &flags);
|
||||
put_hash_bucket(bucket, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(debug_dma_mapping_error);
|
||||
|
||||
@@ -1391,7 +1390,7 @@ static int get_nr_mapped_entries(struct device *dev,
|
||||
|
||||
if (entry)
|
||||
mapped_ents = entry->sg_mapped_ents;
|
||||
put_hash_bucket(bucket, &flags);
|
||||
put_hash_bucket(bucket, flags);
|
||||
|
||||
return mapped_ents;
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <linux/dma-contiguous.h>
|
||||
#include <linux/dma-noncoherent.h>
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <linux/swiotlb.h>
|
||||
|
||||
@@ -26,10 +27,10 @@ static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size)
|
||||
{
|
||||
if (!dev->dma_mask) {
|
||||
dev_err_once(dev, "DMA map on device without dma_mask\n");
|
||||
} else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_mask) {
|
||||
} else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_limit) {
|
||||
dev_err_once(dev,
|
||||
"overflow %pad+%zu of DMA mask %llx bus mask %llx\n",
|
||||
&dma_addr, size, *dev->dma_mask, dev->bus_dma_mask);
|
||||
"overflow %pad+%zu of DMA mask %llx bus limit %llx\n",
|
||||
&dma_addr, size, *dev->dma_mask, dev->bus_dma_limit);
|
||||
}
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
@@ -42,6 +43,12 @@ static inline dma_addr_t phys_to_dma_direct(struct device *dev,
|
||||
return phys_to_dma(dev, phys);
|
||||
}
|
||||
|
||||
static inline struct page *dma_direct_to_page(struct device *dev,
|
||||
dma_addr_t dma_addr)
|
||||
{
|
||||
return pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_addr)));
|
||||
}
|
||||
|
||||
u64 dma_direct_get_required_mask(struct device *dev)
|
||||
{
|
||||
u64 max_dma = phys_to_dma_direct(dev, (max_pfn - 1) << PAGE_SHIFT);
|
||||
@@ -50,15 +57,14 @@ u64 dma_direct_get_required_mask(struct device *dev)
|
||||
}
|
||||
|
||||
static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
|
||||
u64 *phys_mask)
|
||||
u64 *phys_limit)
|
||||
{
|
||||
if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask)
|
||||
dma_mask = dev->bus_dma_mask;
|
||||
u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit);
|
||||
|
||||
if (force_dma_unencrypted(dev))
|
||||
*phys_mask = __dma_to_phys(dev, dma_mask);
|
||||
*phys_limit = __dma_to_phys(dev, dma_limit);
|
||||
else
|
||||
*phys_mask = dma_to_phys(dev, dma_mask);
|
||||
*phys_limit = dma_to_phys(dev, dma_limit);
|
||||
|
||||
/*
|
||||
* Optimistically try the zone that the physical address mask falls
|
||||
@@ -68,9 +74,9 @@ static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
|
||||
* Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding
|
||||
* zones.
|
||||
*/
|
||||
if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits))
|
||||
if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits))
|
||||
return GFP_DMA;
|
||||
if (*phys_mask <= DMA_BIT_MASK(32))
|
||||
if (*phys_limit <= DMA_BIT_MASK(32))
|
||||
return GFP_DMA32;
|
||||
return 0;
|
||||
}
|
||||
@@ -78,16 +84,16 @@ static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
|
||||
static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
|
||||
{
|
||||
return phys_to_dma_direct(dev, phys) + size - 1 <=
|
||||
min_not_zero(dev->coherent_dma_mask, dev->bus_dma_mask);
|
||||
min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit);
|
||||
}
|
||||
|
||||
struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
|
||||
gfp_t gfp, unsigned long attrs)
|
||||
{
|
||||
size_t alloc_size = PAGE_ALIGN(size);
|
||||
int node = dev_to_node(dev);
|
||||
struct page *page = NULL;
|
||||
u64 phys_mask;
|
||||
u64 phys_limit;
|
||||
|
||||
if (attrs & DMA_ATTR_NO_WARN)
|
||||
gfp |= __GFP_NOWARN;
|
||||
@@ -95,7 +101,7 @@ struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
|
||||
/* we always manually zero the memory once we are done: */
|
||||
gfp &= ~__GFP_ZERO;
|
||||
gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
|
||||
&phys_mask);
|
||||
&phys_limit);
|
||||
page = dma_alloc_contiguous(dev, alloc_size, gfp);
|
||||
if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
|
||||
dma_free_contiguous(dev, page, alloc_size);
|
||||
@@ -109,7 +115,7 @@ again:
|
||||
page = NULL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
|
||||
phys_mask < DMA_BIT_MASK(64) &&
|
||||
phys_limit < DMA_BIT_MASK(64) &&
|
||||
!(gfp & (GFP_DMA32 | GFP_DMA))) {
|
||||
gfp |= GFP_DMA32;
|
||||
goto again;
|
||||
@@ -130,7 +136,16 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
|
||||
struct page *page;
|
||||
void *ret;
|
||||
|
||||
page = __dma_direct_alloc_pages(dev, size, dma_handle, gfp, attrs);
|
||||
if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
|
||||
dma_alloc_need_uncached(dev, attrs) &&
|
||||
!gfpflags_allow_blocking(gfp)) {
|
||||
ret = dma_alloc_from_pool(PAGE_ALIGN(size), &page, gfp);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
page = __dma_direct_alloc_pages(dev, size, gfp, attrs);
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
@@ -139,9 +154,28 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
|
||||
/* remove any dirty cache lines on the kernel alias */
|
||||
if (!PageHighMem(page))
|
||||
arch_dma_prep_coherent(page, size);
|
||||
*dma_handle = phys_to_dma(dev, page_to_phys(page));
|
||||
/* return the page pointer as the opaque cookie */
|
||||
return page;
|
||||
ret = page;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
|
||||
dma_alloc_need_uncached(dev, attrs)) ||
|
||||
(IS_ENABLED(CONFIG_DMA_REMAP) && PageHighMem(page))) {
|
||||
/* remove any dirty cache lines on the kernel alias */
|
||||
arch_dma_prep_coherent(page, PAGE_ALIGN(size));
|
||||
|
||||
/* create a coherent mapping */
|
||||
ret = dma_common_contiguous_remap(page, PAGE_ALIGN(size),
|
||||
dma_pgprot(dev, PAGE_KERNEL, attrs),
|
||||
__builtin_return_address(0));
|
||||
if (!ret) {
|
||||
dma_free_contiguous(dev, page, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(ret, 0, size);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (PageHighMem(page)) {
|
||||
@@ -152,17 +186,14 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
|
||||
* so log an error and fail.
|
||||
*/
|
||||
dev_info(dev, "Rejecting highmem page from CMA.\n");
|
||||
__dma_direct_free_pages(dev, size, page);
|
||||
dma_free_contiguous(dev, page, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = page_address(page);
|
||||
if (force_dma_unencrypted(dev)) {
|
||||
if (force_dma_unencrypted(dev))
|
||||
set_memory_decrypted((unsigned long)ret, 1 << get_order(size));
|
||||
*dma_handle = __phys_to_dma(dev, page_to_phys(page));
|
||||
} else {
|
||||
*dma_handle = phys_to_dma(dev, page_to_phys(page));
|
||||
}
|
||||
|
||||
memset(ret, 0, size);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
|
||||
@@ -170,15 +201,14 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
|
||||
arch_dma_prep_coherent(page, size);
|
||||
ret = uncached_kernel_address(ret);
|
||||
}
|
||||
|
||||
done:
|
||||
if (force_dma_unencrypted(dev))
|
||||
*dma_handle = __phys_to_dma(dev, page_to_phys(page));
|
||||
else
|
||||
*dma_handle = phys_to_dma(dev, page_to_phys(page));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __dma_direct_free_pages(struct device *dev, size_t size, struct page *page)
|
||||
{
|
||||
dma_free_contiguous(dev, page, size);
|
||||
}
|
||||
|
||||
void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t dma_addr, unsigned long attrs)
|
||||
{
|
||||
@@ -187,23 +217,28 @@ void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr,
|
||||
if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) &&
|
||||
!force_dma_unencrypted(dev)) {
|
||||
/* cpu_addr is a struct page cookie, not a kernel address */
|
||||
__dma_direct_free_pages(dev, size, cpu_addr);
|
||||
dma_free_contiguous(dev, cpu_addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
|
||||
dma_free_from_pool(cpu_addr, PAGE_ALIGN(size)))
|
||||
return;
|
||||
|
||||
if (force_dma_unencrypted(dev))
|
||||
set_memory_encrypted((unsigned long)cpu_addr, 1 << page_order);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
|
||||
dma_alloc_need_uncached(dev, attrs))
|
||||
cpu_addr = cached_kernel_address(cpu_addr);
|
||||
__dma_direct_free_pages(dev, size, virt_to_page(cpu_addr));
|
||||
if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr))
|
||||
vunmap(cpu_addr);
|
||||
|
||||
dma_free_contiguous(dev, dma_direct_to_page(dev, dma_addr), size);
|
||||
}
|
||||
|
||||
void *dma_direct_alloc(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
|
||||
!IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
|
||||
dma_alloc_need_uncached(dev, attrs))
|
||||
return arch_dma_alloc(dev, size, dma_handle, gfp, attrs);
|
||||
return dma_direct_alloc_pages(dev, size, dma_handle, gfp, attrs);
|
||||
@@ -213,6 +248,7 @@ void dma_direct_free(struct device *dev, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_addr, unsigned long attrs)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
|
||||
!IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
|
||||
dma_alloc_need_uncached(dev, attrs))
|
||||
arch_dma_free(dev, size, cpu_addr, dma_addr, attrs);
|
||||
else
|
||||
@@ -230,7 +266,7 @@ void dma_direct_sync_single_for_device(struct device *dev,
|
||||
swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_DEVICE);
|
||||
|
||||
if (!dev_is_dma_coherent(dev))
|
||||
arch_sync_dma_for_device(dev, paddr, size, dir);
|
||||
arch_sync_dma_for_device(paddr, size, dir);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_direct_sync_single_for_device);
|
||||
|
||||
@@ -248,7 +284,7 @@ void dma_direct_sync_sg_for_device(struct device *dev,
|
||||
dir, SYNC_FOR_DEVICE);
|
||||
|
||||
if (!dev_is_dma_coherent(dev))
|
||||
arch_sync_dma_for_device(dev, paddr, sg->length,
|
||||
arch_sync_dma_for_device(paddr, sg->length,
|
||||
dir);
|
||||
}
|
||||
}
|
||||
@@ -264,8 +300,8 @@ void dma_direct_sync_single_for_cpu(struct device *dev,
|
||||
phys_addr_t paddr = dma_to_phys(dev, addr);
|
||||
|
||||
if (!dev_is_dma_coherent(dev)) {
|
||||
arch_sync_dma_for_cpu(dev, paddr, size, dir);
|
||||
arch_sync_dma_for_cpu_all(dev);
|
||||
arch_sync_dma_for_cpu(paddr, size, dir);
|
||||
arch_sync_dma_for_cpu_all();
|
||||
}
|
||||
|
||||
if (unlikely(is_swiotlb_buffer(paddr)))
|
||||
@@ -283,7 +319,7 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
|
||||
phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
|
||||
|
||||
if (!dev_is_dma_coherent(dev))
|
||||
arch_sync_dma_for_cpu(dev, paddr, sg->length, dir);
|
||||
arch_sync_dma_for_cpu(paddr, sg->length, dir);
|
||||
|
||||
if (unlikely(is_swiotlb_buffer(paddr)))
|
||||
swiotlb_tbl_sync_single(dev, paddr, sg->length, dir,
|
||||
@@ -291,7 +327,7 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
|
||||
}
|
||||
|
||||
if (!dev_is_dma_coherent(dev))
|
||||
arch_sync_dma_for_cpu_all(dev);
|
||||
arch_sync_dma_for_cpu_all();
|
||||
}
|
||||
EXPORT_SYMBOL(dma_direct_sync_sg_for_cpu);
|
||||
|
||||
@@ -325,7 +361,7 @@ static inline bool dma_direct_possible(struct device *dev, dma_addr_t dma_addr,
|
||||
size_t size)
|
||||
{
|
||||
return swiotlb_force != SWIOTLB_FORCE &&
|
||||
dma_capable(dev, dma_addr, size);
|
||||
dma_capable(dev, dma_addr, size, true);
|
||||
}
|
||||
|
||||
dma_addr_t dma_direct_map_page(struct device *dev, struct page *page,
|
||||
@@ -342,7 +378,7 @@ dma_addr_t dma_direct_map_page(struct device *dev, struct page *page,
|
||||
}
|
||||
|
||||
if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
||||
arch_sync_dma_for_device(dev, phys, size, dir);
|
||||
arch_sync_dma_for_device(phys, size, dir);
|
||||
return dma_addr;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_direct_map_page);
|
||||
@@ -374,7 +410,7 @@ dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr,
|
||||
{
|
||||
dma_addr_t dma_addr = paddr;
|
||||
|
||||
if (unlikely(!dma_direct_possible(dev, dma_addr, size))) {
|
||||
if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
|
||||
report_addr(dev, dma_addr, size);
|
||||
return DMA_MAPPING_ERROR;
|
||||
}
|
||||
@@ -383,6 +419,59 @@ dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr,
|
||||
}
|
||||
EXPORT_SYMBOL(dma_direct_map_resource);
|
||||
|
||||
int dma_direct_get_sgtable(struct device *dev, struct sg_table *sgt,
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct page *page = dma_direct_to_page(dev, dma_addr);
|
||||
int ret;
|
||||
|
||||
ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
|
||||
if (!ret)
|
||||
sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
bool dma_direct_can_mmap(struct device *dev)
|
||||
{
|
||||
return dev_is_dma_coherent(dev) ||
|
||||
IS_ENABLED(CONFIG_DMA_NONCOHERENT_MMAP);
|
||||
}
|
||||
|
||||
int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
unsigned long user_count = vma_pages(vma);
|
||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
unsigned long pfn = PHYS_PFN(dma_to_phys(dev, dma_addr));
|
||||
int ret = -ENXIO;
|
||||
|
||||
vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
|
||||
|
||||
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
|
||||
return ret;
|
||||
|
||||
if (vma->vm_pgoff >= count || user_count > count - vma->vm_pgoff)
|
||||
return -ENXIO;
|
||||
return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
|
||||
user_count << PAGE_SHIFT, vma->vm_page_prot);
|
||||
}
|
||||
#else /* CONFIG_MMU */
|
||||
bool dma_direct_can_mmap(struct device *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
/*
|
||||
* Because 32-bit DMA masks are so common we expect every architecture to be
|
||||
* able to satisfy them - either by not supporting more physical memory, or by
|
||||
|
@@ -112,24 +112,9 @@ int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct page *page;
|
||||
struct page *page = virt_to_page(cpu_addr);
|
||||
int ret;
|
||||
|
||||
if (!dev_is_dma_coherent(dev)) {
|
||||
unsigned long pfn;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN))
|
||||
return -ENXIO;
|
||||
|
||||
/* If the PFN is not valid, we do not have a struct page */
|
||||
pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr);
|
||||
if (!pfn_valid(pfn))
|
||||
return -ENXIO;
|
||||
page = pfn_to_page(pfn);
|
||||
} else {
|
||||
page = virt_to_page(cpu_addr);
|
||||
}
|
||||
|
||||
ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
|
||||
if (!ret)
|
||||
sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
|
||||
@@ -154,7 +139,7 @@ int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt,
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
|
||||
if (dma_is_direct(ops))
|
||||
return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr,
|
||||
return dma_direct_get_sgtable(dev, sgt, cpu_addr, dma_addr,
|
||||
size, attrs);
|
||||
if (!ops->get_sgtable)
|
||||
return -ENXIO;
|
||||
@@ -192,7 +177,6 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
unsigned long user_count = vma_pages(vma);
|
||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
unsigned long off = vma->vm_pgoff;
|
||||
unsigned long pfn;
|
||||
int ret = -ENXIO;
|
||||
|
||||
vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
|
||||
@@ -203,19 +187,8 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
if (off >= count || user_count > count - off)
|
||||
return -ENXIO;
|
||||
|
||||
if (!dev_is_dma_coherent(dev)) {
|
||||
if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN))
|
||||
return -ENXIO;
|
||||
|
||||
/* If the PFN is not valid, we do not have a struct page */
|
||||
pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr);
|
||||
if (!pfn_valid(pfn))
|
||||
return -ENXIO;
|
||||
} else {
|
||||
pfn = page_to_pfn(virt_to_page(cpu_addr));
|
||||
}
|
||||
|
||||
return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
|
||||
return remap_pfn_range(vma, vma->vm_start,
|
||||
page_to_pfn(virt_to_page(cpu_addr)) + vma->vm_pgoff,
|
||||
user_count << PAGE_SHIFT, vma->vm_page_prot);
|
||||
#else
|
||||
return -ENXIO;
|
||||
@@ -233,12 +206,8 @@ bool dma_can_mmap(struct device *dev)
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
|
||||
if (dma_is_direct(ops)) {
|
||||
return IS_ENABLED(CONFIG_MMU) &&
|
||||
(dev_is_dma_coherent(dev) ||
|
||||
IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN));
|
||||
}
|
||||
|
||||
if (dma_is_direct(ops))
|
||||
return dma_direct_can_mmap(dev);
|
||||
return ops->mmap != NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_can_mmap);
|
||||
@@ -263,7 +232,7 @@ int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
|
||||
if (dma_is_direct(ops))
|
||||
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size,
|
||||
return dma_direct_mmap(dev, vma, cpu_addr, dma_addr, size,
|
||||
attrs);
|
||||
if (!ops->mmap)
|
||||
return -ENXIO;
|
||||
|
@@ -210,59 +210,4 @@ bool dma_free_from_pool(void *start, size_t size)
|
||||
gen_pool_free(atomic_pool, (unsigned long)start, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
|
||||
gfp_t flags, unsigned long attrs)
|
||||
{
|
||||
struct page *page = NULL;
|
||||
void *ret;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
if (!gfpflags_allow_blocking(flags)) {
|
||||
ret = dma_alloc_from_pool(size, &page, flags);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
page = __dma_direct_alloc_pages(dev, size, dma_handle, flags, attrs);
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
/* remove any dirty cache lines on the kernel alias */
|
||||
arch_dma_prep_coherent(page, size);
|
||||
|
||||
/* create a coherent mapping */
|
||||
ret = dma_common_contiguous_remap(page, size,
|
||||
dma_pgprot(dev, PAGE_KERNEL, attrs),
|
||||
__builtin_return_address(0));
|
||||
if (!ret) {
|
||||
__dma_direct_free_pages(dev, size, page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(ret, 0, size);
|
||||
done:
|
||||
*dma_handle = phys_to_dma(dev, page_to_phys(page));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void arch_dma_free(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, unsigned long attrs)
|
||||
{
|
||||
if (!dma_free_from_pool(vaddr, PAGE_ALIGN(size))) {
|
||||
phys_addr_t phys = dma_to_phys(dev, dma_handle);
|
||||
struct page *page = pfn_to_page(__phys_to_pfn(phys));
|
||||
|
||||
vunmap(vaddr);
|
||||
__dma_direct_free_pages(dev, size, page);
|
||||
}
|
||||
}
|
||||
|
||||
long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
|
||||
dma_addr_t dma_addr)
|
||||
{
|
||||
return __phys_to_pfn(dma_to_phys(dev, dma_addr));
|
||||
}
|
||||
#endif /* CONFIG_DMA_DIRECT_REMAP */
|
||||
|
@@ -678,7 +678,7 @@ bool swiotlb_map(struct device *dev, phys_addr_t *phys, dma_addr_t *dma_addr,
|
||||
|
||||
/* Ensure that the address returned is DMA'ble */
|
||||
*dma_addr = __phys_to_dma(dev, *phys);
|
||||
if (unlikely(!dma_capable(dev, *dma_addr, size))) {
|
||||
if (unlikely(!dma_capable(dev, *dma_addr, size, true))) {
|
||||
swiotlb_tbl_unmap_single(dev, *phys, size, size, dir,
|
||||
attrs | DMA_ATTR_SKIP_CPU_SYNC);
|
||||
return false;
|
||||
|
Reference in New Issue
Block a user