95 lines
		
	
	
	
		
			2.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			95 lines
		
	
	
	
		
			2.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | ||
|  |  * | ||
|  |  * This program is free software; you can redistribute it and/or modify | ||
|  |  * it under the terms of the GNU General Public License version 2 as | ||
|  |  * published by the Free Software Foundation. | ||
|  |  */ | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * DMA Coherent API Notes | ||
|  |  * | ||
|  |  * I/O is inherently non-coherent on ARC. So a coherent DMA buffer is | ||
|  |  * implemented by accessintg it using a kernel virtual address, with | ||
|  |  * Cache bit off in the TLB entry. | ||
|  |  * | ||
|  |  * The default DMA address == Phy address which is 0x8000_0000 based. | ||
|  |  * A platform/device can make it zero based, by over-riding | ||
|  |  * plat_{dma,kernel}_addr_to_{kernel,dma} | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <linux/dma-mapping.h>
 | ||
|  | #include <linux/dma-debug.h>
 | ||
|  | #include <linux/export.h>
 | ||
|  | #include <asm/cacheflush.h>
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Helpers for Coherent DMA API. | ||
|  |  */ | ||
|  | void *dma_alloc_noncoherent(struct device *dev, size_t size, | ||
|  | 			    dma_addr_t *dma_handle, gfp_t gfp) | ||
|  | { | ||
|  | 	void *paddr; | ||
|  | 
 | ||
|  | 	/* This is linear addr (0x8000_0000 based) */ | ||
|  | 	paddr = alloc_pages_exact(size, gfp); | ||
|  | 	if (!paddr) | ||
|  | 		return NULL; | ||
|  | 
 | ||
|  | 	/* This is bus address, platform dependent */ | ||
|  | 	*dma_handle = plat_kernel_addr_to_dma(dev, paddr); | ||
|  | 
 | ||
|  | 	return paddr; | ||
|  | } | ||
|  | EXPORT_SYMBOL(dma_alloc_noncoherent); | ||
|  | 
 | ||
|  | void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, | ||
|  | 			  dma_addr_t dma_handle) | ||
|  | { | ||
|  | 	free_pages_exact((void *)plat_dma_addr_to_kernel(dev, dma_handle), | ||
|  | 			 size); | ||
|  | } | ||
|  | EXPORT_SYMBOL(dma_free_noncoherent); | ||
|  | 
 | ||
|  | void *dma_alloc_coherent(struct device *dev, size_t size, | ||
|  | 			 dma_addr_t *dma_handle, gfp_t gfp) | ||
|  | { | ||
|  | 	void *paddr, *kvaddr; | ||
|  | 
 | ||
|  | 	/* This is linear addr (0x8000_0000 based) */ | ||
|  | 	paddr = alloc_pages_exact(size, gfp); | ||
|  | 	if (!paddr) | ||
|  | 		return NULL; | ||
|  | 
 | ||
|  | 	/* This is kernel Virtual address (0x7000_0000 based) */ | ||
|  | 	kvaddr = ioremap_nocache((unsigned long)paddr, size); | ||
|  | 	if (kvaddr != NULL) | ||
|  | 		memset(kvaddr, 0, size); | ||
|  | 
 | ||
|  | 	/* This is bus address, platform dependent */ | ||
|  | 	*dma_handle = plat_kernel_addr_to_dma(dev, paddr); | ||
|  | 
 | ||
|  | 	return kvaddr; | ||
|  | } | ||
|  | EXPORT_SYMBOL(dma_alloc_coherent); | ||
|  | 
 | ||
|  | void dma_free_coherent(struct device *dev, size_t size, void *kvaddr, | ||
|  | 		       dma_addr_t dma_handle) | ||
|  | { | ||
|  | 	iounmap((void __force __iomem *)kvaddr); | ||
|  | 
 | ||
|  | 	free_pages_exact((void *)plat_dma_addr_to_kernel(dev, dma_handle), | ||
|  | 			 size); | ||
|  | } | ||
|  | EXPORT_SYMBOL(dma_free_coherent); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Helper for streaming DMA... | ||
|  |  */ | ||
|  | void __arc_dma_cache_sync(unsigned long paddr, size_t size, | ||
|  | 			  enum dma_data_direction dir) | ||
|  | { | ||
|  | 	__inline_dma_cache_sync(paddr, size, dir); | ||
|  | } | ||
|  | EXPORT_SYMBOL(__arc_dma_cache_sync); |