Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.32-rc5 131 lines 3.0 kB view raw
1#include <linux/module.h> 2#include <linux/highmem.h> 3#include <linux/smp.h> 4#include <asm/fixmap.h> 5#include <asm/tlbflush.h> 6 7static pte_t *kmap_pte; 8 9unsigned long highstart_pfn, highend_pfn; 10 11void *__kmap(struct page *page) 12{ 13 void *addr; 14 15 might_sleep(); 16 if (!PageHighMem(page)) 17 return page_address(page); 18 addr = kmap_high(page); 19 flush_tlb_one((unsigned long)addr); 20 21 return addr; 22} 23EXPORT_SYMBOL(__kmap); 24 25void __kunmap(struct page *page) 26{ 27 BUG_ON(in_interrupt()); 28 if (!PageHighMem(page)) 29 return; 30 kunmap_high(page); 31} 32EXPORT_SYMBOL(__kunmap); 33 34/* 35 * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because 36 * no global lock is needed and because the kmap code must perform a global TLB 37 * invalidation when the kmap pool wraps. 38 * 39 * However when holding an atomic kmap is is not legal to sleep, so atomic 40 * kmaps are appropriate for short, tight code paths only. 41 */ 42 43void *__kmap_atomic(struct page *page, enum km_type type) 44{ 45 enum fixed_addresses idx; 46 unsigned long vaddr; 47 48 /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ 49 pagefault_disable(); 50 if (!PageHighMem(page)) 51 return page_address(page); 52 53 debug_kmap_atomic(type); 54 idx = type + KM_TYPE_NR*smp_processor_id(); 55 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 56#ifdef CONFIG_DEBUG_HIGHMEM 57 BUG_ON(!pte_none(*(kmap_pte - idx))); 58#endif 59 set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); 60 local_flush_tlb_one((unsigned long)vaddr); 61 62 return (void*) vaddr; 63} 64EXPORT_SYMBOL(__kmap_atomic); 65 66void __kunmap_atomic(void *kvaddr, enum km_type type) 67{ 68#ifdef CONFIG_DEBUG_HIGHMEM 69 unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; 70 enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); 71 72 if (vaddr < FIXADDR_START) { // FIXME 73 pagefault_enable(); 74 return; 75 } 76 77 BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); 78 79 /* 80 * force other mappings to Oops if they'll try to access 81 * this pte without first remap it 82 */ 83 pte_clear(&init_mm, vaddr, kmap_pte-idx); 84 local_flush_tlb_one(vaddr); 85#endif 86 87 pagefault_enable(); 88} 89EXPORT_SYMBOL(__kunmap_atomic); 90 91/* 92 * This is the same as kmap_atomic() but can map memory that doesn't 93 * have a struct page associated with it. 94 */ 95void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) 96{ 97 enum fixed_addresses idx; 98 unsigned long vaddr; 99 100 pagefault_disable(); 101 102 debug_kmap_atomic(type); 103 idx = type + KM_TYPE_NR*smp_processor_id(); 104 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 105 set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL)); 106 flush_tlb_one(vaddr); 107 108 return (void*) vaddr; 109} 110 111struct page *__kmap_atomic_to_page(void *ptr) 112{ 113 unsigned long idx, vaddr = (unsigned long)ptr; 114 pte_t *pte; 115 116 if (vaddr < FIXADDR_START) 117 return virt_to_page(ptr); 118 119 idx = virt_to_fix(vaddr); 120 pte = kmap_pte - (idx - FIX_KMAP_BEGIN); 121 return pte_page(*pte); 122} 123 124void __init kmap_init(void) 125{ 126 unsigned long kmap_vstart; 127 128 /* cache the first kmap pte */ 129 kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); 130 kmap_pte = kmap_get_fixmap_pte(kmap_vstart); 131}