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

Configure Feed

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

at v2.6.12-rc4 196 lines 4.9 kB view raw
1/* 2 * Switch a MMU context. 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file "COPYING" in the main directory of this archive 6 * for more details. 7 * 8 * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle 9 * Copyright (C) 1999 Silicon Graphics, Inc. 10 */ 11#ifndef _ASM_MMU_CONTEXT_H 12#define _ASM_MMU_CONTEXT_H 13 14#include <linux/config.h> 15#include <linux/errno.h> 16#include <linux/sched.h> 17#include <linux/slab.h> 18#include <asm/cacheflush.h> 19#include <asm/tlbflush.h> 20 21/* 22 * For the fast tlb miss handlers, we keep a per cpu array of pointers 23 * to the current pgd for each processor. Also, the proc. id is stuffed 24 * into the context register. 25 */ 26extern unsigned long pgd_current[]; 27 28#define TLBMISS_HANDLER_SETUP_PGD(pgd) \ 29 pgd_current[smp_processor_id()] = (unsigned long)(pgd) 30 31#ifdef CONFIG_MIPS32 32#define TLBMISS_HANDLER_SETUP() \ 33 write_c0_context((unsigned long) smp_processor_id() << 23); \ 34 TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) 35#endif 36#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64) 37#define TLBMISS_HANDLER_SETUP() \ 38 write_c0_context((unsigned long) &pgd_current[smp_processor_id()] << 23); \ 39 TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) 40#endif 41#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64) 42#define TLBMISS_HANDLER_SETUP() \ 43 write_c0_context((unsigned long) smp_processor_id() << 23); \ 44 TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) 45#endif 46 47#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) 48 49#define ASID_INC 0x40 50#define ASID_MASK 0xfc0 51 52#elif defined(CONFIG_CPU_R8000) 53 54#define ASID_INC 0x10 55#define ASID_MASK 0xff0 56 57#elif defined(CONFIG_CPU_RM9000) 58 59#define ASID_INC 0x1 60#define ASID_MASK 0xfff 61 62#else /* FIXME: not correct for R6000 */ 63 64#define ASID_INC 0x1 65#define ASID_MASK 0xff 66 67#endif 68 69#define cpu_context(cpu, mm) ((mm)->context[cpu]) 70#define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) 71#define asid_cache(cpu) (cpu_data[cpu].asid_cache) 72 73static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) 74{ 75} 76 77/* 78 * All unused by hardware upper bits will be considered 79 * as a software asid extension. 80 */ 81#define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1))) 82#define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1) 83 84static inline void 85get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) 86{ 87 unsigned long asid = asid_cache(cpu); 88 89 if (! ((asid += ASID_INC) & ASID_MASK) ) { 90 if (cpu_has_vtag_icache) 91 flush_icache_all(); 92 local_flush_tlb_all(); /* start new asid cycle */ 93 if (!asid) /* fix version if needed */ 94 asid = ASID_FIRST_VERSION; 95 } 96 cpu_context(cpu, mm) = asid_cache(cpu) = asid; 97} 98 99/* 100 * Initialize the context related info for a new mm_struct 101 * instance. 102 */ 103static inline int 104init_new_context(struct task_struct *tsk, struct mm_struct *mm) 105{ 106 int i; 107 108 for (i = 0; i < num_online_cpus(); i++) 109 cpu_context(i, mm) = 0; 110 111 return 0; 112} 113 114static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 115 struct task_struct *tsk) 116{ 117 unsigned int cpu = smp_processor_id(); 118 unsigned long flags; 119 120 local_irq_save(flags); 121 122 /* Check if our ASID is of an older version and thus invalid */ 123 if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) 124 get_new_mmu_context(next, cpu); 125 126 write_c0_entryhi(cpu_context(cpu, next)); 127 TLBMISS_HANDLER_SETUP_PGD(next->pgd); 128 129 /* 130 * Mark current->active_mm as not "active" anymore. 131 * We don't want to mislead possible IPI tlb flush routines. 132 */ 133 cpu_clear(cpu, prev->cpu_vm_mask); 134 cpu_set(cpu, next->cpu_vm_mask); 135 136 local_irq_restore(flags); 137} 138 139/* 140 * Destroy context related info for an mm_struct that is about 141 * to be put to rest. 142 */ 143static inline void destroy_context(struct mm_struct *mm) 144{ 145} 146 147#define deactivate_mm(tsk,mm) do { } while (0) 148 149/* 150 * After we have set current->mm to a new value, this activates 151 * the context for the new mm so we see the new mappings. 152 */ 153static inline void 154activate_mm(struct mm_struct *prev, struct mm_struct *next) 155{ 156 unsigned long flags; 157 unsigned int cpu = smp_processor_id(); 158 159 local_irq_save(flags); 160 161 /* Unconditionally get a new ASID. */ 162 get_new_mmu_context(next, cpu); 163 164 write_c0_entryhi(cpu_context(cpu, next)); 165 TLBMISS_HANDLER_SETUP_PGD(next->pgd); 166 167 /* mark mmu ownership change */ 168 cpu_clear(cpu, prev->cpu_vm_mask); 169 cpu_set(cpu, next->cpu_vm_mask); 170 171 local_irq_restore(flags); 172} 173 174/* 175 * If mm is currently active_mm, we can't really drop it. Instead, 176 * we will get a new one for it. 177 */ 178static inline void 179drop_mmu_context(struct mm_struct *mm, unsigned cpu) 180{ 181 unsigned long flags; 182 183 local_irq_save(flags); 184 185 if (cpu_isset(cpu, mm->cpu_vm_mask)) { 186 get_new_mmu_context(mm, cpu); 187 write_c0_entryhi(cpu_asid(cpu, mm)); 188 } else { 189 /* will get a new context next time */ 190 cpu_context(cpu, mm) = 0; 191 } 192 193 local_irq_restore(flags); 194} 195 196#endif /* _ASM_MMU_CONTEXT_H */