| Thomas Gleixner | d291cf8 | 2008-01-30 13:30:35 +0100 | [diff] [blame] | 1 | #ifndef _ASM_X86_TLBFLUSH_H | 
|  | 2 | #define _ASM_X86_TLBFLUSH_H | 
|  | 3 |  | 
|  | 4 | #include <linux/mm.h> | 
|  | 5 | #include <linux/sched.h> | 
|  | 6 |  | 
|  | 7 | #include <asm/processor.h> | 
|  | 8 | #include <asm/system.h> | 
|  | 9 |  | 
|  | 10 | #ifdef CONFIG_PARAVIRT | 
|  | 11 | #include <asm/paravirt.h> | 
| Thomas Gleixner | 96a388d | 2007-10-11 11:20:03 +0200 | [diff] [blame] | 12 | #else | 
| Thomas Gleixner | d291cf8 | 2008-01-30 13:30:35 +0100 | [diff] [blame] | 13 | #define __flush_tlb() __native_flush_tlb() | 
|  | 14 | #define __flush_tlb_global() __native_flush_tlb_global() | 
|  | 15 | #define __flush_tlb_single(addr) __native_flush_tlb_single(addr) | 
| Thomas Gleixner | 96a388d | 2007-10-11 11:20:03 +0200 | [diff] [blame] | 16 | #endif | 
| Thomas Gleixner | d291cf8 | 2008-01-30 13:30:35 +0100 | [diff] [blame] | 17 |  | 
|  | 18 | static inline void __native_flush_tlb(void) | 
|  | 19 | { | 
|  | 20 | write_cr3(read_cr3()); | 
|  | 21 | } | 
|  | 22 |  | 
|  | 23 | static inline void __native_flush_tlb_global(void) | 
|  | 24 | { | 
|  | 25 | unsigned long cr4 = read_cr4(); | 
|  | 26 |  | 
|  | 27 | /* clear PGE */ | 
|  | 28 | write_cr4(cr4 & ~X86_CR4_PGE); | 
|  | 29 | /* write old PGE again and flush TLBs */ | 
|  | 30 | write_cr4(cr4); | 
|  | 31 | } | 
|  | 32 |  | 
|  | 33 | static inline void __native_flush_tlb_single(unsigned long addr) | 
|  | 34 | { | 
| Joe Perches | 94cf8de | 2008-03-23 01:03:45 -0700 | [diff] [blame] | 35 | asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); | 
| Thomas Gleixner | d291cf8 | 2008-01-30 13:30:35 +0100 | [diff] [blame] | 36 | } | 
|  | 37 |  | 
|  | 38 | static inline void __flush_tlb_all(void) | 
|  | 39 | { | 
|  | 40 | if (cpu_has_pge) | 
|  | 41 | __flush_tlb_global(); | 
|  | 42 | else | 
|  | 43 | __flush_tlb(); | 
|  | 44 | } | 
|  | 45 |  | 
|  | 46 | static inline void __flush_tlb_one(unsigned long addr) | 
|  | 47 | { | 
|  | 48 | if (cpu_has_invlpg) | 
|  | 49 | __flush_tlb_single(addr); | 
|  | 50 | else | 
|  | 51 | __flush_tlb(); | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | #ifdef CONFIG_X86_32 | 
|  | 55 | # define TLB_FLUSH_ALL	0xffffffff | 
|  | 56 | #else | 
|  | 57 | # define TLB_FLUSH_ALL	-1ULL | 
|  | 58 | #endif | 
|  | 59 |  | 
|  | 60 | /* | 
|  | 61 | * TLB flushing: | 
|  | 62 | * | 
|  | 63 | *  - flush_tlb() flushes the current mm struct TLBs | 
|  | 64 | *  - flush_tlb_all() flushes all processes TLBs | 
|  | 65 | *  - flush_tlb_mm(mm) flushes the specified mm context TLB's | 
|  | 66 | *  - flush_tlb_page(vma, vmaddr) flushes one page | 
|  | 67 | *  - flush_tlb_range(vma, start, end) flushes a range of pages | 
|  | 68 | *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages | 
|  | 69 | *  - flush_tlb_others(cpumask, mm, va) flushes TLBs on other cpus | 
|  | 70 | * | 
|  | 71 | * ..but the i386 has somewhat limited tlb flushing capabilities, | 
|  | 72 | * and page-granular flushes are available only on i486 and up. | 
|  | 73 | * | 
|  | 74 | * x86-64 can only flush individual pages or full VMs. For a range flush | 
|  | 75 | * we always do the full VM. Might be worth trying if for a small | 
|  | 76 | * range a few INVLPGs in a row are a win. | 
|  | 77 | */ | 
|  | 78 |  | 
|  | 79 | #ifndef CONFIG_SMP | 
|  | 80 |  | 
|  | 81 | #define flush_tlb() __flush_tlb() | 
|  | 82 | #define flush_tlb_all() __flush_tlb_all() | 
|  | 83 | #define local_flush_tlb() __flush_tlb() | 
|  | 84 |  | 
|  | 85 | static inline void flush_tlb_mm(struct mm_struct *mm) | 
|  | 86 | { | 
|  | 87 | if (mm == current->active_mm) | 
|  | 88 | __flush_tlb(); | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | static inline void flush_tlb_page(struct vm_area_struct *vma, | 
|  | 92 | unsigned long addr) | 
|  | 93 | { | 
|  | 94 | if (vma->vm_mm == current->active_mm) | 
|  | 95 | __flush_tlb_one(addr); | 
|  | 96 | } | 
|  | 97 |  | 
|  | 98 | static inline void flush_tlb_range(struct vm_area_struct *vma, | 
|  | 99 | unsigned long start, unsigned long end) | 
|  | 100 | { | 
|  | 101 | if (vma->vm_mm == current->active_mm) | 
|  | 102 | __flush_tlb(); | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | static inline void native_flush_tlb_others(const cpumask_t *cpumask, | 
|  | 106 | struct mm_struct *mm, | 
|  | 107 | unsigned long va) | 
|  | 108 | { | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 | #else  /* SMP */ | 
|  | 112 |  | 
|  | 113 | #include <asm/smp.h> | 
|  | 114 |  | 
|  | 115 | #define local_flush_tlb() __flush_tlb() | 
|  | 116 |  | 
|  | 117 | extern void flush_tlb_all(void); | 
|  | 118 | extern void flush_tlb_current_task(void); | 
|  | 119 | extern void flush_tlb_mm(struct mm_struct *); | 
|  | 120 | extern void flush_tlb_page(struct vm_area_struct *, unsigned long); | 
|  | 121 |  | 
|  | 122 | #define flush_tlb()	flush_tlb_current_task() | 
|  | 123 |  | 
|  | 124 | static inline void flush_tlb_range(struct vm_area_struct *vma, | 
|  | 125 | unsigned long start, unsigned long end) | 
|  | 126 | { | 
|  | 127 | flush_tlb_mm(vma->vm_mm); | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | void native_flush_tlb_others(const cpumask_t *cpumask, struct mm_struct *mm, | 
|  | 131 | unsigned long va); | 
|  | 132 |  | 
|  | 133 | #define TLBSTATE_OK	1 | 
|  | 134 | #define TLBSTATE_LAZY	2 | 
|  | 135 |  | 
|  | 136 | #ifdef CONFIG_X86_32 | 
| Joe Perches | 94cf8de | 2008-03-23 01:03:45 -0700 | [diff] [blame] | 137 | struct tlb_state { | 
| Thomas Gleixner | d291cf8 | 2008-01-30 13:30:35 +0100 | [diff] [blame] | 138 | struct mm_struct *active_mm; | 
|  | 139 | int state; | 
|  | 140 | char __cacheline_padding[L1_CACHE_BYTES-8]; | 
|  | 141 | }; | 
|  | 142 | DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate); | 
|  | 143 | #endif | 
|  | 144 |  | 
|  | 145 | #endif	/* SMP */ | 
|  | 146 |  | 
|  | 147 | #ifndef CONFIG_PARAVIRT | 
|  | 148 | #define flush_tlb_others(mask, mm, va)	native_flush_tlb_others(&mask, mm, va) | 
|  | 149 | #endif | 
|  | 150 |  | 
|  | 151 | static inline void flush_tlb_kernel_range(unsigned long start, | 
|  | 152 | unsigned long end) | 
|  | 153 | { | 
|  | 154 | flush_tlb_all(); | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | #endif /* _ASM_X86_TLBFLUSH_H */ |