ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-sh / mmu_context.h
1 /*
2  * Copyright (C) 1999 Niibe Yutaka
3  * Copyright (C) 2003 Paul Mundt
4  *
5  * ASID handling idea taken from MIPS implementation.
6  */
7 #ifndef __ASM_SH_MMU_CONTEXT_H
8 #define __ASM_SH_MMU_CONTEXT_H
9
10 #include <asm/cpu/mmu_context.h>
11 #include <asm/tlbflush.h>
12 #include <asm/pgalloc.h>
13 #include <asm/uaccess.h>
14 #include <asm/io.h>
15
16 /*
17  * The MMU "context" consists of two things:
18  *    (a) TLB cache version (or round, cycle whatever expression you like)
19  *    (b) ASID (Address Space IDentifier)
20  */
21
22 /*
23  * Cache of MMU context last used.
24  */
25 extern unsigned long mmu_context_cache;
26
27 #define MMU_CONTEXT_ASID_MASK           0x000000ff
28 #define MMU_CONTEXT_VERSION_MASK        0xffffff00
29 #define MMU_CONTEXT_FIRST_VERSION       0x00000100
30 #define NO_CONTEXT                      0
31
32 /* ASID is 8-bit value, so it can't be 0x100 */
33 #define MMU_NO_ASID                     0x100
34
35 /*
36  * Virtual Page Number mask
37  */
38 #define MMU_VPN_MASK    0xfffff000
39
40 #ifdef CONFIG_MMU
41 /*
42  * Get MMU context if needed.
43  */
44 static __inline__ void
45 get_mmu_context(struct mm_struct *mm)
46 {
47         extern void flush_tlb_all(void);
48         unsigned long mc = mmu_context_cache;
49
50         /* Check if we have old version of context. */
51         if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
52                 /* It's up to date, do nothing */
53                 return;
54
55         /* It's old, we need to get new context with new version. */
56         mc = ++mmu_context_cache;
57         if (!(mc & MMU_CONTEXT_ASID_MASK)) {
58                 /*
59                  * We exhaust ASID of this version.
60                  * Flush all TLB and start new cycle.
61                  */
62                 flush_tlb_all();
63                 /*
64                  * Fix version; Note that we avoid version #0
65                  * to distingush NO_CONTEXT.
66                  */
67                 if (!mc)
68                         mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
69         }
70         mm->context = mc;
71 }
72
73 /*
74  * Initialize the context related info for a new mm_struct
75  * instance.
76  */
77 static __inline__ int init_new_context(struct task_struct *tsk,
78                                        struct mm_struct *mm)
79 {
80         mm->context = NO_CONTEXT;
81
82         return 0;
83 }
84
85 /*
86  * Destroy context related info for an mm_struct that is about
87  * to be put to rest.
88  */
89 static __inline__ void destroy_context(struct mm_struct *mm)
90 {
91         /* Do nothing */
92 }
93
94 static __inline__ void set_asid(unsigned long asid)
95 {
96         unsigned long __dummy;
97
98         __asm__ __volatile__ ("mov.l    %2, %0\n\t"
99                               "and      %3, %0\n\t"
100                               "or       %1, %0\n\t"
101                               "mov.l    %0, %2"
102                               : "=&r" (__dummy)
103                               : "r" (asid), "m" (__m(MMU_PTEH)),
104                                 "r" (0xffffff00));
105 }
106
107 static __inline__ unsigned long get_asid(void)
108 {
109         unsigned long asid;
110
111         __asm__ __volatile__ ("mov.l    %1, %0"
112                               : "=r" (asid)
113                               : "m" (__m(MMU_PTEH)));
114         asid &= MMU_CONTEXT_ASID_MASK;
115         return asid;
116 }
117
118 /*
119  * After we have set current->mm to a new value, this activates
120  * the context for the new mm so we see the new mappings.
121  */
122 static __inline__ void activate_context(struct mm_struct *mm)
123 {
124         get_mmu_context(mm);
125         set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
126 }
127
128 /* MMU_TTB can be used for optimizing the fault handling.
129    (Currently not used) */
130 static __inline__ void switch_mm(struct mm_struct *prev,
131                                  struct mm_struct *next,
132                                  struct task_struct *tsk)
133 {
134         if (likely(prev != next)) {
135                 unsigned long __pgdir = (unsigned long)next->pgd;
136
137                 __asm__ __volatile__("mov.l     %0, %1"
138                                      : /* no output */
139                                      : "r" (__pgdir), "m" (__m(MMU_TTB)));
140                 activate_context(next);
141         }
142 }
143
144 #define deactivate_mm(tsk,mm)   do { } while (0)
145
146 #define activate_mm(prev, next) \
147         switch_mm((prev),(next),NULL)
148
149 static __inline__ void
150 enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
151 {
152 }
153 #else /* !CONFIG_MMU */
154 #define get_mmu_context(mm)             do { } while (0)
155 #define init_new_context(tsk,mm)        (0)
156 #define destroy_context(mm)             do { } while (0)
157 #define set_asid(asid)                  do { } while (0)
158 #define get_asid()                      (0)
159 #define activate_context(mm)            do { } while (0)
160 #define switch_mm(prev,next,tsk)        do { } while (0)
161 #define deactivate_mm(tsk,mm)           do { } while (0)
162 #define activate_mm(prev,next)          do { } while (0)
163 #define enter_lazy_tlb(mm,tsk)          do { } while (0)
164 #endif /* CONFIG_MMU */
165
166 #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4)
167 /*
168  * If this processor has an MMU, we need methods to turn it off/on ..
169  * paging_init() will also have to be updated for the processor in
170  * question.
171  */
172 static inline void enable_mmu(void)
173 {
174         /* Enable MMU */
175         ctrl_outl(MMU_CONTROL_INIT, MMUCR);
176
177         /* The manual suggests doing some nops after turning on the MMU */
178         __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop\n\t");
179
180         if (mmu_context_cache == NO_CONTEXT)
181                 mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
182
183         set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
184 }
185
186 static inline void disable_mmu(void)
187 {
188         unsigned long cr;
189
190         cr = ctrl_inl(MMUCR);
191         cr &= ~MMU_CONTROL_INIT;
192         ctrl_outl(cr, MMUCR);
193         __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop\n\t");
194 }
195 #else
196 /*
197  * MMU control handlers for processors lacking memory
198  * management hardware.
199  */
200 #define enable_mmu()    do { BUG(); } while (0)
201 #define disable_mmu()   do { BUG(); } while (0)
202 #endif
203
204 #endif /* __ASM_SH_MMU_CONTEXT_H */