common: add dma_mmap_from_coherent() function
Add a common helper for dma-mapping core for mapping a coherent buffer to userspace. Reported-by: Subash Patel <subashrp@gmail.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Tested-By: Subash Patel <subash.ramaswamy@linaro.org>
This commit is contained in:
parent
76e10d158e
commit
bca0fa5f12
2 changed files with 45 additions and 1 deletions
|
@ -10,6 +10,7 @@
|
||||||
struct dma_coherent_mem {
|
struct dma_coherent_mem {
|
||||||
void *virt_base;
|
void *virt_base;
|
||||||
dma_addr_t device_base;
|
dma_addr_t device_base;
|
||||||
|
phys_addr_t pfn_base;
|
||||||
int size;
|
int size;
|
||||||
int flags;
|
int flags;
|
||||||
unsigned long *bitmap;
|
unsigned long *bitmap;
|
||||||
|
@ -44,6 +45,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||||
|
|
||||||
dev->dma_mem->virt_base = mem_base;
|
dev->dma_mem->virt_base = mem_base;
|
||||||
dev->dma_mem->device_base = device_addr;
|
dev->dma_mem->device_base = device_addr;
|
||||||
|
dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
|
||||||
dev->dma_mem->size = pages;
|
dev->dma_mem->size = pages;
|
||||||
dev->dma_mem->flags = flags;
|
dev->dma_mem->flags = flags;
|
||||||
|
|
||||||
|
@ -176,3 +178,43 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_release_from_coherent);
|
EXPORT_SYMBOL(dma_release_from_coherent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dma_mmap_from_coherent() - try to mmap the memory allocated from
|
||||||
|
* per-device coherent memory pool to userspace
|
||||||
|
* @dev: device from which the memory was allocated
|
||||||
|
* @vma: vm_area for the userspace memory
|
||||||
|
* @vaddr: cpu address returned by dma_alloc_from_coherent
|
||||||
|
* @size: size of the memory buffer allocated by dma_alloc_from_coherent
|
||||||
|
*
|
||||||
|
* This checks whether the memory was allocated from the per-device
|
||||||
|
* coherent memory pool and if so, maps that memory to the provided vma.
|
||||||
|
*
|
||||||
|
* Returns 1 if we correctly mapped the memory, or 0 if
|
||||||
|
* dma_release_coherent() should proceed with mapping memory from
|
||||||
|
* generic pools.
|
||||||
|
*/
|
||||||
|
int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
|
||||||
|
void *vaddr, size_t size, int *ret)
|
||||||
|
{
|
||||||
|
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||||
|
|
||||||
|
if (mem && vaddr >= mem->virt_base && vaddr + size <=
|
||||||
|
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||||
|
unsigned long off = vma->vm_pgoff;
|
||||||
|
int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||||
|
int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
|
||||||
|
int count = size >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
*ret = -ENXIO;
|
||||||
|
if (off < count && user_count <= count - off) {
|
||||||
|
unsigned pfn = mem->pfn_base + start + off;
|
||||||
|
*ret = remap_pfn_range(vma, vma->vm_start, pfn,
|
||||||
|
user_count << PAGE_SHIFT,
|
||||||
|
vma->vm_page_prot);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dma_mmap_from_coherent);
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
|
|
||||||
#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
|
#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
|
||||||
/*
|
/*
|
||||||
* These two functions are only for dma allocator.
|
* These three functions are only for dma allocator.
|
||||||
* Don't use them in device drivers.
|
* Don't use them in device drivers.
|
||||||
*/
|
*/
|
||||||
int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
||||||
dma_addr_t *dma_handle, void **ret);
|
dma_addr_t *dma_handle, void **ret);
|
||||||
int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
|
int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
|
||||||
|
|
||||||
|
int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
|
||||||
|
void *cpu_addr, size_t size, int *ret);
|
||||||
/*
|
/*
|
||||||
* Standard interface
|
* Standard interface
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue