2009-06-18 19:25:00 +00:00
/*
* highmem . c : virtual kernel memory mappings for high memory
*
* PowerPC version , stolen from the i386 version .
*
* Used in CONFIG_HIGHMEM systems for memory pages which
* are not addressable by direct kernel virtual addresses .
*
* Copyright ( C ) 1999 Gerhard Wichert , Siemens AG
* Gerhard . Wichert @ pdb . siemens . de
*
*
* Redesigned the x86 32 - bit VM architecture to deal with
* up to 16 Terrabyte physical memory . With current x86 CPUs
* we now support up to 64 Gigabytes physical RAM .
*
* Copyright ( C ) 1999 Ingo Molnar < mingo @ redhat . com >
*
* Reworked for PowerPC by various contributors . Moved from
* highmem . h by Benjamin Herrenschmidt ( c ) 2009 IBM Corp .
*/
# include <linux/highmem.h>
# include <linux/module.h>
/*
* The use of kmap_atomic / kunmap_atomic is discouraged - kmap / kunmap
* gives a more generic ( and caching ) interface . But kmap_atomic can
* be used in IRQ contexts , so in some ( very limited ) cases we need
* it .
*/
2010-10-26 14:21:51 -07:00
void * kmap_atomic_prot ( struct page * page , pgprot_t prot )
2009-06-18 19:25:00 +00:00
{
unsigned long vaddr ;
2010-10-26 14:21:51 -07:00
int idx , type ;
2009-06-18 19:25:00 +00:00
2015-05-11 17:52:09 +02:00
preempt_disable ( ) ;
2009-06-18 19:25:00 +00:00
pagefault_disable ( ) ;
if ( ! PageHighMem ( page ) )
return page_address ( page ) ;
2010-10-26 14:21:51 -07:00
type = kmap_atomic_idx_push ( ) ;
2009-06-18 19:25:00 +00:00
idx = type + KM_TYPE_NR * smp_processor_id ( ) ;
vaddr = __fix_to_virt ( FIX_KMAP_BEGIN + idx ) ;
# ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON ( ! pte_none ( * ( kmap_pte - idx ) ) ) ;
# endif
__set_pte_at ( & init_mm , vaddr , kmap_pte - idx , mk_pte ( page , prot ) , 1 ) ;
local_flush_tlb_page ( NULL , vaddr ) ;
return ( void * ) vaddr ;
}
EXPORT_SYMBOL ( kmap_atomic_prot ) ;
2010-10-26 14:21:51 -07:00
void __kunmap_atomic ( void * kvaddr )
2009-06-18 19:25:00 +00:00
{
unsigned long vaddr = ( unsigned long ) kvaddr & PAGE_MASK ;
2010-10-26 14:21:51 -07:00
int type ;
2009-06-18 19:25:00 +00:00
if ( vaddr < __fix_to_virt ( FIX_KMAP_END ) ) {
pagefault_enable ( ) ;
2015-05-11 17:52:09 +02:00
preempt_enable ( ) ;
2009-06-18 19:25:00 +00:00
return ;
}
2010-10-27 15:32:58 -07:00
type = kmap_atomic_idx ( ) ;
2009-06-18 19:25:00 +00:00
2010-10-26 14:21:51 -07:00
# ifdef CONFIG_DEBUG_HIGHMEM
{
unsigned int idx ;
idx = type + KM_TYPE_NR * smp_processor_id ( ) ;
BUG_ON ( vaddr ! = __fix_to_virt ( FIX_KMAP_BEGIN + idx ) ) ;
/*
* force other mappings to Oops if they ' ll try to access
* this pte without first remap it
*/
pte_clear ( & init_mm , vaddr , kmap_pte - idx ) ;
local_flush_tlb_page ( NULL , vaddr ) ;
}
2009-06-18 19:25:00 +00:00
# endif
2010-10-27 15:32:58 -07:00
kmap_atomic_idx_pop ( ) ;
2009-06-18 19:25:00 +00:00
pagefault_enable ( ) ;
2015-05-11 17:52:09 +02:00
preempt_enable ( ) ;
2009-06-18 19:25:00 +00:00
}
2010-10-26 14:21:51 -07:00
EXPORT_SYMBOL ( __kunmap_atomic ) ;