diff options
Diffstat (limited to 'drivers/base/dma-mapping.c')
| -rw-r--r-- | drivers/base/dma-mapping.c | 56 | 
1 files changed, 53 insertions, 3 deletions
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 763d59c1eb6..6cd08e145bf 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -8,7 +8,9 @@   */  #include <linux/dma-mapping.h> +#include <linux/export.h>  #include <linux/gfp.h> +#include <asm-generic/dma-coherent.h>  /*   * Managed DMA API @@ -173,7 +175,7 @@ static void dmam_coherent_decl_release(struct device *dev, void *res)  /**   * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory()   * @dev: Device to declare coherent memory for - * @bus_addr: Bus address of coherent memory to be declared + * @phys_addr: Physical address of coherent memory to be declared   * @device_addr: Device address of coherent memory to be declared   * @size: Size of coherent memory to be declared   * @flags: Flags @@ -183,7 +185,7 @@ static void dmam_coherent_decl_release(struct device *dev, void *res)   * RETURNS:   * 0 on success, -errno on failure.   */ -int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, +int dmam_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,  				 dma_addr_t device_addr, size_t size, int flags)  {  	void *res; @@ -193,7 +195,7 @@ int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,  	if (!res)  		return -ENOMEM; -	rc = dma_declare_coherent_memory(dev, bus_addr, device_addr, size, +	rc = dma_declare_coherent_memory(dev, phys_addr, device_addr, size,  					 flags);  	if (rc == 0)  		devres_add(dev, res); @@ -217,3 +219,51 @@ void dmam_release_declared_memory(struct device *dev)  EXPORT_SYMBOL(dmam_release_declared_memory);  #endif + +/* + * Create scatter-list for the already allocated DMA buffer. + */ +int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, +		 void *cpu_addr, dma_addr_t handle, size_t size) +{ +	struct page *page = virt_to_page(cpu_addr); +	int ret; + +	ret = sg_alloc_table(sgt, 1, GFP_KERNEL); +	if (unlikely(ret)) +		return ret; + +	sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); +	return 0; +} +EXPORT_SYMBOL(dma_common_get_sgtable); + +/* + * Create userspace mapping for the DMA-coherent memory. + */ +int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, +		    void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ +	int ret = -ENXIO; +#ifdef CONFIG_MMU +	unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; +	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; +	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr)); +	unsigned long off = vma->vm_pgoff; + +	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + +	if (dma_mmap_from_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); +	} +#endif	/* CONFIG_MMU */ + +	return ret; +} +EXPORT_SYMBOL(dma_common_mmap);  | 
