aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-01-14 16:15:05 -0500
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-02 05:01:28 -0400
commitcfd23e93a0289cf6711fd3877c5226658d87240a (patch)
tree1030f0ee5ccd59d1d80b2b5fdc892987f90fac8e
parentebe74597a55fef00edc80a414ef5c6477d035e0a (diff)
avr32: Store virtual addresses in the PGD
Instead of storing physical addresses along with page flags in the PGD, store virtual addresses and use NULL to indicate a not present second-level page table. A non-page-aligned page table indicates a bad PMD. This simplifies the TLB miss handler since it no longer has to check the Present bit and no longer has to convert the PGD entry from physical to virtual address. Instead, it has to check for a NULL entry, which is slightly cheaper than either. Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
-rw-r--r--arch/avr32/kernel/entry-avr32b.S45
-rw-r--r--arch/avr32/kernel/vmlinux.lds.S4
-rw-r--r--arch/avr32/mm/init.c4
-rw-r--r--include/asm-avr32/pgalloc.h18
-rw-r--r--include/asm-avr32/pgtable.h34
5 files changed, 51 insertions, 54 deletions
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index 050c006a7f0c..3cdd7071f35e 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -74,12 +74,6 @@ exception_vectors:
74 .align 2 74 .align 2
75 bral do_dtlb_modified 75 bral do_dtlb_modified
76 76
77 /*
78 * r0 : PGD/PT/PTE
79 * r1 : Offending address
80 * r2 : Scratch register
81 * r3 : Cause (5, 12 or 13)
82 */
83#define tlbmiss_save pushm r0-r3 77#define tlbmiss_save pushm r0-r3
84#define tlbmiss_restore popm r0-r3 78#define tlbmiss_restore popm r0-r3
85 79
@@ -108,17 +102,17 @@ tlb_miss_common:
108 bld r0, 31 102 bld r0, 31
109 brcs handle_vmalloc_miss 103 brcs handle_vmalloc_miss
110 104
111 /* First level lookup */ 105 /*
106 * First level lookup: The PGD contains virtual pointers to
107 * the second-level page tables, but they may be NULL if not
108 * present.
109 */
112pgtbl_lookup: 110pgtbl_lookup:
113 lsr r2, r0, PGDIR_SHIFT 111 lsr r2, r0, PGDIR_SHIFT
114 ld.w r3, r1[r2 << 2] 112 ld.w r3, r1[r2 << 2]
115 bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT 113 bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
116 bld r3, _PAGE_BIT_PRESENT 114 cp.w r3, 0
117 brcc page_table_not_present 115 breq page_table_not_present
118
119 /* Translate to virtual address in P1. */
120 andl r3, 0xf000
121 sbr r3, 31
122 116
123 /* Second level lookup */ 117 /* Second level lookup */
124 ld.w r2, r3[r1 << 2] 118 ld.w r2, r3[r1 << 2]
@@ -155,6 +149,19 @@ handle_vmalloc_miss:
155 orh r1, hi(swapper_pg_dir) 149 orh r1, hi(swapper_pg_dir)
156 rjmp pgtbl_lookup 150 rjmp pgtbl_lookup
157 151
152 /* The slow path of the TLB miss handler */
153 .align 2
154page_table_not_present:
155page_not_present:
156 tlbmiss_restore
157 sub sp, 4
158 stmts --sp, r0-lr
159 rcall save_full_context_ex
160 mfsr r12, SYSREG_ECR
161 mov r11, sp
162 rcall do_page_fault
163 rjmp ret_from_exception
164
158 165
159 /* --- System Call --- */ 166 /* --- System Call --- */
160 167
@@ -267,18 +274,6 @@ syscall_exit_work:
267 brcc syscall_exit_cont 274 brcc syscall_exit_cont
268 rjmp enter_monitor_mode 275 rjmp enter_monitor_mode
269 276
270 /* The slow path of the TLB miss handler */
271page_table_not_present:
272page_not_present:
273 tlbmiss_restore
274 sub sp, 4
275 stmts --sp, r0-lr
276 rcall save_full_context_ex
277 mfsr r12, SYSREG_ECR
278 mov r11, sp
279 rcall do_page_fault
280 rjmp ret_from_exception
281
282 /* This function expects to find offending PC in SYSREG_RAR_EX */ 277 /* This function expects to find offending PC in SYSREG_RAR_EX */
283 .type save_full_context_ex, @function 278 .type save_full_context_ex, @function
284 .align 2 279 .align 2
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index 033dd46bfa62..5d25d8eeb750 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -99,6 +99,10 @@ SECTIONS
99 */ 99 */
100 *(.data.init_task) 100 *(.data.init_task)
101 101
102 /* Then, the page-aligned data */
103 . = ALIGN(PAGE_SIZE);
104 *(.data.page_aligned)
105
102 /* Then, the cacheline aligned data */ 106 /* Then, the cacheline aligned data */
103 . = ALIGN(L1_CACHE_BYTES); 107 . = ALIGN(L1_CACHE_BYTES);
104 *(.data.cacheline_aligned) 108 *(.data.cacheline_aligned)
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index 0e77578c358d..3f90a87527bb 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -24,9 +24,11 @@
24#include <asm/setup.h> 24#include <asm/setup.h>
25#include <asm/sections.h> 25#include <asm/sections.h>
26 26
27#define __page_aligned __attribute__((section(".data.page_aligned")))
28
27DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); 29DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
28 30
29pgd_t swapper_pg_dir[PTRS_PER_PGD]; 31pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned;
30 32
31struct page *empty_zero_page; 33struct page *empty_zero_page;
32EXPORT_SYMBOL(empty_zero_page); 34EXPORT_SYMBOL(empty_zero_page);
diff --git a/include/asm-avr32/pgalloc.h b/include/asm-avr32/pgalloc.h
index 51fc1f6e4b17..5b768fc2388e 100644
--- a/include/asm-avr32/pgalloc.h
+++ b/include/asm-avr32/pgalloc.h
@@ -8,25 +8,27 @@
8#ifndef __ASM_AVR32_PGALLOC_H 8#ifndef __ASM_AVR32_PGALLOC_H
9#define __ASM_AVR32_PGALLOC_H 9#define __ASM_AVR32_PGALLOC_H
10 10
11#include <asm/processor.h>
12#include <linux/threads.h>
13#include <linux/slab.h>
14#include <linux/mm.h> 11#include <linux/mm.h>
12#include <linux/sched.h>
13#include <linux/slab.h>
15 14
16#define pmd_populate_kernel(mm, pmd, pte) \ 15static inline void pmd_populate_kernel(struct mm_struct *mm,
17 set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) 16 pmd_t *pmd, pte_t *pte)
17{
18 set_pmd(pmd, __pmd((unsigned long)pte));
19}
18 20
19static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd, 21static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
20 pgtable_t pte) 22 pgtable_t pte)
21{ 23{
22 set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte))); 24 set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
23} 25}
24#define pmd_pgtable(pmd) pmd_page(pmd) 26#define pmd_pgtable(pmd) pmd_page(pmd)
25 27
26/* 28/*
27 * Allocate and free page tables 29 * Allocate and free page tables
28 */ 30 */
29static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm) 31static inline pgd_t *pgd_alloc(struct mm_struct *mm)
30{ 32{
31 return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL); 33 return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
32} 34}
diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
index c0e5e29417df..fecdda16f444 100644
--- a/include/asm-avr32/pgtable.h
+++ b/include/asm-avr32/pgtable.h
@@ -129,13 +129,6 @@ extern struct page *empty_zero_page;
129 129
130#define _PAGE_FLAGS_CACHE_MASK (_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT) 130#define _PAGE_FLAGS_CACHE_MASK (_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT)
131 131
132/* TODO: Check for saneness */
133/* User-mode page table flags (to be set in a pgd or pmd entry) */
134#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
135 | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
136/* Kernel-mode page table flags */
137#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
138 | _PAGE_ACCESSED | _PAGE_DIRTY)
139/* Flags that may be modified by software */ 132/* Flags that may be modified by software */
140#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \ 133#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \
141 | _PAGE_FLAGS_CACHE_MASK) 134 | _PAGE_FLAGS_CACHE_MASK)
@@ -262,10 +255,14 @@ static inline pte_t pte_mkspecial(pte_t pte)
262} 255}
263 256
264#define pmd_none(x) (!pmd_val(x)) 257#define pmd_none(x) (!pmd_val(x))
265#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) 258#define pmd_present(x) (pmd_val(x))
266#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) 259
267#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) \ 260static inline void pmd_clear(pmd_t *pmdp)
268 != _KERNPG_TABLE) 261{
262 set_pmd(pmdp, __pmd(0));
263}
264
265#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK)
269 266
270/* 267/*
271 * Permanent address of a page. We don't support highmem, so this is 268 * Permanent address of a page. We don't support highmem, so this is
@@ -303,19 +300,16 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
303 300
304#define page_pte(page) page_pte_prot(page, __pgprot(0)) 301#define page_pte(page) page_pte_prot(page, __pgprot(0))
305 302
306#define pmd_page_vaddr(pmd) \ 303#define pmd_page_vaddr(pmd) pmd_val(pmd)
307 ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) 304#define pmd_page(pmd) (virt_to_page(pmd_val(pmd)))
308
309#define pmd_page(pmd) (phys_to_page(pmd_val(pmd)))
310 305
311/* to find an entry in a page-table-directory. */ 306/* to find an entry in a page-table-directory. */
312#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) 307#define pgd_index(address) (((address) >> PGDIR_SHIFT) \
313#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) 308 & (PTRS_PER_PGD - 1))
314#define pgd_offset_current(address) \ 309#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
315 ((pgd_t *)__mfsr(SYSREG_PTBR) + pgd_index(address))
316 310
317/* to find an entry in a kernel page-table-directory */ 311/* to find an entry in a kernel page-table-directory */
318#define pgd_offset_k(address) pgd_offset(&init_mm, address) 312#define pgd_offset_k(address) pgd_offset(&init_mm, address)
319 313
320/* Find an entry in the third-level page table.. */ 314/* Find an entry in the third-level page table.. */
321#define pte_index(address) \ 315#define pte_index(address) \