2005-04-16 15:20:36 -07:00
/*
* arch / cris / mm / ioremap . c
*
* Re - map IO memory to kernel address space so that we can access it .
* Needed for memory - mapped I / O devices mapped outside our normal DRAM
* window ( that is , all memory - mapped I / O devices ) .
*
* ( C ) Copyright 1995 1996 Linus Torvalds
* CRIS - port by Axis Communications AB
*/
# include <linux/vmalloc.h>
2006-09-30 23:29:17 -07:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
# include <asm/pgalloc.h>
2005-07-27 11:44:39 -07:00
# include <asm/arch/memmap.h>
2005-04-16 15:20:36 -07:00
/*
* Generic mapping function ( not visible outside ) :
*/
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space . Needed when the kernel wants to access high addresses
* directly .
*
* NOTE ! We need to allow non - page - aligned mappings too : we will obviously
* have to convert them into an offset in a page - aligned mapping , but the
* caller shouldn ' t need to know that small detail .
*/
2005-07-27 11:44:39 -07:00
void __iomem * __ioremap_prot ( unsigned long phys_addr , unsigned long size , pgprot_t prot )
2005-04-16 15:20:36 -07:00
{
2005-07-27 11:44:39 -07:00
void __iomem * addr ;
2005-04-16 15:20:36 -07:00
struct vm_struct * area ;
unsigned long offset , last_addr ;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1 ;
if ( ! size | | last_addr < phys_addr )
return NULL ;
/*
* Mappings have to be page - aligned
*/
offset = phys_addr & ~ PAGE_MASK ;
phys_addr & = PAGE_MASK ;
size = PAGE_ALIGN ( last_addr + 1 ) - phys_addr ;
/*
* Ok , go for it . .
*/
area = get_vm_area ( size , VM_IOREMAP ) ;
if ( ! area )
return NULL ;
2005-07-27 11:44:39 -07:00
addr = ( void __iomem * ) area - > addr ;
2006-09-30 23:29:17 -07:00
if ( ioremap_page_range ( ( unsigned long ) addr , ( unsigned long ) addr + size ,
phys_addr , prot ) ) {
2005-07-27 11:44:39 -07:00
vfree ( ( void __force * ) addr ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
2005-07-27 11:44:39 -07:00
return ( void __iomem * ) ( offset + ( char __iomem * ) addr ) ;
}
void __iomem * __ioremap ( unsigned long phys_addr , unsigned long size , unsigned long flags )
{
return __ioremap_prot ( phys_addr , size ,
__pgprot ( _PAGE_PRESENT | __READABLE |
__WRITEABLE | _PAGE_GLOBAL |
_PAGE_KERNEL | flags ) ) ;
}
/**
* ioremap_nocache - map bus memory into CPU space
* @ offset : bus address of the memory
* @ size : size of the resource to map
*
* Must be freed with iounmap .
*/
void __iomem * ioremap_nocache ( unsigned long phys_addr , unsigned long size )
{
return __ioremap ( phys_addr | MEM_NON_CACHEABLE , size , 0 ) ;
2005-04-16 15:20:36 -07:00
}
2005-07-27 11:44:39 -07:00
void iounmap ( volatile void __iomem * addr )
2005-04-16 15:20:36 -07:00
{
if ( addr > high_memory )
return vfree ( ( void * ) ( PAGE_MASK & ( unsigned long ) addr ) ) ;
}