xref: /openbmc/linux/arch/nios2/mm/mmu_context.c (revision e5451c8f8330e03ad3cfa16048b4daf961af434f)
1*71995e4dSLey Foon Tan /*
2*71995e4dSLey Foon Tan  * MMU context handling.
3*71995e4dSLey Foon Tan  *
4*71995e4dSLey Foon Tan  * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
5*71995e4dSLey Foon Tan  * Copyright (C) 2009 Wind River Systems Inc
6*71995e4dSLey Foon Tan  *   Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
7*71995e4dSLey Foon Tan  *
8*71995e4dSLey Foon Tan  * This file is subject to the terms and conditions of the GNU General Public
9*71995e4dSLey Foon Tan  * License.  See the file "COPYING" in the main directory of this archive
10*71995e4dSLey Foon Tan  * for more details.
11*71995e4dSLey Foon Tan  */
12*71995e4dSLey Foon Tan 
13*71995e4dSLey Foon Tan #include <linux/mm.h>
14*71995e4dSLey Foon Tan 
15*71995e4dSLey Foon Tan #include <asm/cpuinfo.h>
16*71995e4dSLey Foon Tan #include <asm/mmu_context.h>
17*71995e4dSLey Foon Tan #include <asm/tlb.h>
18*71995e4dSLey Foon Tan 
19*71995e4dSLey Foon Tan /* The pids position and mask in context */
20*71995e4dSLey Foon Tan #define PID_SHIFT	0
21*71995e4dSLey Foon Tan #define PID_BITS	(cpuinfo.tlb_pid_num_bits)
22*71995e4dSLey Foon Tan #define PID_MASK	((1UL << PID_BITS) - 1)
23*71995e4dSLey Foon Tan 
24*71995e4dSLey Foon Tan /* The versions position and mask in context */
25*71995e4dSLey Foon Tan #define VERSION_BITS	(32 - PID_BITS)
26*71995e4dSLey Foon Tan #define VERSION_SHIFT	(PID_SHIFT + PID_BITS)
27*71995e4dSLey Foon Tan #define VERSION_MASK	((1UL << VERSION_BITS) - 1)
28*71995e4dSLey Foon Tan 
29*71995e4dSLey Foon Tan /* Return the version part of a context */
30*71995e4dSLey Foon Tan #define CTX_VERSION(c)	(((c) >> VERSION_SHIFT) & VERSION_MASK)
31*71995e4dSLey Foon Tan 
32*71995e4dSLey Foon Tan /* Return the pid part of a context */
33*71995e4dSLey Foon Tan #define CTX_PID(c)	(((c) >> PID_SHIFT) & PID_MASK)
34*71995e4dSLey Foon Tan 
35*71995e4dSLey Foon Tan /* Value of the first context (version 1, pid 0) */
36*71995e4dSLey Foon Tan #define FIRST_CTX	((1UL << VERSION_SHIFT) | (0 << PID_SHIFT))
37*71995e4dSLey Foon Tan 
38*71995e4dSLey Foon Tan static mm_context_t next_mmu_context;
39*71995e4dSLey Foon Tan 
40*71995e4dSLey Foon Tan /*
41*71995e4dSLey Foon Tan  * Initialize MMU context management stuff.
42*71995e4dSLey Foon Tan  */
mmu_context_init(void)43*71995e4dSLey Foon Tan void __init mmu_context_init(void)
44*71995e4dSLey Foon Tan {
45*71995e4dSLey Foon Tan 	/* We need to set this here because the value depends on runtime data
46*71995e4dSLey Foon Tan 	 * from cpuinfo */
47*71995e4dSLey Foon Tan 	next_mmu_context = FIRST_CTX;
48*71995e4dSLey Foon Tan }
49*71995e4dSLey Foon Tan 
50*71995e4dSLey Foon Tan /*
51*71995e4dSLey Foon Tan  * Set new context (pid), keep way
52*71995e4dSLey Foon Tan  */
set_context(mm_context_t context)53*71995e4dSLey Foon Tan static void set_context(mm_context_t context)
54*71995e4dSLey Foon Tan {
55*71995e4dSLey Foon Tan 	set_mmu_pid(CTX_PID(context));
56*71995e4dSLey Foon Tan }
57*71995e4dSLey Foon Tan 
get_new_context(void)58*71995e4dSLey Foon Tan static mm_context_t get_new_context(void)
59*71995e4dSLey Foon Tan {
60*71995e4dSLey Foon Tan 	/* Return the next pid */
61*71995e4dSLey Foon Tan 	next_mmu_context += (1UL << PID_SHIFT);
62*71995e4dSLey Foon Tan 
63*71995e4dSLey Foon Tan 	/* If the pid field wraps around we increase the version and
64*71995e4dSLey Foon Tan 	 * flush the tlb */
65*71995e4dSLey Foon Tan 	if (unlikely(CTX_PID(next_mmu_context) == 0)) {
66*71995e4dSLey Foon Tan 		/* Version is incremented since the pid increment above
67*71995e4dSLey Foon Tan 		 * overflows info version */
68*71995e4dSLey Foon Tan 		flush_cache_all();
69*71995e4dSLey Foon Tan 		flush_tlb_all();
70*71995e4dSLey Foon Tan 	}
71*71995e4dSLey Foon Tan 
72*71995e4dSLey Foon Tan 	/* If the version wraps we start over with the first generation, we do
73*71995e4dSLey Foon Tan 	 * not need to flush the tlb here since it's always done above */
74*71995e4dSLey Foon Tan 	if (unlikely(CTX_VERSION(next_mmu_context) == 0))
75*71995e4dSLey Foon Tan 		next_mmu_context = FIRST_CTX;
76*71995e4dSLey Foon Tan 
77*71995e4dSLey Foon Tan 	return next_mmu_context;
78*71995e4dSLey Foon Tan }
79*71995e4dSLey Foon Tan 
switch_mm(struct mm_struct * prev,struct mm_struct * next,struct task_struct * tsk)80*71995e4dSLey Foon Tan void switch_mm(struct mm_struct *prev, struct mm_struct *next,
81*71995e4dSLey Foon Tan 	       struct task_struct *tsk)
82*71995e4dSLey Foon Tan {
83*71995e4dSLey Foon Tan 	unsigned long flags;
84*71995e4dSLey Foon Tan 
85*71995e4dSLey Foon Tan 	local_irq_save(flags);
86*71995e4dSLey Foon Tan 
87*71995e4dSLey Foon Tan 	/* If the process context we are swapping in has a different context
88*71995e4dSLey Foon Tan 	 * generation then we have it should get a new generation/pid */
89*71995e4dSLey Foon Tan 	if (unlikely(CTX_VERSION(next->context) !=
90*71995e4dSLey Foon Tan 		CTX_VERSION(next_mmu_context)))
91*71995e4dSLey Foon Tan 		next->context = get_new_context();
92*71995e4dSLey Foon Tan 
93*71995e4dSLey Foon Tan 	/* Save the current pgd so the fast tlb handler can find it */
94*71995e4dSLey Foon Tan 	pgd_current = next->pgd;
95*71995e4dSLey Foon Tan 
96*71995e4dSLey Foon Tan 	/* Set the current context */
97*71995e4dSLey Foon Tan 	set_context(next->context);
98*71995e4dSLey Foon Tan 
99*71995e4dSLey Foon Tan 	local_irq_restore(flags);
100*71995e4dSLey Foon Tan }
101*71995e4dSLey Foon Tan 
102*71995e4dSLey Foon Tan /*
103*71995e4dSLey Foon Tan  * After we have set current->mm to a new value, this activates
104*71995e4dSLey Foon Tan  * the context for the new mm so we see the new mappings.
105*71995e4dSLey Foon Tan  */
activate_mm(struct mm_struct * prev,struct mm_struct * next)106*71995e4dSLey Foon Tan void activate_mm(struct mm_struct *prev, struct mm_struct *next)
107*71995e4dSLey Foon Tan {
108*71995e4dSLey Foon Tan 	next->context = get_new_context();
109*71995e4dSLey Foon Tan 	set_context(next->context);
110*71995e4dSLey Foon Tan 	pgd_current = next->pgd;
111*71995e4dSLey Foon Tan }
112*71995e4dSLey Foon Tan 
get_pid_from_context(mm_context_t * context)113*71995e4dSLey Foon Tan unsigned long get_pid_from_context(mm_context_t *context)
114*71995e4dSLey Foon Tan {
115*71995e4dSLey Foon Tan 	return CTX_PID((*context));
116*71995e4dSLey Foon Tan }
117