aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
authorGreg Ungerer <gerg@uclinux.org>2011-10-18 01:07:29 -0400
committerGreg Ungerer <gerg@uclinux.org>2011-12-29 19:20:34 -0500
commit83b73d6cb8301df32d9887c16c83490c4fd1f55f (patch)
treeeb2661eb9046976f03561982da442fb1a02fb2ef /arch/m68k
parent33d4bcca603c9174c0ee0e312fd3c6da03ff9e15 (diff)
m68k: ColdFire V4e MMU context support code
Add code to manage the context's of the ColdFire V4e MMU. This code is mostly taken from the Freescale 2.6.35 kernel BSP for MMU enabled ColdFire. Signed-off-by: Greg Ungerer <gerg@uclinux.org> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: Matt Waddel <mwaddel@yahoo.com> Acked-by: Kurt Mahan <kmahan@xmission.com>
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/include/asm/atomic.h10
-rw-r--r--arch/m68k/include/asm/mmu_context.h250
2 files changed, 211 insertions, 49 deletions
diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h
index 65c6be6c8180..4eba796c00d4 100644
--- a/arch/m68k/include/asm/atomic.h
+++ b/arch/m68k/include/asm/atomic.h
@@ -55,6 +55,16 @@ static inline int atomic_dec_and_test(atomic_t *v)
55 return c != 0; 55 return c != 0;
56} 56}
57 57
58static inline int atomic_dec_and_test_lt(atomic_t *v)
59{
60 char c;
61 __asm__ __volatile__(
62 "subql #1,%1; slt %0"
63 : "=d" (c), "=m" (*v)
64 : "m" (*v));
65 return c != 0;
66}
67
58static inline int atomic_inc_and_test(atomic_t *v) 68static inline int atomic_inc_and_test(atomic_t *v)
59{ 69{
60 char c; 70 char c;
diff --git a/arch/m68k/include/asm/mmu_context.h b/arch/m68k/include/asm/mmu_context.h
index 7d4341e55a99..dc3be991d634 100644
--- a/arch/m68k/include/asm/mmu_context.h
+++ b/arch/m68k/include/asm/mmu_context.h
@@ -8,7 +8,206 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
8} 8}
9 9
10#ifdef CONFIG_MMU 10#ifdef CONFIG_MMU
11#ifndef CONFIG_SUN3 11
12#if defined(CONFIG_COLDFIRE)
13
14#include <asm/atomic.h>
15#include <asm/bitops.h>
16#include <asm/mcfmmu.h>
17#include <asm/mmu.h>
18
19#define NO_CONTEXT 256
20#define LAST_CONTEXT 255
21#define FIRST_CONTEXT 1
22
23extern unsigned long context_map[];
24extern mm_context_t next_mmu_context;
25
26extern atomic_t nr_free_contexts;
27extern struct mm_struct *context_mm[LAST_CONTEXT+1];
28extern void steal_context(void);
29
30static inline void get_mmu_context(struct mm_struct *mm)
31{
32 mm_context_t ctx;
33
34 if (mm->context != NO_CONTEXT)
35 return;
36 while (atomic_dec_and_test_lt(&nr_free_contexts)) {
37 atomic_inc(&nr_free_contexts);
38 steal_context();
39 }
40 ctx = next_mmu_context;
41 while (test_and_set_bit(ctx, context_map)) {
42 ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
43 if (ctx > LAST_CONTEXT)
44 ctx = 0;
45 }
46 next_mmu_context = (ctx + 1) & LAST_CONTEXT;
47 mm->context = ctx;
48 context_mm[ctx] = mm;
49}
50
51/*
52 * Set up the context for a new address space.
53 */
54#define init_new_context(tsk, mm) (((mm)->context = NO_CONTEXT), 0)
55
56/*
57 * We're finished using the context for an address space.
58 */
59static inline void destroy_context(struct mm_struct *mm)
60{
61 if (mm->context != NO_CONTEXT) {
62 clear_bit(mm->context, context_map);
63 mm->context = NO_CONTEXT;
64 atomic_inc(&nr_free_contexts);
65 }
66}
67
68static inline void set_context(mm_context_t context, pgd_t *pgd)
69{
70 __asm__ __volatile__ ("movec %0,%%asid" : : "d" (context));
71}
72
73static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
74 struct task_struct *tsk)
75{
76 get_mmu_context(tsk->mm);
77 set_context(tsk->mm->context, next->pgd);
78}
79
80/*
81 * After we have set current->mm to a new value, this activates
82 * the context for the new mm so we see the new mappings.
83 */
84static inline void activate_mm(struct mm_struct *active_mm,
85 struct mm_struct *mm)
86{
87 get_mmu_context(mm);
88 set_context(mm->context, mm->pgd);
89}
90
91#define deactivate_mm(tsk, mm) do { } while (0)
92
93extern void mmu_context_init(void);
94#define prepare_arch_switch(next) load_ksp_mmu(next)
95
96static inline void load_ksp_mmu(struct task_struct *task)
97{
98 unsigned long flags;
99 struct mm_struct *mm;
100 int asid;
101 pgd_t *pgd;
102 pmd_t *pmd;
103 pte_t *pte;
104 unsigned long mmuar;
105
106 local_irq_save(flags);
107 mmuar = task->thread.ksp;
108
109 /* Search for a valid TLB entry, if one is found, don't remap */
110 mmu_write(MMUAR, mmuar);
111 mmu_write(MMUOR, MMUOR_STLB | MMUOR_ADR);
112 if (mmu_read(MMUSR) & MMUSR_HIT)
113 goto end;
114
115 if (mmuar >= PAGE_OFFSET) {
116 mm = &init_mm;
117 } else {
118 pr_info("load_ksp_mmu: non-kernel mm found: 0x%p\n", task->mm);
119 mm = task->mm;
120 }
121
122 if (!mm)
123 goto bug;
124
125 pgd = pgd_offset(mm, mmuar);
126 if (pgd_none(*pgd))
127 goto bug;
128
129 pmd = pmd_offset(pgd, mmuar);
130 if (pmd_none(*pmd))
131 goto bug;
132
133 pte = (mmuar >= PAGE_OFFSET) ? pte_offset_kernel(pmd, mmuar)
134 : pte_offset_map(pmd, mmuar);
135 if (pte_none(*pte) || !pte_present(*pte))
136 goto bug;
137
138 set_pte(pte, pte_mkyoung(*pte));
139 asid = mm->context & 0xff;
140 if (!pte_dirty(*pte) && mmuar <= PAGE_OFFSET)
141 set_pte(pte, pte_wrprotect(*pte));
142
143 mmu_write(MMUTR, (mmuar & PAGE_MASK) | (asid << MMUTR_IDN) |
144 (((int)(pte->pte) & (int)CF_PAGE_MMUTR_MASK)
145 >> CF_PAGE_MMUTR_SHIFT) | MMUTR_V);
146
147 mmu_write(MMUDR, (pte_val(*pte) & PAGE_MASK) |
148 ((pte->pte) & CF_PAGE_MMUDR_MASK) | MMUDR_SZ_8KB | MMUDR_X);
149
150 mmu_write(MMUOR, MMUOR_ACC | MMUOR_UAA);
151
152 goto end;
153
154bug:
155 pr_info("ksp load failed: mm=0x%p ksp=0x08%lx\n", mm, mmuar);
156end:
157 local_irq_restore(flags);
158}
159
160#elif defined(CONFIG_SUN3)
161#include <asm/sun3mmu.h>
162#include <linux/sched.h>
163
164extern unsigned long get_free_context(struct mm_struct *mm);
165extern void clear_context(unsigned long context);
166
167/* set the context for a new task to unmapped */
168static inline int init_new_context(struct task_struct *tsk,
169 struct mm_struct *mm)
170{
171 mm->context = SUN3_INVALID_CONTEXT;
172 return 0;
173}
174
175/* find the context given to this process, and if it hasn't already
176 got one, go get one for it. */
177static inline void get_mmu_context(struct mm_struct *mm)
178{
179 if (mm->context == SUN3_INVALID_CONTEXT)
180 mm->context = get_free_context(mm);
181}
182
183/* flush context if allocated... */
184static inline void destroy_context(struct mm_struct *mm)
185{
186 if (mm->context != SUN3_INVALID_CONTEXT)
187 clear_context(mm->context);
188}
189
190static inline void activate_context(struct mm_struct *mm)
191{
192 get_mmu_context(mm);
193 sun3_put_context(mm->context);
194}
195
196static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
197 struct task_struct *tsk)
198{
199 activate_context(tsk->mm);
200}
201
202#define deactivate_mm(tsk, mm) do { } while (0)
203
204static inline void activate_mm(struct mm_struct *prev_mm,
205 struct mm_struct *next_mm)
206{
207 activate_context(next_mm);
208}
209
210#else
12 211
13#include <asm/setup.h> 212#include <asm/setup.h>
14#include <asm/page.h> 213#include <asm/page.h>
@@ -103,55 +302,8 @@ static inline void activate_mm(struct mm_struct *prev_mm,
103 switch_mm_0460(next_mm); 302 switch_mm_0460(next_mm);
104} 303}
105 304
106#else /* CONFIG_SUN3 */
107#include <asm/sun3mmu.h>
108#include <linux/sched.h>
109
110extern unsigned long get_free_context(struct mm_struct *mm);
111extern void clear_context(unsigned long context);
112
113/* set the context for a new task to unmapped */
114static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
115{
116 mm->context = SUN3_INVALID_CONTEXT;
117 return 0;
118}
119
120/* find the context given to this process, and if it hasn't already
121 got one, go get one for it. */
122static inline void get_mmu_context(struct mm_struct *mm)
123{
124 if(mm->context == SUN3_INVALID_CONTEXT)
125 mm->context = get_free_context(mm);
126}
127
128/* flush context if allocated... */
129static inline void destroy_context(struct mm_struct *mm)
130{
131 if(mm->context != SUN3_INVALID_CONTEXT)
132 clear_context(mm->context);
133}
134
135static inline void activate_context(struct mm_struct *mm)
136{
137 get_mmu_context(mm);
138 sun3_put_context(mm->context);
139}
140
141static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
142{
143 activate_context(tsk->mm);
144}
145
146#define deactivate_mm(tsk,mm) do { } while (0)
147
148static inline void activate_mm(struct mm_struct *prev_mm,
149 struct mm_struct *next_mm)
150{
151 activate_context(next_mm);
152}
153
154#endif 305#endif
306
155#else /* !CONFIG_MMU */ 307#else /* !CONFIG_MMU */
156 308
157static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) 309static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)