~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/include/asm/mmu_context.h

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/errno.h>
 15 #include <linux/sched.h>
 16 #include <linux/mm_types.h>
 17 #include <linux/smp.h>
 18 #include <linux/slab.h>
 19 
 20 #include <asm/barrier.h>
 21 #include <asm/cacheflush.h>
 22 #include <asm/dsemul.h>
 23 #include <asm/ginvt.h>
 24 #include <asm/hazards.h>
 25 #include <asm/tlbflush.h>
 26 #include <asm-generic/mm_hooks.h>
 27 
 28 #define htw_set_pwbase(pgd)                                             \
 29 do {                                                                    \
 30         if (cpu_has_htw) {                                              \
 31                 write_c0_pwbase(pgd);                                   \
 32                 back_to_back_c0_hazard();                               \
 33         }                                                               \
 34 } while (0)
 35 
 36 extern void tlbmiss_handler_setup_pgd(unsigned long);
 37 extern char tlbmiss_handler_setup_pgd_end[];
 38 
 39 /* Note: This is also implemented with uasm in arch/mips/kvm/entry.c */
 40 #define TLBMISS_HANDLER_SETUP_PGD(pgd)                                  \
 41 do {                                                                    \
 42         tlbmiss_handler_setup_pgd((unsigned long)(pgd));                \
 43         htw_set_pwbase((unsigned long)pgd);                             \
 44 } while (0)
 45 
 46 #ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 47 
 48 #define TLBMISS_HANDLER_RESTORE()                                       \
 49         write_c0_xcontext((unsigned long) smp_processor_id() <<         \
 50                           SMP_CPUID_REGSHIFT)
 51 
 52 #define TLBMISS_HANDLER_SETUP()                                         \
 53         do {                                                            \
 54                 TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir);              \
 55                 TLBMISS_HANDLER_RESTORE();                              \
 56         } while (0)
 57 
 58 #else /* !CONFIG_MIPS_PGD_C0_CONTEXT: using  pgd_current*/
 59 
 60 /*
 61  * For the fast tlb miss handlers, we keep a per cpu array of pointers
 62  * to the current pgd for each processor. Also, the proc. id is stuffed
 63  * into the context register.
 64  */
 65 extern unsigned long pgd_current[];
 66 
 67 #define TLBMISS_HANDLER_RESTORE()                                       \
 68         write_c0_context((unsigned long) smp_processor_id() <<          \
 69                          SMP_CPUID_REGSHIFT)
 70 
 71 #define TLBMISS_HANDLER_SETUP()                                         \
 72         TLBMISS_HANDLER_RESTORE();                                      \
 73         back_to_back_c0_hazard();                                       \
 74         TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
 75 #endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/
 76 
 77 /*
 78  * The ginvt instruction will invalidate wired entries when its type field
 79  * targets anything other than the entire TLB. That means that if we were to
 80  * allow the kernel to create wired entries with the MMID of current->active_mm
 81  * then those wired entries could be invalidated when we later use ginvt to
 82  * invalidate TLB entries with that MMID.
 83  *
 84  * In order to prevent ginvt from trashing wired entries, we reserve one MMID
 85  * for use by the kernel when creating wired entries. This MMID will never be
 86  * assigned to a struct mm, and we'll never target it with a ginvt instruction.
 87  */
 88 #define MMID_KERNEL_WIRED       0
 89 
 90 /*
 91  *  All unused by hardware upper bits will be considered
 92  *  as a software asid extension.
 93  */
 94 static inline u64 asid_version_mask(unsigned int cpu)
 95 {
 96         unsigned long asid_mask = cpu_asid_mask(&cpu_data[cpu]);
 97 
 98         return ~(u64)(asid_mask | (asid_mask - 1));
 99 }
