2009-11-05 10:54:17 +03:00
/*
* Re - map IO memory to kernel address space so that we can access it .
*
* These functions should only be used when it is necessary to map a
* physical address space into the kernel address space before ioremap ( )
* can be used , e . g . early in boot before paging_init ( ) .
*
* Copyright ( C ) 2009 Matt Fleming
*/
# include <linux/vmalloc.h>
# include <linux/ioport.h>
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/io.h>
# include <linux/bootmem.h>
# include <linux/proc_fs.h>
# include <asm/fixmap.h>
# include <asm/page.h>
# include <asm/pgalloc.h>
# include <asm/addrspace.h>
# include <asm/cacheflush.h>
# include <asm/tlbflush.h>
# include <asm/mmu.h>
# include <asm/mmu_context.h>
struct ioremap_map {
void __iomem * addr ;
unsigned long size ;
unsigned long fixmap_addr ;
} ;
static struct ioremap_map ioremap_maps [ FIX_N_IOREMAPS ] ;
void __init ioremap_fixed_init ( void )
{
struct ioremap_map * map ;
int i ;
for ( i = 0 ; i < FIX_N_IOREMAPS ; i + + ) {
map = & ioremap_maps [ i ] ;
map - > fixmap_addr = __fix_to_virt ( FIX_IOREMAP_BEGIN + i ) ;
}
}
void __init __iomem *
2010-02-23 10:20:53 +03:00
ioremap_fixed ( phys_addr_t phys_addr , unsigned long size , pgprot_t prot )
2009-11-05 10:54:17 +03:00
{
enum fixed_addresses idx0 , idx ;
struct ioremap_map * map ;
unsigned int nrpages ;
2010-02-23 10:20:53 +03:00
unsigned long offset ;
2009-11-05 10:54:17 +03:00
int i , slot ;
2010-02-23 10:20:53 +03:00
/*
* Mappings have to be page - aligned
*/
offset = phys_addr & ~ PAGE_MASK ;
phys_addr & = PAGE_MASK ;
size = PAGE_ALIGN ( phys_addr + size ) - phys_addr ;
2009-11-05 10:54:17 +03:00
slot = - 1 ;
for ( i = 0 ; i < FIX_N_IOREMAPS ; i + + ) {
map = & ioremap_maps [ i ] ;
if ( ! map - > addr ) {
map - > size = size ;
slot = i ;
break ;
}
}
if ( slot < 0 )
return NULL ;
/*
* Mappings have to fit in the FIX_IOREMAP area .
*/
nrpages = size > > PAGE_SHIFT ;
if ( nrpages > FIX_N_IOREMAPS )
return NULL ;
/*
* Ok , go for it . .
*/
idx0 = FIX_IOREMAP_BEGIN + slot ;
idx = idx0 ;
while ( nrpages > 0 ) {
pgprot_val ( prot ) | = _PAGE_WIRED ;
__set_fixmap ( idx , phys_addr , prot ) ;
phys_addr + = PAGE_SIZE ;
idx + + ;
- - nrpages ;
}
map - > addr = ( void __iomem * ) ( offset + map - > fixmap_addr ) ;
return map - > addr ;
}
2010-01-18 15:30:29 +03:00
int iounmap_fixed ( void __iomem * addr )
2009-11-05 10:54:17 +03:00
{
enum fixed_addresses idx ;
struct ioremap_map * map ;
unsigned int nrpages ;
int i , slot ;
slot = - 1 ;
for ( i = 0 ; i < FIX_N_IOREMAPS ; i + + ) {
map = & ioremap_maps [ i ] ;
if ( map - > addr = = addr ) {
slot = i ;
break ;
}
}
2010-01-18 15:30:29 +03:00
/*
* If we don ' t match , it ' s not for us .
*/
2009-11-05 10:54:17 +03:00
if ( slot < 0 )
2010-01-18 15:30:29 +03:00
return - EINVAL ;
2009-11-05 10:54:17 +03:00
2010-01-20 12:10:30 +03:00
nrpages = map - > size > > PAGE_SHIFT ;
2009-11-05 10:54:17 +03:00
2010-01-20 12:10:30 +03:00
idx = FIX_IOREMAP_BEGIN + slot + nrpages - 1 ;
2009-11-05 10:54:17 +03:00
while ( nrpages > 0 ) {
2010-01-19 07:49:19 +03:00
__clear_fixmap ( idx , __pgprot ( _PAGE_WIRED ) ) ;
2009-11-05 10:54:17 +03:00
- - idx ;
- - nrpages ;
}
map - > size = 0 ;
map - > addr = NULL ;
2010-01-18 15:30:29 +03:00
return 0 ;
2009-11-05 10:54:17 +03:00
}