diff options
-rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 42 | ||||
-rw-r--r-- | include/asm-avr32/pgalloc.h | 14 |
2 files changed, 42 insertions, 14 deletions
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 3cdd7071f35e..2b398cae110c 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S | |||
@@ -98,10 +98,6 @@ tlb_miss_common: | |||
98 | mfsr r0, SYSREG_TLBEAR | 98 | mfsr r0, SYSREG_TLBEAR |
99 | mfsr r1, SYSREG_PTBR | 99 | mfsr r1, SYSREG_PTBR |
100 | 100 | ||
101 | /* Is it the vmalloc space? */ | ||
102 | bld r0, 31 | ||
103 | brcs handle_vmalloc_miss | ||
104 | |||
105 | /* | 101 | /* |
106 | * First level lookup: The PGD contains virtual pointers to | 102 | * First level lookup: The PGD contains virtual pointers to |
107 | * the second-level page tables, but they may be NULL if not | 103 | * the second-level page tables, but they may be NULL if not |
@@ -143,15 +139,13 @@ pgtbl_lookup: | |||
143 | tlbmiss_restore | 139 | tlbmiss_restore |
144 | rete | 140 | rete |
145 | 141 | ||
146 | handle_vmalloc_miss: | ||
147 | /* Simply do the lookup in init's page table */ | ||
148 | mov r1, lo(swapper_pg_dir) | ||
149 | orh r1, hi(swapper_pg_dir) | ||
150 | rjmp pgtbl_lookup | ||
151 | |||
152 | /* The slow path of the TLB miss handler */ | 142 | /* The slow path of the TLB miss handler */ |
153 | .align 2 | 143 | .align 2 |
154 | page_table_not_present: | 144 | page_table_not_present: |
145 | /* Do we need to synchronize with swapper_pg_dir? */ | ||
146 | bld r0, 31 | ||
147 | brcs sync_with_swapper_pg_dir | ||
148 | |||
155 | page_not_present: | 149 | page_not_present: |
156 | tlbmiss_restore | 150 | tlbmiss_restore |
157 | sub sp, 4 | 151 | sub sp, 4 |
@@ -162,6 +156,34 @@ page_not_present: | |||
162 | rcall do_page_fault | 156 | rcall do_page_fault |
163 | rjmp ret_from_exception | 157 | rjmp ret_from_exception |
164 | 158 | ||
159 | .align 2 | ||
160 | sync_with_swapper_pg_dir: | ||
161 | /* | ||
162 | * If swapper_pg_dir contains a non-NULL second-level page | ||
163 | * table pointer, copy it into the current PGD. If not, we | ||
164 | * must handle it as a full-blown page fault. | ||
165 | * | ||
166 | * Jumping back to pgtbl_lookup causes an unnecessary lookup, | ||
167 | * but it is guaranteed to be a cache hit, it won't happen | ||
168 | * very often, and we absolutely do not want to sacrifice any | ||
169 | * performance in the fast path in order to improve this. | ||
170 | */ | ||
171 | mov r1, lo(swapper_pg_dir) | ||
172 | orh r1, hi(swapper_pg_dir) | ||
173 | ld.w r3, r1[r2 << 2] | ||
174 | cp.w r3, 0 | ||
175 | breq page_not_present | ||
176 | mfsr r1, SYSREG_PTBR | ||
177 | st.w r1[r2 << 2], r3 | ||
178 | rjmp pgtbl_lookup | ||
179 | |||
180 | /* | ||
181 | * We currently have two bytes left at this point until we | ||
182 | * crash into the system call handler... | ||
183 | * | ||
184 | * Don't worry, the assembler will let us know. | ||
185 | */ | ||
186 | |||
165 | 187 | ||
166 | /* --- System Call --- */ | 188 | /* --- System Call --- */ |
167 | 189 | ||
diff --git a/include/asm-avr32/pgalloc.h b/include/asm-avr32/pgalloc.h index 5b768fc2388e..e9636d1f383f 100644 --- a/include/asm-avr32/pgalloc.h +++ b/include/asm-avr32/pgalloc.h | |||
@@ -9,8 +9,6 @@ | |||
9 | #define __ASM_AVR32_PGALLOC_H | 9 | #define __ASM_AVR32_PGALLOC_H |
10 | 10 | ||
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/sched.h> | ||
13 | #include <linux/slab.h> | ||
14 | 12 | ||
15 | static inline void pmd_populate_kernel(struct mm_struct *mm, | 13 | static inline void pmd_populate_kernel(struct mm_struct *mm, |
16 | pmd_t *pmd, pte_t *pte) | 14 | pmd_t *pmd, pte_t *pte) |
@@ -30,12 +28,20 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, | |||
30 | */ | 28 | */ |
31 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 29 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
32 | { | 30 | { |
33 | return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL); | 31 | pgd_t *pgd; |
32 | |||
33 | pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT); | ||
34 | if (likely(pgd)) | ||
35 | memcpy(pgd + USER_PTRS_PER_PGD, | ||
36 | swapper_pg_dir + USER_PTRS_PER_PGD, | ||
37 | (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); | ||
38 | |||
39 | return pgd; | ||
34 | } | 40 | } |
35 | 41 | ||
36 | static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) | 42 | static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) |
37 | { | 43 | { |
38 | kfree(pgd); | 44 | free_page((unsigned long)pgd); |
39 | } | 45 | } |
40 | 46 | ||
41 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, | 47 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, |