]>
Commit | Line | Data |
---|---|---|
5f97f7f9 HS |
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 | ||
589ee628 IM |
15 | #include <linux/mm_types.h> |
16 | ||
5f97f7f9 | 17 | #include <asm/tlbflush.h> |
5f97f7f9 | 18 | #include <asm/sysreg.h> |
d6dd61c8 | 19 | #include <asm-generic/mm_hooks.h> |
5f97f7f9 HS |
20 | |
21 | /* | |
22 | * The MMU "context" consists of two things: | |
23 | * (a) TLB cache version | |
24 | * (b) ASID (Address Space IDentifier) | |
25 | */ | |
26 | #define MMU_CONTEXT_ASID_MASK 0x000000ff | |
27 | #define MMU_CONTEXT_VERSION_MASK 0xffffff00 | |
28 | #define MMU_CONTEXT_FIRST_VERSION 0x00000100 | |
29 | #define NO_CONTEXT 0 | |
30 | ||
31 | #define MMU_NO_ASID 0x100 | |
32 | ||
33 | /* Virtual Page Number mask */ | |
34 | #define MMU_VPN_MASK 0xfffff000 | |
35 | ||
36 | /* Cache of MMU context last used */ | |
37 | extern unsigned long mmu_context_cache; | |
38 | ||
39 | /* | |
40 | * Get MMU context if needed | |
41 | */ | |
42 | static inline void | |
43 | get_mmu_context(struct mm_struct *mm) | |
44 | { | |
45 | unsigned long mc = mmu_context_cache; | |
46 | ||
47 | if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0) | |
48 | /* It's up to date, do nothing */ | |
49 | return; | |
50 | ||
51 | /* It's old, we need to get new context with new version */ | |
52 | mc = ++mmu_context_cache; | |
53 | if (!(mc & MMU_CONTEXT_ASID_MASK)) { | |
54 | /* | |
55 | * We have exhausted all ASIDs of this version. | |
56 | * Flush the TLB and start new cycle. | |
57 | */ | |
58 | flush_tlb_all(); | |
59 | /* | |
60 | * Fix version. Note that we avoid version #0 | |
61 | * to distinguish NO_CONTEXT. | |
62 | */ | |
63 | if (!mc) | |
64 | mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION; | |
65 | } | |
66 | mm->context = mc; | |
67 | } | |
68 | ||
69 | /* | |
70 | * Initialize the context related info for a new mm_struct | |
71 | * instance. | |
72 | */ | |
73 | static inline int init_new_context(struct task_struct *tsk, | |
74 | struct mm_struct *mm) | |
75 | { | |
76 | mm->context = NO_CONTEXT; | |
77 | return 0; | |
78 | } | |
79 | ||
80 | /* | |
81 | * Destroy context related info for an mm_struct that is about | |
82 | * to be put to rest. | |
83 | */ | |
84 | static inline void destroy_context(struct mm_struct *mm) | |
85 | { | |
86 | /* Do nothing */ | |
87 | } | |
88 | ||
89 | static inline void set_asid(unsigned long asid) | |
90 | { | |
91 | /* XXX: We're destroying TLBEHI[8:31] */ | |
92 | sysreg_write(TLBEHI, asid & MMU_CONTEXT_ASID_MASK); | |
93 | cpu_sync_pipeline(); | |
94 | } | |
95 | ||
96 | static inline unsigned long get_asid(void) | |
97 | { | |
98 | unsigned long asid; | |
99 | ||
100 | asid = sysreg_read(TLBEHI); | |
101 | return asid & MMU_CONTEXT_ASID_MASK; | |
102 | } | |
103 | ||
104 | static inline void activate_context(struct mm_struct *mm) | |
105 | { | |
106 | get_mmu_context(mm); | |
107 | set_asid(mm->context & MMU_CONTEXT_ASID_MASK); | |
108 | } | |
109 | ||
110 | static inline void switch_mm(struct mm_struct *prev, | |
111 | struct mm_struct *next, | |
112 | struct task_struct *tsk) | |
113 | { | |
114 | if (likely(prev != next)) { | |
115 | unsigned long __pgdir = (unsigned long)next->pgd; | |
116 | ||
117 | sysreg_write(PTBR, __pgdir); | |
118 | activate_context(next); | |
119 | } | |
120 | } | |
121 | ||
122 | #define deactivate_mm(tsk,mm) do { } while(0) | |
123 | ||
124 | #define activate_mm(prev, next) switch_mm((prev), (next), NULL) | |
125 | ||
126 | static inline void | |
127 | enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) | |
128 | { | |
129 | } | |
130 | ||
131 | ||
132 | static inline void enable_mmu(void) | |
133 | { | |
134 | sysreg_write(MMUCR, (SYSREG_BIT(MMUCR_S) | |
135 | | SYSREG_BIT(E) | |
136 | | SYSREG_BIT(MMUCR_I))); | |
137 | nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); | |
138 | ||
139 | if (mmu_context_cache == NO_CONTEXT) | |
140 | mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; | |
141 | ||
142 | set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); | |
143 | } | |
144 | ||
145 | static inline void disable_mmu(void) | |
146 | { | |
147 | sysreg_write(MMUCR, SYSREG_BIT(MMUCR_S)); | |
148 | } | |
149 | ||
150 | #endif /* __ASM_AVR32_MMU_CONTEXT_H */ |