100 
101 static inline u64 asid_first_version(unsigned int cpu)
102 {
103         return ~asid_version_mask(cpu) + 1;
104 }
105 
106 static inline u64 cpu_context(unsigned int cpu, const struct mm_struct *mm)
107 {
108         if (cpu_has_mmid)
109                 return atomic64_read(&mm->context.mmid);
110 
111         return mm->context.asid[cpu];
112 }
113 
114 static inline void set_cpu_context(unsigned int cpu,
115                                    struct mm_struct *mm, u64 ctx)
116 {
117         if (cpu_has_mmid)
118                 atomic64_set(&mm->context.mmid, ctx);
119         else
120                 mm->context.asid[cpu] = ctx;
121 }
122 
123 #define asid_cache(cpu)         (cpu_data[cpu].asid_cache)
124 #define cpu_asid(cpu, mm) \
125         (cpu_context((cpu), (mm)) & cpu_asid_mask(&cpu_data[cpu]))
126 
127 extern void get_new_mmu_context(struct mm_struct *mm);
128 extern void check_mmu_context(struct mm_struct *mm);
129 extern void check_switch_mmu_context(struct mm_struct *mm);
130 
131 /*
132  * Initialize the context related info for a new mm_struct
133  * instance.
134  */
135 #define init_new_context init_new_context
136 static inline int
137 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
138 {
139         int i;
140 
141         if (cpu_has_mmid) {
142                 set_cpu_context(0, mm, 0);
143         } else {
144                 for_each_possible_cpu(i)
145                         set_cpu_context(i, mm, 0);
146         }
147 
148         mm->context.bd_emupage_allocmap = NULL;
149         spin_lock_init(&mm->context.bd_emupage_lock);
150         init_waitqueue_head(&mm->context.bd_emupage_queue);
151 
152         return 0;
153 }
154 
155 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
156                              struct task_struct *tsk)
157 {
158         unsigned int cpu = smp_processor_id();
159         unsigned long flags;
160         local_irq_save(flags);
161 
162         htw_stop();
163         check_switch_mmu_context(next);
164 
165         /*
166          * Mark current->active_mm as not "active" anymore.
167          * We don't want to mislead possible IPI tlb flush routines.
168          */
169         cpumask_clear_cpu(cpu, mm_cpumask(prev));
170         cpumask_set_cpu(cpu, mm_cpumask(next));
171         htw_start();
172 
173         local_irq_restore(flags);
174 }
175 
176 /*
177  * Destroy context related info for an mm_struct that is about
178  * to be put to rest.
179  */
180 #define destroy_context destroy_context
181 static inline void destroy_context(struct mm_struct *mm)
182 {
183         dsemul_mm_cleanup(mm);
184 }
185 
186 static inline void
187 drop_mmu_context(struct mm_struct *mm)
188 {
189         unsigned long flags;
190         unsigned int cpu;
191         u32 old_mmid;
192         u64 ctx;
193 
194         local_irq_save(flags);
195 
196         cpu = smp_processor_id();
197         ctx = cpu_context(cpu, mm);
198 
199         if (!ctx) {
200                 /* no-op */
201         } else if (cpu_has_mmid) {
202                 /*
203                  * Globally invalidating TLB entries associated with the MMID
204                  * is pretty cheap using the GINVT instruction, so we'll do
205                  * that rather than incur the overhead of allocating a new
206                  * MMID. The latter would be especially difficult since MMIDs
207                  * are global & other CPUs may be actively using ctx.
208                  */
209                 htw_stop();
210                 old_mmid = read_c0_memorymapid();
211                 write_c0_memorymapid(ctx & cpu_asid_mask(&cpu_data[cpu]));
212                 mtc0_tlbw_hazard();
213                 ginvt_mmid();
214                 sync_ginv();
215                 write_c0_memorymapid(old_mmid);
216                 instruction_hazard();
217                 htw_start();
218         } else if (cpumask_test_cpu(cpu, mm_cpumask(mm))) {
219                 /*
220                  * mm is currently active, so we can't really drop it.
221                  * Instead we bump the ASID.
222                  */
223                 htw_stop();
224                 get_new_mmu_context(mm);
225                 write_c0_entryhi(cpu_asid(cpu, mm));
226                 htw_start();
227         } else {
228                 /* will get a new context next time */
229                 set_cpu_context(cpu, mm, 0);
230         }
231 
232         local_irq_restore(flags);
233 }
234 
235 #include <asm-generic/mmu_context.h>
236 
237 #endif /* _ASM_MMU_CONTEXT_H */
238 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php