Merge commit 'upstream/master'
[pandora-kernel.git] / include / asm-avr32 / mmu_context.h
1 /*
2  * Copyright (C) 2004-2006 Atmel Corporation
3  *
4  * ASID handling taken from SH implementation.
5  *   Copyright (C) 1999 Niibe Yutaka
6  *   Copyright (C) 2003 Paul Mundt
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 #ifndef __ASM_AVR32_MMU_CONTEXT_H
13 #define __ASM_AVR32_MMU_CONTEXT_H
14
15 #include <asm/tlbflush.h>
16 #include <asm/sysreg.h>
17 #include <asm-generic/mm_hooks.h>
18
19 /*
20  * The MMU "context" consists of two things:
21  *    (a) TLB cache version
22  *    (b) ASID (Address Space IDentifier)
23  */
24 #define MMU_CONTEXT_ASID_MASK           0x000000ff
25 #define MMU_CONTEXT_VERSION_MASK        0xffffff00
26 #define MMU_CONTEXT_FIRST_VERSION       0x00000100
27 #define NO_CONTEXT                      0
28
29 #define MMU_NO_ASID                     0x100
30
31 /* Virtual Page Number mask */
32 #define MMU_VPN_MASK    0xfffff000
33
34 /* Cache of MMU context last used */
35 extern unsigned long mmu_context_cache;
36
37 /*
38  * Get MMU context if needed
39  */
40 static inline void
41 get_mmu_context(struct mm_struct *mm)
42 {
43         unsigned long mc = mmu_context_cache;
44
45         if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
46                 /* It's up to date, do nothing */
47                 return;
48
49         /* It's old, we need to get new context with new version */
50         mc = ++mmu_context_cache;
51         if (!(mc & MMU_CONTEXT_ASID_MASK)) {
52                 /*
53                  * We have exhausted all ASIDs of this version.
54                  * Flush the TLB and start new cycle.
55                  */
56                 flush_tlb_all();
57                 /*
58                  * Fix version. Note that we avoid version #0
59                  * to distinguish NO_CONTEXT.
60                  */
61                 if (!mc)
62                         mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
63         }
64         mm->context = mc;
65 }
66
67 /*
68  * Initialize the context related info for a new mm_struct
69  * instance.
70  */
71 static inline int init_new_context(struct task_struct *tsk,
72                                        struct mm_struct *mm)
73 {
74         mm->context = NO_CONTEXT;
75         return 0;
76 }
77
78 /*
79  * Destroy context related info for an mm_struct that is about
80  * to be put to rest.
81  */
82 static inline void destroy_context(struct mm_struct *mm)
83 {
84         /* Do nothing */
85 }
86
87 static inline void set_asid(unsigned long asid)
88 {
89         /* XXX: We're destroying TLBEHI[8:31] */
90         sysreg_write(TLBEHI, asid & MMU_CONTEXT_ASID_MASK);
91         cpu_sync_pipeline();
92 }
93
94 static inline unsigned long get_asid(void)
95 {
96         unsigned long asid;
97
98         asid = sysreg_read(TLBEHI);
99         return asid & MMU_CONTEXT_ASID_MASK;
100 }
101
102 static inline void activate_context(struct mm_struct *mm)
103 {
104         get_mmu_context(mm);
105         set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
106 }
107
108 static inline void switch_mm(struct mm_struct *prev,
109                                  struct mm_struct *next,
110                                  struct task_struct *tsk)
111 {
112         if (likely(prev != next)) {
113                 unsigned long __pgdir = (unsigned long)next->pgd;
114
115                 sysreg_write(PTBR, __pgdir);
116                 activate_context(next);
117         }
118 }
119
120 #define deactivate_mm(tsk,mm) do { } while(0)
121
122 #define activate_mm(prev, next) switch_mm((prev), (next), NULL)
123
124 static inline void
125 enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
126 {
127 }
128
129
130 static inline void enable_mmu(void)
131 {
132         sysreg_write(MMUCR, (SYSREG_BIT(MMUCR_S)
133                              | SYSREG_BIT(E)
134                              | SYSREG_BIT(MMUCR_I)));
135         nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
136
137         if (mmu_context_cache == NO_CONTEXT)
138                 mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
139
140         set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
141 }
142
143 static inline void disable_mmu(void)
144 {
145         sysreg_write(MMUCR, SYSREG_BIT(MMUCR_S));
146 }
147
148 #endif /* __ASM_AVR32_MMU_CONTEXT_H */