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 idx = type + KM_TYPE_NR*smp_processor_id(); 32 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 33 34 flush_cache_all(); 35 36#ifdef CONFIG_DEBUG_HIGHMEM 37 BUG_ON(!pte_none(*(kmap_pte-idx))); 38#endif 39 set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); 40 flush_tlb_all(); 41 42 return (void*) vaddr; 43} 44 45void kunmap_atomic(void *kvaddr, enum km_type type) 46{ 47#ifdef CONFIG_DEBUG_HIGHMEM 48 unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; 49 unsigned long idx = type + KM_TYPE_NR*smp_processor_id(); 50 51 if (vaddr < FIXADDR_START) { 52 pagefault_enable(); 53 return; 54 } 55 56 BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)); 57 58 flush_cache_all(); 59 60 /* 61 * force other mappings to Oops if they'll try to access 62 * this pte without first remap it 63 */ 64 pte_clear(&init_mm, vaddr, kmap_pte-idx); 65 flush_tlb_all(); 66#endif 67 68 pagefault_enable(); 69} 70 71/* We may be fed a pagetable here by ptep_to_xxx and others. */ 72struct page *kmap_atomic_to_page(void *ptr) 73{ 74 unsigned long idx, vaddr = (unsigned long)ptr; 75 pte_t *pte; 76 77 if (vaddr < SRMMU_NOCACHE_VADDR) 78 return virt_to_page(ptr); 79 if (vaddr < PKMAP_BASE) 80 return pfn_to_page(__nocache_pa(vaddr) >> PAGE_SHIFT); 81 BUG_ON(vaddr < FIXADDR_START); 82 BUG_ON(vaddr > FIXADDR_TOP); 83 84 idx = virt_to_fix(vaddr); 85 pte = kmap_pte - (idx - FIX_KMAP_BEGIN); 86 return pte_page(*pte); 87} 88