2005-04-17 02:20:36 +04:00
/*
* linux / arch / m32r / mm / ioremap . c
*
* Copyright ( c ) 2001 , 2002 Hiroyuki Kondo
*
* Taken from mips version .
* ( C ) Copyright 1995 1996 Linus Torvalds
* ( C ) Copyright 2001 Ralf Baechle
*/
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
*/
# include <linux/module.h>
# include <asm/addrspace.h>
# include <asm/byteorder.h>
# include <linux/vmalloc.h>
2006-10-01 10:29:18 +04:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
# include <asm/pgalloc.h>
/*
* 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 .
*/
# define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL))
void __iomem *
__ioremap ( unsigned long phys_addr , unsigned long size , unsigned long flags )
{
void __iomem * addr ;
struct vm_struct * area ;
unsigned long offset , last_addr ;
2006-10-01 10:29:18 +04:00
pgprot_t pgprot ;
2005-04-17 02:20:36 +04:00
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1 ;
if ( ! size | | last_addr < phys_addr )
return NULL ;
/*
* Map objects in the low 512 mb of address space using KSEG1 , otherwise
* map using page tables .
*/
if ( IS_LOW512 ( phys_addr ) & & IS_LOW512 ( phys_addr + size - 1 ) )
return ( void * ) KSEG1ADDR ( phys_addr ) ;
/*
* Don ' t allow anybody to remap normal RAM that we ' re using . .
*/
if ( phys_addr < virt_to_phys ( high_memory ) ) {
char * t_addr , * t_end ;
struct page * page ;
t_addr = __va ( phys_addr ) ;
t_end = t_addr + ( size - 1 ) ;
for ( page = virt_to_page ( t_addr ) ; page < = virt_to_page ( t_end ) ; page + + )
if ( ! PageReserved ( page ) )
return NULL ;
}
2006-10-01 10:29:18 +04:00
pgprot = __pgprot ( _PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ
| _PAGE_WRITE | flags ) ;
2005-04-17 02:20:36 +04:00
/*
* 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 ;
area - > phys_addr = phys_addr ;
addr = ( void __iomem * ) area - > addr ;
2006-10-01 10:29:18 +04:00
if ( ioremap_page_range ( ( unsigned long ) addr , ( unsigned long ) addr + size ,
phys_addr , pgprot ) ) {
2005-04-17 02:20:36 +04:00
vunmap ( ( void __force * ) addr ) ;
return NULL ;
}
return ( void __iomem * ) ( offset + ( char __iomem * ) addr ) ;
}
# define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1)
void iounmap ( volatile void __iomem * addr )
{
if ( ! IS_KSEG1 ( addr ) )
vfree ( ( void * ) ( PAGE_MASK & ( unsigned long ) addr ) ) ;
}