mirror of
https://github.com/torvalds/linux
synced 2024-09-06 18:01:05 +00:00
dma-mapping: consolidate the dma mmap implementations
The only functional differences (modulo a few missing fixes in the arch code) is that architectures without coherent caches need a hook to convert a virtual or dma address into a pfn, given that we don't have the kernel linear mapping available for the otherwise easy virt_to_page call. As a side effect we can support mmap of the per-device coherent area even on architectures not providing the callback, and we make previous dangerous default methods dma_common_mmap actually save for non-coherent architectures by rejecting it without the right helper. In addition to that we need a hook so that some architectures can override the protection bits when mmaping a dma coherent allocations. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Paul Burton <paul.burton@mips.com> # MIPS parts
This commit is contained in:
parent
bc3ec75de5
commit
58b0440663
|
@ -9,6 +9,7 @@
|
||||||
config ARC
|
config ARC
|
||||||
def_bool y
|
def_bool y
|
||||||
select ARC_TIMERS
|
select ARC_TIMERS
|
||||||
|
select ARCH_HAS_DMA_COHERENT_TO_PFN
|
||||||
select ARCH_HAS_PTE_SPECIAL
|
select ARCH_HAS_PTE_SPECIAL
|
||||||
select ARCH_HAS_SYNC_DMA_FOR_CPU
|
select ARCH_HAS_SYNC_DMA_FOR_CPU
|
||||||
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
|
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
|
||||||
|
@ -18,7 +19,6 @@ config ARC
|
||||||
select CLONE_BACKWARDS
|
select CLONE_BACKWARDS
|
||||||
select COMMON_CLK
|
select COMMON_CLK
|
||||||
select DMA_DIRECT_OPS
|
select DMA_DIRECT_OPS
|
||||||
select DMA_NONCOHERENT_MMAP
|
|
||||||
select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC)
|
select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC)
|
||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select GENERIC_FIND_FIRST_BIT
|
select GENERIC_FIND_FIRST_BIT
|
||||||
|
|
|
@ -84,29 +84,10 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
|
||||||
__free_pages(page, get_order(size));
|
__free_pages(page, get_order(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
|
||||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
dma_addr_t dma_addr)
|
||||||
unsigned long attrs)
|
|
||||||
{
|
{
|
||||||
unsigned long user_count = vma_pages(vma);
|
return __phys_to_pfn(dma_addr);
|
||||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
|
||||||
unsigned long pfn = __phys_to_pfn(dma_addr);
|
|
||||||
unsigned long off = vma->vm_pgoff;
|
|
||||||
int ret = -ENXIO;
|
|
||||||
|
|
||||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
|
||||||
|
|
||||||
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (off < count && user_count <= (count - off)) {
|
|
||||||
ret = remap_pfn_range(vma, vma->vm_start,
|
|
||||||
pfn + off,
|
|
||||||
user_count << PAGE_SHIFT,
|
|
||||||
vma->vm_page_prot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -91,7 +91,7 @@ static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||||
if (dma_mmap_from_global_coherent(vma, cpu_addr, size, &ret))
|
if (dma_mmap_from_global_coherent(vma, cpu_addr, size, &ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
|
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
config MICROBLAZE
|
config MICROBLAZE
|
||||||
def_bool y
|
def_bool y
|
||||||
select ARCH_NO_SWAP
|
select ARCH_NO_SWAP
|
||||||
|
select ARCH_HAS_DMA_COHERENT_TO_PFN if MMU
|
||||||
select ARCH_HAS_GCOV_PROFILE_ALL
|
select ARCH_HAS_GCOV_PROFILE_ALL
|
||||||
select ARCH_HAS_SYNC_DMA_FOR_CPU
|
select ARCH_HAS_SYNC_DMA_FOR_CPU
|
||||||
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
|
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
|
||||||
|
@ -12,7 +13,6 @@ config MICROBLAZE
|
||||||
select CLONE_BACKWARDS3
|
select CLONE_BACKWARDS3
|
||||||
select COMMON_CLK
|
select COMMON_CLK
|
||||||
select DMA_DIRECT_OPS
|
select DMA_DIRECT_OPS
|
||||||
select DMA_NONCOHERENT_MMAP
|
|
||||||
select GENERIC_ATOMIC64
|
select GENERIC_ATOMIC64
|
||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select GENERIC_CPU_DEVICES
|
select GENERIC_CPU_DEVICES
|
||||||
|
|
|
@ -553,8 +553,6 @@ void __init *early_get_page(void);
|
||||||
|
|
||||||
extern unsigned long ioremap_bot, ioremap_base;
|
extern unsigned long ioremap_bot, ioremap_base;
|
||||||
|
|
||||||
unsigned long consistent_virt_to_pfn(void *vaddr);
|
|
||||||
|
|
||||||
void setup_memory(void);
|
void setup_memory(void);
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
|
|
@ -42,25 +42,3 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
|
||||||
{
|
{
|
||||||
__dma_sync(dev, paddr, size, dir);
|
__dma_sync(dev, paddr, size, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
|
||||||
void *cpu_addr, dma_addr_t handle, size_t size,
|
|
||||||
unsigned long attrs)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_MMU
|
|
||||||
unsigned long user_count = vma_pages(vma);
|
|
||||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
|
||||||
unsigned long off = vma->vm_pgoff;
|
|
||||||
unsigned long pfn;
|
|
||||||
|
|
||||||
if (off >= count || user_count > (count - off))
|
|
||||||
return -ENXIO;
|
|
||||||
|
|
||||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
|
||||||
pfn = consistent_virt_to_pfn(cpu_addr);
|
|
||||||
return remap_pfn_range(vma, vma->vm_start, pfn + off,
|
|
||||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
|
||||||
#else
|
|
||||||
return -ENXIO;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
|
@ -165,7 +165,8 @@ static pte_t *consistent_virt_to_pte(void *vaddr)
|
||||||
return pte_offset_kernel(pmd_offset(pgd_offset_k(addr), addr), addr);
|
return pte_offset_kernel(pmd_offset(pgd_offset_k(addr), addr), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long consistent_virt_to_pfn(void *vaddr)
|
long arch_dma_coherent_to_pfn(struct device *dev, void *vaddr,
|
||||||
|
dma_addr_t dma_addr)
|
||||||
{
|
{
|
||||||
pte_t *ptep = consistent_virt_to_pte(vaddr);
|
pte_t *ptep = consistent_virt_to_pte(vaddr);
|
||||||
|
|
||||||
|
|
|
@ -1116,10 +1116,11 @@ config DMA_PERDEV_COHERENT
|
||||||
|
|
||||||
config DMA_NONCOHERENT
|
config DMA_NONCOHERENT
|
||||||
bool
|
bool
|
||||||
|
select ARCH_HAS_DMA_MMAP_PGPROT
|
||||||
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
|
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
|
||||||
select ARCH_HAS_SYNC_DMA_FOR_CPU
|
select ARCH_HAS_SYNC_DMA_FOR_CPU
|
||||||
select NEED_DMA_MAP_STATE
|
select NEED_DMA_MAP_STATE
|
||||||
select DMA_NONCOHERENT_MMAP
|
select ARCH_HAS_DMA_COHERENT_TO_PFN
|
||||||
select DMA_NONCOHERENT_CACHE_SYNC
|
select DMA_NONCOHERENT_CACHE_SYNC
|
||||||
|
|
||||||
config SYS_HAS_EARLY_PRINTK
|
config SYS_HAS_EARLY_PRINTK
|
||||||
|
|
|
@ -682,7 +682,6 @@ static int jazz_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
|
||||||
const struct dma_map_ops jazz_dma_ops = {
|
const struct dma_map_ops jazz_dma_ops = {
|
||||||
.alloc = jazz_dma_alloc,
|
.alloc = jazz_dma_alloc,
|
||||||
.free = jazz_dma_free,
|
.free = jazz_dma_free,
|
||||||
.mmap = arch_dma_mmap,
|
|
||||||
.map_page = jazz_dma_map_page,
|
.map_page = jazz_dma_map_page,
|
||||||
.unmap_page = jazz_dma_unmap_page,
|
.unmap_page = jazz_dma_unmap_page,
|
||||||
.map_sg = jazz_dma_map_sg,
|
.map_sg = jazz_dma_map_sg,
|
||||||
|
|
|
@ -66,33 +66,19 @@ void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
|
||||||
dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
|
dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
|
||||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
dma_addr_t dma_addr)
|
||||||
|
{
|
||||||
|
unsigned long addr = CAC_ADDR((unsigned long)cpu_addr);
|
||||||
|
return page_to_pfn(virt_to_page((void *)addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
|
||||||
unsigned long attrs)
|
unsigned long attrs)
|
||||||
{
|
{
|
||||||
unsigned long user_count = vma_pages(vma);
|
|
||||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
|
||||||
unsigned long addr = CAC_ADDR((unsigned long)cpu_addr);
|
|
||||||
unsigned long off = vma->vm_pgoff;
|
|
||||||
unsigned long pfn = page_to_pfn(virt_to_page((void *)addr));
|
|
||||||
int ret = -ENXIO;
|
|
||||||
|
|
||||||
if (attrs & DMA_ATTR_WRITE_COMBINE)
|
if (attrs & DMA_ATTR_WRITE_COMBINE)
|
||||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
return pgprot_writecombine(prot);
|
||||||
else
|
return pgprot_noncached(prot);
|
||||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
|
||||||
|
|
||||||
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (off < count && user_count <= (count - off)) {
|
|
||||||
ret = remap_pfn_range(vma, vma->vm_start,
|
|
||||||
pfn + off,
|
|
||||||
user_count << PAGE_SHIFT,
|
|
||||||
vma->vm_page_prot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void dma_sync_virt(void *addr, size_t size,
|
static inline void dma_sync_virt(void *addr, size_t size,
|
||||||
|
|
|
@ -662,7 +662,7 @@ xen_swiotlb_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||||
return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr,
|
return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr,
|
||||||
dma_addr, size, attrs);
|
dma_addr, size, attrs);
|
||||||
#endif
|
#endif
|
||||||
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
|
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -444,7 +444,8 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||||
void *cpu_addr, dma_addr_t dma_addr, size_t size);
|
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||||
|
unsigned long attrs);
|
||||||
|
|
||||||
void *dma_common_contiguous_remap(struct page *page, size_t size,
|
void *dma_common_contiguous_remap(struct page *page, size_t size,
|
||||||
unsigned long vm_flags,
|
unsigned long vm_flags,
|
||||||
|
@ -476,7 +477,7 @@ dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
|
||||||
BUG_ON(!ops);
|
BUG_ON(!ops);
|
||||||
if (ops->mmap)
|
if (ops->mmap)
|
||||||
return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
|
return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
|
||||||
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
|
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
|
#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
|
||||||
|
|
|
@ -24,9 +24,15 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
|
||||||
gfp_t gfp, unsigned long attrs);
|
gfp_t gfp, unsigned long attrs);
|
||||||
void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
|
void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
|
||||||
dma_addr_t dma_addr, unsigned long attrs);
|
dma_addr_t dma_addr, unsigned long attrs);
|
||||||
int arch_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
|
||||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
dma_addr_t dma_addr);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARCH_HAS_DMA_MMAP_PGPROT
|
||||||
|
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
|
||||||
unsigned long attrs);
|
unsigned long attrs);
|
||||||
|
#else
|
||||||
|
# define arch_dma_mmap_pgprot(dev, prot, attrs) pgprot_noncached(prot)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_DMA_NONCOHERENT_CACHE_SYNC
|
#ifdef CONFIG_DMA_NONCOHERENT_CACHE_SYNC
|
||||||
void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
||||||
|
|
|
@ -29,14 +29,16 @@ config ARCH_HAS_SYNC_DMA_FOR_CPU
|
||||||
config ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
|
config ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config ARCH_HAS_DMA_COHERENT_TO_PFN
|
||||||
|
bool
|
||||||
|
|
||||||
|
config ARCH_HAS_DMA_MMAP_PGPROT
|
||||||
|
bool
|
||||||
|
|
||||||
config DMA_DIRECT_OPS
|
config DMA_DIRECT_OPS
|
||||||
bool
|
bool
|
||||||
depends on HAS_DMA
|
depends on HAS_DMA
|
||||||
|
|
||||||
config DMA_NONCOHERENT_MMAP
|
|
||||||
bool
|
|
||||||
depends on DMA_DIRECT_OPS
|
|
||||||
|
|
||||||
config DMA_NONCOHERENT_CACHE_SYNC
|
config DMA_NONCOHERENT_CACHE_SYNC
|
||||||
bool
|
bool
|
||||||
depends on DMA_DIRECT_OPS
|
depends on DMA_DIRECT_OPS
|
||||||
|
|
|
@ -155,16 +155,6 @@ void dma_direct_free(struct device *dev, size_t size,
|
||||||
dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
|
dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static 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)
|
|
||||||
{
|
|
||||||
if (!dev_is_dma_coherent(dev) &&
|
|
||||||
IS_ENABLED(CONFIG_DMA_NONCOHERENT_MMAP))
|
|
||||||
return arch_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
|
|
||||||
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dma_direct_sync_single_for_device(struct device *dev,
|
static void dma_direct_sync_single_for_device(struct device *dev,
|
||||||
dma_addr_t addr, size_t size, enum dma_data_direction dir)
|
dma_addr_t addr, size_t size, enum dma_data_direction dir)
|
||||||
{
|
{
|
||||||
|
@ -293,7 +283,6 @@ int dma_direct_mapping_error(struct device *dev, dma_addr_t dma_addr)
|
||||||
const struct dma_map_ops dma_direct_ops = {
|
const struct dma_map_ops dma_direct_ops = {
|
||||||
.alloc = dma_direct_alloc,
|
.alloc = dma_direct_alloc,
|
||||||
.free = dma_direct_free,
|
.free = dma_direct_free,
|
||||||
.mmap = dma_direct_mmap,
|
|
||||||
.map_page = dma_direct_map_page,
|
.map_page = dma_direct_map_page,
|
||||||
.map_sg = dma_direct_map_sg,
|
.map_sg = dma_direct_map_sg,
|
||||||
#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE)
|
#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-noncoherent.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
@ -220,27 +220,37 @@ EXPORT_SYMBOL(dma_common_get_sgtable);
|
||||||
* Create userspace mapping for the DMA-coherent memory.
|
* Create userspace mapping for the DMA-coherent memory.
|
||||||
*/
|
*/
|
||||||
int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||||
void *cpu_addr, dma_addr_t dma_addr, size_t size)
|
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||||
|
unsigned long attrs)
|
||||||
{
|
{
|
||||||
int ret = -ENXIO;
|
|
||||||
#ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP
|
#ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP
|
||||||
unsigned long user_count = vma_pages(vma);
|
unsigned long user_count = vma_pages(vma);
|
||||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||||
unsigned long off = vma->vm_pgoff;
|
unsigned long off = vma->vm_pgoff;
|
||||||
|
unsigned long pfn;
|
||||||
|
int ret = -ENXIO;
|
||||||
|
|
||||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
vma->vm_page_prot = arch_dma_mmap_pgprot(dev, vma->vm_page_prot, attrs);
|
||||||
|
|
||||||
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
|
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (off < count && user_count <= (count - off))
|
if (off >= count || user_count > count - off)
|
||||||
ret = remap_pfn_range(vma, vma->vm_start,
|
return -ENXIO;
|
||||||
page_to_pfn(virt_to_page(cpu_addr)) + off,
|
|
||||||
user_count << PAGE_SHIFT,
|
|
||||||
vma->vm_page_prot);
|
|
||||||
#endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */
|
|
||||||
|
|
||||||
return ret;
|
if (!dev_is_dma_coherent(dev)) {
|
||||||
|
if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN))
|
||||||
|
return -ENXIO;
|
||||||
|
pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr);
|
||||||
|
} else {
|
||||||
|
pfn = page_to_pfn(virt_to_page(cpu_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
|
||||||
|
user_count << PAGE_SHIFT, vma->vm_page_prot);
|
||||||
|
#else
|
||||||
|
return -ENXIO;
|
||||||
|
#endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_common_mmap);
|
EXPORT_SYMBOL(dma_common_mmap);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue