mfsr r0, SYSREG_TLBEAR
mfsr r1, SYSREG_PTBR
- /* Is it the vmalloc space? */
- bld r0, 31
- brcs handle_vmalloc_miss
-
/*
* First level lookup: The PGD contains virtual pointers to
* the second-level page tables, but they may be NULL if not
tlbmiss_restore
rete
-handle_vmalloc_miss:
- /* Simply do the lookup in init's page table */
- mov r1, lo(swapper_pg_dir)
- orh r1, hi(swapper_pg_dir)
- rjmp pgtbl_lookup
-
/* The slow path of the TLB miss handler */
.align 2
page_table_not_present:
+ /* Do we need to synchronize with swapper_pg_dir? */
+ bld r0, 31
+ brcs sync_with_swapper_pg_dir
+
page_not_present:
tlbmiss_restore
sub sp, 4
rcall do_page_fault
rjmp ret_from_exception
+ .align 2
+sync_with_swapper_pg_dir:
+ /*
+ * If swapper_pg_dir contains a non-NULL second-level page
+ * table pointer, copy it into the current PGD. If not, we
+ * must handle it as a full-blown page fault.
+ *
+ * Jumping back to pgtbl_lookup causes an unnecessary lookup,
+ * but it is guaranteed to be a cache hit, it won't happen
+ * very often, and we absolutely do not want to sacrifice any
+ * performance in the fast path in order to improve this.
+ */
+ mov r1, lo(swapper_pg_dir)
+ orh r1, hi(swapper_pg_dir)
+ ld.w r3, r1[r2 << 2]
+ cp.w r3, 0
+ breq page_not_present
+ mfsr r1, SYSREG_PTBR
+ st.w r1[r2 << 2], r3
+ rjmp pgtbl_lookup
+
+ /*
+ * We currently have two bytes left at this point until we
+ * crash into the system call handler...
+ *
+ * Don't worry, the assembler will let us know.
+ */
+
/* --- System Call --- */
#define __ASM_AVR32_PGALLOC_H
#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
static inline void pmd_populate_kernel(struct mm_struct *mm,
pmd_t *pmd, pte_t *pte)
*/
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
- return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
+ pgd_t *pgd;
+
+ pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
+ if (likely(pgd))
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ swapper_pg_dir + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+
+ return pgd;
}
static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
- kfree(pgd);
+ free_page((unsigned long)pgd);
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,