2006-03-26 13:37:06 +04:00
/*
2007-03-30 20:34:05 +04:00
* ( c ) Copyright 2006 , 2007 Hewlett - Packard Development Company , L . P .
2006-03-26 13:37:06 +04:00
* Bjorn Helgaas < bjorn . helgaas @ hp . 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 .
*/
# include <linux/compiler.h>
# include <linux/module.h>
# include <linux/efi.h>
2007-03-30 20:34:05 +04:00
# include <linux/io.h>
# include <linux/vmalloc.h>
2006-03-26 13:37:06 +04:00
# include <asm/io.h>
2006-05-06 03:19:50 +04:00
# include <asm/meminit.h>
2006-03-26 13:37:06 +04:00
static inline void __iomem *
2007-03-30 20:34:05 +04:00
__ioremap ( unsigned long phys_addr )
2006-03-26 13:37:06 +04:00
{
2007-03-30 20:33:11 +04:00
return ( void __iomem * ) ( __IA64_UNCACHED_OFFSET | phys_addr ) ;
2006-03-26 13:37:06 +04:00
}
2009-12-14 23:00:36 +03:00
void __iomem *
early_ioremap ( unsigned long phys_addr , unsigned long size )
{
return __ioremap ( phys_addr ) ;
}
2006-03-26 13:37:06 +04:00
void __iomem *
2007-03-30 20:33:11 +04:00
ioremap ( unsigned long phys_addr , unsigned long size )
2006-03-26 13:37:06 +04:00
{
2007-03-30 20:34:05 +04:00
void __iomem * addr ;
struct vm_struct * area ;
unsigned long offset ;
pgprot_t prot ;
2006-05-06 03:19:50 +04:00
u64 attr ;
unsigned long gran_base , gran_size ;
2007-03-30 20:34:05 +04:00
unsigned long page_base ;
2006-03-26 13:37:06 +04:00
2006-05-06 03:19:50 +04:00
/*
* For things in kern_memmap , we must use the same attribute
* as the rest of the kernel . For more details , see
* Documentation / ia64 / aliasing . txt .
*/
2007-03-30 20:33:11 +04:00
attr = kern_mem_attribute ( phys_addr , size ) ;
2006-05-06 03:19:50 +04:00
if ( attr & EFI_MEMORY_WB )
2007-03-30 20:33:11 +04:00
return ( void __iomem * ) phys_to_virt ( phys_addr ) ;
2006-05-06 03:19:50 +04:00
else if ( attr & EFI_MEMORY_UC )
2007-03-30 20:34:05 +04:00
return __ioremap ( phys_addr ) ;
2006-03-30 20:53:39 +04:00
2006-03-26 13:37:06 +04:00
/*
2006-05-06 03:19:50 +04:00
* Some chipsets don ' t support UC access to memory . If
* WB is supported for the whole granule , we prefer that .
2006-03-26 13:37:06 +04:00
*/
2007-03-30 20:33:11 +04:00
gran_base = GRANULEROUNDDOWN ( phys_addr ) ;
gran_size = GRANULEROUNDUP ( phys_addr + size ) - gran_base ;
2006-05-06 03:19:50 +04:00
if ( efi_mem_attribute ( gran_base , gran_size ) & EFI_MEMORY_WB )
2007-03-30 20:33:11 +04:00
return ( void __iomem * ) phys_to_virt ( phys_addr ) ;
2006-05-06 03:19:50 +04:00
2007-03-30 20:34:05 +04:00
/*
* WB is not supported for the whole granule , so we can ' t use
* the region 7 identity mapping . If we can safely cover the
* area with kernel page table mappings , we can use those
* instead .
*/
page_base = phys_addr & PAGE_MASK ;
size = PAGE_ALIGN ( phys_addr + size ) - page_base ;
if ( efi_mem_attribute ( page_base , size ) & EFI_MEMORY_WB ) {
prot = PAGE_KERNEL ;
/*
* Mappings have to be page - aligned
*/
offset = phys_addr & ~ PAGE_MASK ;
phys_addr & = PAGE_MASK ;
/*
* 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 ;
if ( ioremap_page_range ( ( unsigned long ) addr ,
( unsigned long ) addr + size , phys_addr , prot ) ) {
vunmap ( ( void __force * ) addr ) ;
return NULL ;
}
return ( void __iomem * ) ( offset + ( char __iomem * ) addr ) ;
}
return __ioremap ( phys_addr ) ;
2006-03-26 13:37:06 +04:00
}
EXPORT_SYMBOL ( ioremap ) ;
void __iomem *
2007-03-30 20:33:11 +04:00
ioremap_nocache ( unsigned long phys_addr , unsigned long size )
2006-03-26 13:37:06 +04:00
{
2007-03-30 20:33:11 +04:00
if ( kern_mem_attribute ( phys_addr , size ) & EFI_MEMORY_WB )
2006-07-17 09:41:59 +04:00
return NULL ;
2006-05-06 03:19:50 +04:00
2007-03-30 20:34:05 +04:00
return __ioremap ( phys_addr ) ;
2006-03-26 13:37:06 +04:00
}
EXPORT_SYMBOL ( ioremap_nocache ) ;
2007-03-30 20:34:05 +04:00
2009-12-14 23:00:36 +03:00
void
early_iounmap ( volatile void __iomem * addr , unsigned long size )
{
}
2007-03-30 20:34:05 +04:00
void
iounmap ( volatile void __iomem * addr )
{
if ( REGION_NUMBER ( addr ) = = RGN_GATE )
vunmap ( ( void * ) ( ( unsigned long ) addr & PAGE_MASK ) ) ;
}
EXPORT_SYMBOL ( iounmap ) ;