diff options
author | Greg Ungerer <gerg@uclinux.org> | 2011-10-14 02:11:38 -0400 |
---|---|---|
committer | Greg Ungerer <gerg@uclinux.org> | 2011-12-29 19:20:25 -0500 |
commit | 91521c2ea6e3d5a790df40988101ad099ddbf7c8 (patch) | |
tree | adeef29bb587ce55d5b7325b299831be45799c65 /arch/m68k/include | |
parent | bbc6f1ba509cf9cda42ce63bbd40afe577ab028e (diff) |
m68k: page table support definitions and code for ColdFire MMU
The ColdFire V4e MMU is nothing like any of the other m68k MMU's.
So we need to create a set of definitions and support routines
for the kernels paging functions.
This is largely taken from Freescales BSP code for this (though it
was a 2.6.25 kernel). I have cleaned it up alot from the original.
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/include')
-rw-r--r-- | arch/m68k/include/asm/mcf_pgtable.h | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/arch/m68k/include/asm/mcf_pgtable.h b/arch/m68k/include/asm/mcf_pgtable.h new file mode 100644 index 000000000000..756bde4fb4f8 --- /dev/null +++ b/arch/m68k/include/asm/mcf_pgtable.h | |||
@@ -0,0 +1,425 @@ | |||
1 | #ifndef _MCF_PGTABLE_H | ||
2 | #define _MCF_PGTABLE_H | ||
3 | |||
4 | #include <asm/mcfmmu.h> | ||
5 | #include <asm/page.h> | ||
6 | |||
7 | /* | ||
8 | * MMUDR bits, in proper place. We write these directly into the MMUDR | ||
9 | * after masking from the pte. | ||
10 | */ | ||
11 | #define CF_PAGE_LOCKED MMUDR_LK /* 0x00000002 */ | ||
12 | #define CF_PAGE_EXEC MMUDR_X /* 0x00000004 */ | ||
13 | #define CF_PAGE_WRITABLE MMUDR_W /* 0x00000008 */ | ||
14 | #define CF_PAGE_READABLE MMUDR_R /* 0x00000010 */ | ||
15 | #define CF_PAGE_SYSTEM MMUDR_SP /* 0x00000020 */ | ||
16 | #define CF_PAGE_COPYBACK MMUDR_CM_CCB /* 0x00000040 */ | ||
17 | #define CF_PAGE_NOCACHE MMUDR_CM_NCP /* 0x00000080 */ | ||
18 | |||
19 | #define CF_CACHEMASK (~MMUDR_CM_CCB) | ||
20 | #define CF_PAGE_MMUDR_MASK 0x000000fe | ||
21 | |||
22 | #define _PAGE_NOCACHE030 CF_PAGE_NOCACHE | ||
23 | |||
24 | /* | ||
25 | * MMUTR bits, need shifting down. | ||
26 | */ | ||
27 | #define CF_PAGE_MMUTR_MASK 0x00000c00 | ||
28 | #define CF_PAGE_MMUTR_SHIFT 10 | ||
29 | |||
30 | #define CF_PAGE_VALID (MMUTR_V << CF_PAGE_MMUTR_SHIFT) | ||
31 | #define CF_PAGE_SHARED (MMUTR_SG << CF_PAGE_MMUTR_SHIFT) | ||
32 | |||
33 | /* | ||
34 | * Fake bits, not implemented in CF, will get masked out before | ||
35 | * hitting hardware. | ||
36 | */ | ||
37 | #define CF_PAGE_DIRTY 0x00000001 | ||
38 | #define CF_PAGE_FILE 0x00000200 | ||
39 | #define CF_PAGE_ACCESSED 0x00001000 | ||
40 | |||
41 | #define _PAGE_CACHE040 0x020 /* 68040 cache mode, cachable, copyback */ | ||
42 | #define _PAGE_NOCACHE_S 0x040 /* 68040 no-cache mode, serialized */ | ||
43 | #define _PAGE_NOCACHE 0x060 /* 68040 cache mode, non-serialized */ | ||
44 | #define _PAGE_CACHE040W 0x000 /* 68040 cache mode, cachable, write-through */ | ||
45 | #define _DESCTYPE_MASK 0x003 | ||
46 | #define _CACHEMASK040 (~0x060) | ||
47 | #define _PAGE_GLOBAL040 0x400 /* 68040 global bit, used for kva descs */ | ||
48 | |||
49 | /* | ||
50 | * Externally used page protection values. | ||
51 | */ | ||
52 | #define _PAGE_PRESENT (CF_PAGE_VALID) | ||
53 | #define _PAGE_ACCESSED (CF_PAGE_ACCESSED) | ||
54 | #define _PAGE_DIRTY (CF_PAGE_DIRTY) | ||
55 | #define _PAGE_READWRITE (CF_PAGE_READABLE \ | ||
56 | | CF_PAGE_WRITABLE \ | ||
57 | | CF_PAGE_SYSTEM \ | ||
58 | | CF_PAGE_SHARED) | ||
59 | |||
60 | /* | ||
61 | * Compound page protection values. | ||
62 | */ | ||
63 | #define PAGE_NONE __pgprot(CF_PAGE_VALID \ | ||
64 | | CF_PAGE_ACCESSED) | ||
65 | |||
66 | #define PAGE_SHARED __pgprot(CF_PAGE_VALID \ | ||
67 | | CF_PAGE_ACCESSED \ | ||
68 | | CF_PAGE_SHARED) | ||
69 | |||
70 | #define PAGE_INIT __pgprot(CF_PAGE_VALID \ | ||
71 | | CF_PAGE_READABLE \ | ||
72 | | CF_PAGE_WRITABLE \ | ||
73 | | CF_PAGE_EXEC \ | ||
74 | | CF_PAGE_SYSTEM) | ||
75 | |||
76 | #define PAGE_KERNEL __pgprot(CF_PAGE_VALID \ | ||
77 | | CF_PAGE_ACCESSED \ | ||
78 | | CF_PAGE_READABLE \ | ||
79 | | CF_PAGE_WRITABLE \ | ||
80 | | CF_PAGE_EXEC \ | ||
81 | | CF_PAGE_SYSTEM) | ||
82 | |||
83 | #define PAGE_COPY __pgprot(CF_PAGE_VALID \ | ||
84 | | CF_PAGE_ACCESSED \ | ||
85 | | CF_PAGE_READABLE \ | ||
86 | | CF_PAGE_DIRTY) | ||
87 | |||
88 | /* | ||
89 | * Page protections for initialising protection_map. See mm/mmap.c | ||
90 | * for use. In general, the bit positions are xwr, and P-items are | ||
91 | * private, the S-items are shared. | ||
92 | */ | ||
93 | #define __P000 PAGE_NONE | ||
94 | #define __P001 __pgprot(CF_PAGE_VALID \ | ||
95 | | CF_PAGE_ACCESSED \ | ||
96 | | CF_PAGE_READABLE) | ||
97 | #define __P010 __pgprot(CF_PAGE_VALID \ | ||
98 | | CF_PAGE_ACCESSED \ | ||
99 | | CF_PAGE_WRITABLE) | ||
100 | #define __P011 __pgprot(CF_PAGE_VALID \ | ||
101 | | CF_PAGE_ACCESSED \ | ||
102 | | CF_PAGE_READABLE \ | ||
103 | | CF_PAGE_WRITABLE) | ||
104 | #define __P100 __pgprot(CF_PAGE_VALID \ | ||
105 | | CF_PAGE_ACCESSED \ | ||
106 | | CF_PAGE_EXEC) | ||
107 | #define __P101 __pgprot(CF_PAGE_VALID \ | ||
108 | | CF_PAGE_ACCESSED \ | ||
109 | | CF_PAGE_READABLE \ | ||
110 | | CF_PAGE_EXEC) | ||
111 | #define __P110 __pgprot(CF_PAGE_VALID \ | ||
112 | | CF_PAGE_ACCESSED \ | ||
113 | | CF_PAGE_WRITABLE \ | ||
114 | | CF_PAGE_EXEC) | ||
115 | #define __P111 __pgprot(CF_PAGE_VALID \ | ||
116 | | CF_PAGE_ACCESSED \ | ||
117 | | CF_PAGE_READABLE \ | ||
118 | | CF_PAGE_WRITABLE \ | ||
119 | | CF_PAGE_EXEC) | ||
120 | |||
121 | #define __S000 PAGE_NONE | ||
122 | #define __S001 __pgprot(CF_PAGE_VALID \ | ||
123 | | CF_PAGE_ACCESSED \ | ||
124 | | CF_PAGE_READABLE) | ||
125 | #define __S010 PAGE_SHARED | ||
126 | #define __S011 __pgprot(CF_PAGE_VALID \ | ||
127 | | CF_PAGE_ACCESSED \ | ||
128 | | CF_PAGE_SHARED \ | ||
129 | | CF_PAGE_READABLE) | ||
130 | #define __S100 __pgprot(CF_PAGE_VALID \ | ||
131 | | CF_PAGE_ACCESSED \ | ||
132 | | CF_PAGE_EXEC) | ||
133 | #define __S101 __pgprot(CF_PAGE_VALID \ | ||
134 | | CF_PAGE_ACCESSED \ | ||
135 | | CF_PAGE_READABLE \ | ||
136 | | CF_PAGE_EXEC) | ||
137 | #define __S110 __pgprot(CF_PAGE_VALID \ | ||
138 | | CF_PAGE_ACCESSED \ | ||
139 | | CF_PAGE_SHARED \ | ||
140 | | CF_PAGE_EXEC) | ||
141 | #define __S111 __pgprot(CF_PAGE_VALID \ | ||
142 | | CF_PAGE_ACCESSED \ | ||
143 | | CF_PAGE_SHARED \ | ||
144 | | CF_PAGE_READABLE \ | ||
145 | | CF_PAGE_EXEC) | ||
146 | |||
147 | #define PTE_MASK PAGE_MASK | ||
148 | #define CF_PAGE_CHG_MASK (PTE_MASK | CF_PAGE_ACCESSED | CF_PAGE_DIRTY) | ||
149 | |||
150 | #ifndef __ASSEMBLY__ | ||
151 | |||
152 | /* | ||
153 | * Conversion functions: convert a page and protection to a page entry, | ||
154 | * and a page entry and page directory to the page they refer to. | ||
155 | */ | ||
156 | #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) | ||
157 | |||
158 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | ||
159 | { | ||
160 | pte_val(pte) = (pte_val(pte) & CF_PAGE_CHG_MASK) | pgprot_val(newprot); | ||
161 | return pte; | ||
162 | } | ||
163 | |||
164 | #define pmd_set(pmdp, ptep) do {} while (0) | ||
165 | |||
166 | static inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp) | ||
167 | { | ||
168 | pgd_val(*pgdp) = virt_to_phys(pmdp); | ||
169 | } | ||
170 | |||
171 | #define __pte_page(pte) ((unsigned long) (pte_val(pte) & PAGE_MASK)) | ||
172 | #define __pmd_page(pmd) ((unsigned long) (pmd_val(pmd))) | ||
173 | |||
174 | static inline int pte_none(pte_t pte) | ||
175 | { | ||
176 | return !pte_val(pte); | ||
177 | } | ||
178 | |||
179 | static inline int pte_present(pte_t pte) | ||
180 | { | ||
181 | return pte_val(pte) & CF_PAGE_VALID; | ||
182 | } | ||
183 | |||
184 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, | ||
185 | pte_t *ptep) | ||
186 | { | ||
187 | pte_val(*ptep) = 0; | ||
188 | } | ||
189 | |||
190 | #define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT) | ||
191 | #define pte_page(pte) virt_to_page(__pte_page(pte)) | ||
192 | |||
193 | static inline int pmd_none2(pmd_t *pmd) { return !pmd_val(*pmd); } | ||
194 | #define pmd_none(pmd) pmd_none2(&(pmd)) | ||
195 | static inline int pmd_bad2(pmd_t *pmd) { return 0; } | ||
196 | #define pmd_bad(pmd) pmd_bad2(&(pmd)) | ||
197 | #define pmd_present(pmd) (!pmd_none2(&(pmd))) | ||
198 | static inline void pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; } | ||
199 | |||
200 | static inline int pgd_none(pgd_t pgd) { return 0; } | ||
201 | static inline int pgd_bad(pgd_t pgd) { return 0; } | ||
202 | static inline int pgd_present(pgd_t pgd) { return 1; } | ||
203 | static inline void pgd_clear(pgd_t *pgdp) {} | ||
204 | |||
205 | #define pte_ERROR(e) \ | ||
206 | printk(KERN_ERR "%s:%d: bad pte %08lx.\n", \ | ||
207 | __FILE__, __LINE__, pte_val(e)) | ||
208 | #define pmd_ERROR(e) \ | ||
209 | printk(KERN_ERR "%s:%d: bad pmd %08lx.\n", \ | ||
210 | __FILE__, __LINE__, pmd_val(e)) | ||
211 | #define pgd_ERROR(e) \ | ||
212 | printk(KERN_ERR "%s:%d: bad pgd %08lx.\n", \ | ||
213 | __FILE__, __LINE__, pgd_val(e)) | ||
214 | |||
215 | /* | ||
216 | * The following only work if pte_present() is true. | ||
217 | * Undefined behaviour if not... | ||
218 | * [we have the full set here even if they don't change from m68k] | ||
219 | */ | ||
220 | static inline int pte_read(pte_t pte) | ||
221 | { | ||
222 | return pte_val(pte) & CF_PAGE_READABLE; | ||
223 | } | ||
224 | |||
225 | static inline int pte_write(pte_t pte) | ||
226 | { | ||
227 | return pte_val(pte) & CF_PAGE_WRITABLE; | ||
228 | } | ||
229 | |||
230 | static inline int pte_exec(pte_t pte) | ||
231 | { | ||
232 | return pte_val(pte) & CF_PAGE_EXEC; | ||
233 | } | ||
234 | |||
235 | static inline int pte_dirty(pte_t pte) | ||
236 | { | ||
237 | return pte_val(pte) & CF_PAGE_DIRTY; | ||
238 | } | ||
239 | |||
240 | static inline int pte_young(pte_t pte) | ||
241 | { | ||
242 | return pte_val(pte) & CF_PAGE_ACCESSED; | ||
243 | } | ||
244 | |||
245 | static inline int pte_file(pte_t pte) | ||
246 | { | ||
247 | return pte_val(pte) & CF_PAGE_FILE; | ||
248 | } | ||
249 | |||
250 | static inline int pte_special(pte_t pte) | ||
251 | { | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static inline pte_t pte_wrprotect(pte_t pte) | ||
256 | { | ||
257 | pte_val(pte) &= ~CF_PAGE_WRITABLE; | ||
258 | return pte; | ||
259 | } | ||
260 | |||
261 | static inline pte_t pte_rdprotect(pte_t pte) | ||
262 | { | ||
263 | pte_val(pte) &= ~CF_PAGE_READABLE; | ||
264 | return pte; | ||
265 | } | ||
266 | |||
267 | static inline pte_t pte_exprotect(pte_t pte) | ||
268 | { | ||
269 | pte_val(pte) &= ~CF_PAGE_EXEC; | ||
270 | return pte; | ||
271 | } | ||
272 | |||
273 | static inline pte_t pte_mkclean(pte_t pte) | ||
274 | { | ||
275 | pte_val(pte) &= ~CF_PAGE_DIRTY; | ||
276 | return pte; | ||
277 | } | ||
278 | |||
279 | static inline pte_t pte_mkold(pte_t pte) | ||
280 | { | ||
281 | pte_val(pte) &= ~CF_PAGE_ACCESSED; | ||
282 | return pte; | ||
283 | } | ||
284 | |||
285 | static inline pte_t pte_mkwrite(pte_t pte) | ||
286 | { | ||
287 | pte_val(pte) |= CF_PAGE_WRITABLE; | ||
288 | return pte; | ||
289 | } | ||
290 | |||
291 | static inline pte_t pte_mkread(pte_t pte) | ||
292 | { | ||
293 | pte_val(pte) |= CF_PAGE_READABLE; | ||
294 | return pte; | ||
295 | } | ||
296 | |||
297 | static inline pte_t pte_mkexec(pte_t pte) | ||
298 | { | ||
299 | pte_val(pte) |= CF_PAGE_EXEC; | ||
300 | return pte; | ||
301 | } | ||
302 | |||
303 | static inline pte_t pte_mkdirty(pte_t pte) | ||
304 | { | ||
305 | pte_val(pte) |= CF_PAGE_DIRTY; | ||
306 | return pte; | ||
307 | } | ||
308 | |||
309 | static inline pte_t pte_mkyoung(pte_t pte) | ||
310 | { | ||
311 | pte_val(pte) |= CF_PAGE_ACCESSED; | ||
312 | return pte; | ||
313 | } | ||
314 | |||
315 | static inline pte_t pte_mknocache(pte_t pte) | ||
316 | { | ||
317 | pte_val(pte) |= 0x80 | (pte_val(pte) & ~0x40); | ||
318 | return pte; | ||
319 | } | ||
320 | |||
321 | static inline pte_t pte_mkcache(pte_t pte) | ||
322 | { | ||
323 | pte_val(pte) &= ~CF_PAGE_NOCACHE; | ||
324 | return pte; | ||
325 | } | ||
326 | |||
327 | static inline pte_t pte_mkspecial(pte_t pte) | ||
328 | { | ||
329 | return pte; | ||
330 | } | ||
331 | |||
332 | #define swapper_pg_dir kernel_pg_dir | ||
333 | extern pgd_t kernel_pg_dir[PTRS_PER_PGD]; | ||
334 | |||
335 | /* | ||
336 | * Find an entry in a pagetable directory. | ||
337 | */ | ||
338 | #define pgd_index(address) ((address) >> PGDIR_SHIFT) | ||
339 | #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) | ||
340 | |||
341 | /* | ||
342 | * Find an entry in a kernel pagetable directory. | ||
343 | */ | ||
344 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) | ||
345 | |||
346 | /* | ||
347 | * Find an entry in the second-level pagetable. | ||
348 | */ | ||
349 | static inline pmd_t *pmd_offset(pgd_t *pgd, unsigned long address) | ||
350 | { | ||
351 | return (pmd_t *) pgd; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Find an entry in the third-level pagetable. | ||
356 | */ | ||
357 | #define __pte_offset(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) | ||
358 | #define pte_offset_kernel(dir, address) \ | ||
359 | ((pte_t *) __pmd_page(*(dir)) + __pte_offset(address)) | ||
360 | |||
361 | /* | ||
362 | * Disable caching for page at given kernel virtual address. | ||
363 | */ | ||
364 | static inline void nocache_page(void *vaddr) | ||
365 | { | ||
366 | pgd_t *dir; | ||
367 | pmd_t *pmdp; | ||
368 | pte_t *ptep; | ||
369 | unsigned long addr = (unsigned long) vaddr; | ||
370 | |||
371 | dir = pgd_offset_k(addr); | ||
372 | pmdp = pmd_offset(dir, addr); | ||
373 | ptep = pte_offset_kernel(pmdp, addr); | ||
374 | *ptep = pte_mknocache(*ptep); | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * Enable caching for page at given kernel virtual address. | ||
379 | */ | ||
380 | static inline void cache_page(void *vaddr) | ||
381 | { | ||
382 | pgd_t *dir; | ||
383 | pmd_t *pmdp; | ||
384 | pte_t *ptep; | ||
385 | unsigned long addr = (unsigned long) vaddr; | ||
386 | |||
387 | dir = pgd_offset_k(addr); | ||
388 | pmdp = pmd_offset(dir, addr); | ||
389 | ptep = pte_offset_kernel(pmdp, addr); | ||
390 | *ptep = pte_mkcache(*ptep); | ||
391 | } | ||
392 | |||
393 | #define PTE_FILE_MAX_BITS 21 | ||
394 | #define PTE_FILE_SHIFT 11 | ||
395 | |||
396 | static inline unsigned long pte_to_pgoff(pte_t pte) | ||
397 | { | ||
398 | return pte_val(pte) >> PTE_FILE_SHIFT; | ||
399 | } | ||
400 | |||
401 | static inline pte_t pgoff_to_pte(unsigned pgoff) | ||
402 | { | ||
403 | return __pte((pgoff << PTE_FILE_SHIFT) + CF_PAGE_FILE); | ||
404 | } | ||
405 | |||
406 | /* | ||
407 | * Encode and de-code a swap entry (must be !pte_none(e) && !pte_present(e)) | ||
408 | */ | ||
409 | #define __swp_type(x) ((x).val & 0xFF) | ||
410 | #define __swp_offset(x) ((x).val >> PTE_FILE_SHIFT) | ||
411 | #define __swp_entry(typ, off) ((swp_entry_t) { (typ) | \ | ||
412 | (off << PTE_FILE_SHIFT) }) | ||
413 | #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) | ||
414 | #define __swp_entry_to_pte(x) (__pte((x).val)) | ||
415 | |||
416 | #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) | ||
417 | |||
418 | #define pte_offset_map(pmdp, addr) ((pte_t *)__pmd_page(*pmdp) + \ | ||
419 | __pte_offset(addr)) | ||
420 | #define pte_unmap(pte) ((void) 0) | ||
421 | #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) | ||
422 | #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) | ||
423 | |||
424 | #endif /* !__ASSEMBLY__ */ | ||
425 | #endif /* _MCF_PGTABLE_H */ | ||