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