1/* 2 * highmem.c: virtual kernel memory mappings for high memory 3 * 4 * Provides kernel-static versions of atomic kmap functions originally 5 * found as inlines in include/asm-sparc/highmem.h. These became 6 * needed as kmap_atomic() and kunmap_atomic() started getting 7 * called from within modules. 8 * -- Tomas Szepe <szepe@pinerecords.com>, September 2002 9 * 10 * But kmap_atomic() and kunmap_atomic() cannot be inlined in 11 * modules because they are loaded with btfixup-ped functions. 12 */ 13 14#include <linux/mm.h> 15#include <linux/highmem.h> 16#include <asm/pgalloc.h> 17#include <asm/cacheflush.h> 18#include <asm/tlbflush.h> 19#include <asm/fixmap.h> 20 21void *kmap_atomic(struct page *page, enum km_type type) 22{ 23 unsigned long idx; 24 unsigned long vaddr; 25 26 /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ 27 pagefault_disable(); 28 if (!PageHighMem(page)) 29 return page_address(page); 30 31 debug_kmap_atomic(type); 32 idx = type + KM_TYPE_NR*smp_processor_id(); 33 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 34 35 flush_cache_all(); 36 37#ifdef CONFIG_DEBUG_HIGHMEM 38 BUG_ON(!pte_none(*(kmap_pte-idx))); 39#endif 40 set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); 41 flush_tlb_all(); 42 43 return (void*) vaddr; 44} 45EXPORT_SYMBOL(kmap_atomic); 46 47void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type) 48{ 49#ifdef CONFIG_DEBUG_HIGHMEM 50 unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; 51 unsigned long idx = type + KM_TYPE_NR*smp_processor_id(); 52 53 if (vaddr < FIXADDR_START) { 54 pagefault_enable(); 55 return; 56 } 57 58 BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)); 59 60 flush_cache_all(); 61 62 /* 63 * force other mappings to Oops if they'll try to access 64 * this pte without first remap it 65 */ 66 pte_clear(&init_mm, vaddr, kmap_pte-idx); 67 flush_tlb_all(); 68#endif 69 70 pagefault_enable(); 71} 72EXPORT_SYMBOL(kunmap_atomic_notypecheck); 73 74/* We may be fed a pagetable here by ptep_to_xxx and others. */ 75struct page *kmap_atomic_to_page(void *ptr) 76{ 77 unsigned long idx, vaddr = (unsigned long)ptr; 78 pte_t *pte; 79 80 if (vaddr < SRMMU_NOCACHE_VADDR) 81 return virt_to_page(ptr); 82 if (vaddr < PKMAP_BASE) 83 return pfn_to_page(__nocache_pa(vaddr) >> PAGE_SHIFT); 84 BUG_ON(vaddr < FIXADDR_START); 85 BUG_ON(vaddr > FIXADDR_TOP); 86 87 idx = virt_to_fix(vaddr); 88 pte = kmap_pte - (idx - FIX_KMAP_BEGIN); 89 return pte_page(*pte); 90} 91