Blame view

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