linux/arch/microblaze/mm/consistent.c
/*
 * Consistent memory allocators. Used for DMA devices that want to
 * share uncached memory with the processor core.
 * My crufty no-MMU approach is simple. In the HW platform we can optionally
 * mirror the DDR up above the processor cacheable region.  So, memory accessed
 * in this mirror region will not be cached.  It's alloced from the same
 * pool as normal memory, but the handle we return is shifted up into the
 * uncached region.  This will no doubt cause big problems if memory allocated
 * here is not also freed properly. -- JW
 */
Consistent memory allocators. Used for DMA devices that want to
share uncached memory with the processor core.
My crufty no-MMU approach is simple. In the HW platform we can optionally
mirror the DDR up above the processor cacheable region.  So, memory accessed
in this mirror region will not be cached.  It's alloced from the same
pool as normal memory, but the handle we return is shifted up into the
uncached region.  This will no doubt cause big problems if memory allocated
here is not also freed properly. -- JW
Consistent memory allocators . Used for DMA devices that want to share uncached memory with the processor core . My crufty no - MMU approach is simple . In the HW platform we can optionally mirror the DDR up above the processor cacheable region . So memory accessed in this mirror region will not be cached . It ' s alloced from the same pool as normal memory but the handle we return is shifted up into the uncached region . This will no doubt cause big problems if memory allocated here is not also freed properly . -- JW
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
		gfp_t gfp, unsigned long attrs)
{
	unsigned long order, vaddr;
	void *ret;
	unsigned int i, err = 0;
	struct page *page, *end;
#ifdef CONFIG_MMU
	phys_addr_t pa;
	struct vm_struct *area;
	unsigned long va;
#endif
	if (in_interrupt())
		BUG();
	size = PAGE_ALIGN(size);
	order = get_order(size);
	vaddr = __get_free_pages(gfp, order);
	if (!vaddr)
		return NULL;
	flush_dcache_range(virt_to_phys((void *)vaddr),
					virt_to_phys((void *)vaddr) + size);
#ifndef CONFIG_MMU
	ret = (void *)vaddr;
# ifdef CONFIG_XILINX_UNCACHED_SHADOW
	ret = (void *)((unsigned) ret | UNCACHED_SHADOW_MASK);
# endif
	if ((unsigned int)ret > cpuinfo.dcache_base &&
				(unsigned int)ret < cpuinfo.dcache_high)
		pr_warn("ERROR: Your cache coherent area is CACHED!!!\n");
	*dma_handle = (dma_addr_t)ret;
#else
	area = get_vm_area(size, VM_ALLOC);
	if (!area) {
		free_pages(vaddr, order);
		return NULL;
	}
	va = (unsigned long) area->addr;
	ret = (void *)va;
	*dma_handle = pa = __virt_to_phys(vaddr);
#endif
	page = virt_to_page(vaddr);
	end = page + (1 << order);
	split_page(page, order);
	for (i = 0; i < size && err == 0; i += PAGE_SIZE) {
#ifdef CONFIG_MMU
		err = map_page(va + i, pa + i, _PAGE_KERNEL | _PAGE_NO_CACHE);
#endif
		SetPageReserved(page);
		page++;
	}
	while (page < end) {
		__free_page(page);
		page++;
	}
	if (err) {
		free_pages(vaddr, order);
		return NULL;
	}
	return ret;
}
void * arch_dma_alloc ( struct device * dev , size_t size , dma_addr_t * dma_handle , gfp_t gfp , unsigned long attrs ) { unsigned long order , vaddr ; void * ret ; unsigned int i , err = 0 ; struct page * page , * end ; #ifdef CONFIG_MMU phys_addr_t pa ; struct vm_struct * area ; unsigned long va ; #endif if ( in_interrupt ( ) ) BUG ( ) ; size = PAGE_ALIGN ( size ) ; order = get_order ( size ) ; vaddr = __get_free_pages ( gfp , order ) ; if ( ! vaddr ) return NULL ; flush_dcache_range ( virt_to_phys ( ( void * ) vaddr ) , virt_to_phys ( ( void * ) vaddr ) + size ) ; #ifndef CONFIG_MMU ret = ( void * ) vaddr ; # ifdef CONFIG_XILINX_UNCACHED_SHADOW ret = ( void * ) ( ( unsigned ) ret | UNCACHED_SHADOW_MASK ) ; # endif if ( ( unsigned int ) ret > cpuinfo . dcache_base && ( unsigned int ) ret < cpuinfo . dcache_high ) pr_warn ( " \n " ) ; * dma_handle = ( dma_addr_t ) ret ; #else area = get_vm_area ( size , VM_ALLOC ) ; if ( ! area ) { free_pages ( vaddr , order ) ; return NULL ; } va = ( unsigned long ) area -> addr ; ret = ( void * ) va ; * dma_handle = pa = __virt_to_phys ( vaddr ) ; #endif page = virt_to_page ( vaddr ) ; end = page + ( 1 << order ) ; split_page ( page , order ) ; for ( i = 0 ; i < size && err == 0 ; i += PAGE_SIZE ) { #ifdef CONFIG_MMU err = map_page ( va + i , pa + i , _PAGE_KERNEL | _PAGE_NO_CACHE ) ; #endif SetPageReserved ( page ) ; page ++ ; } while ( page < end ) { __free_page ( page ) ; page ++ ; } if ( err ) { free_pages ( vaddr , order ) ; return NULL ; } return ret ; }
Consistent memory allocators.
Consistent memory allocators .
/* Only allocate page size areas. */ /*
	 * we need to ensure that there are no cachelines in use,
	 * or worse dirty in this area.
	 */ /*
	 * Here's the magic!  Note if the uncached shadow is not implemented,
	 * it's up to the calling code to also test that condition and make
	 * other arranegments, such as manually flushing the cache and so on.
	 */ /* dma_handle is same as physical (shadowed) address */ /* Allocate some common virtual space to map the new pages. */ /* This gives us the real physical address of the first page. */ /*
	 * free wasted pages.  We skip the first page since we know
	 * that it will have count = 1 and won't require freeing.
	 * We also mark the pages in use as reserved so that
	 * remap_page_range works.
	 */ /* MS: This is the whole magic - use cache inhibit pages */ /* Free the otherwise unused pages. */