diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-mips/page.h | 42 | ||||
-rw-r--r-- | include/asm-mips/pgalloc.h | 19 | ||||
-rw-r--r-- | include/asm-mips/pgtable-32.h | 40 | ||||
-rw-r--r-- | include/asm-mips/pgtable-64.h | 55 | ||||
-rw-r--r-- | include/asm-mips/pgtable.h | 13 |
5 files changed, 101 insertions, 68 deletions
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index 652b6d67a57..ee25a779bf4 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -87,22 +87,48 @@ static inline void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, typedef struct { unsigned long pte; } pte_t; #define pte_val(x) ((x).pte) #endif +#define __pte(x) ((pte_t) { (x) } ) -typedef struct { unsigned long pmd; } pmd_t; -typedef struct { unsigned long pgd; } pgd_t; -typedef struct { unsigned long pgprot; } pgprot_t; +/* + * For 3-level pagetables we defines these ourselves, for 2-level the + * definitions are supplied by <asm-generic/pgtable-nopmd.h>. + */ +#ifdef CONFIG_64BIT +typedef struct { unsigned long pmd; } pmd_t; #define pmd_val(x) ((x).pmd) -#define pgd_val(x) ((x).pgd) -#define pgprot_val(x) ((x).pgprot) +#define __pmd(x) ((pmd_t) { (x) } ) -#define ptep_buddy(x) ((pte_t *)((unsigned long)(x) ^ sizeof(pte_t))) +#endif -#define __pte(x) ((pte_t) { (x) } ) -#define __pmd(x) ((pmd_t) { (x) } ) +/* + * Right now we don't support 4-level pagetables, so all pud-related + * definitions come from <asm-generic/pgtable-nopud.h>. + */ + +/* + * Finall the top of the hierarchy, the pgd + */ +typedef struct { unsigned long pgd; } pgd_t; +#define pgd_val(x) ((x).pgd) #define __pgd(x) ((pgd_t) { (x) } ) + +/* + * Manipulate page protection bits + */ +typedef struct { unsigned long pgprot; } pgprot_t; +#define pgprot_val(x) ((x).pgprot) #define __pgprot(x) ((pgprot_t) { (x) } ) +/* + * On R4000-style MMUs where a TLB entry is mapping a adjacent even / odd + * pair of pages we only have a single global bit per pair of pages. When + * writing to the TLB make sure we always have the bit set for both pages + * or none. This macro is used to access the `buddy' of the pte we're just + * working on. + */ +#define ptep_buddy(x) ((pte_t *)((unsigned long)(x) ^ sizeof(pte_t))) + #endif /* !__ASSEMBLY__ */ /* to align the pointer to the (next) page boundary */ diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h index ce57288d43b..fe1df572318 100644 --- a/include/asm-mips/pgalloc.h +++ b/include/asm-mips/pgalloc.h @@ -26,10 +26,22 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, } /* + * Initialize a new pmd table with invalid pointers. + */ +extern void pmd_init(unsigned long page, unsigned long pagetable); + +#ifdef CONFIG_64BIT + +static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + set_pud(pud, __pud((unsigned long)pmd)); +} +#endif + +/* * Initialize a new pgd / pmd table with invalid pointers. */ extern void pgd_init(unsigned long page); -extern void pmd_init(unsigned long page, unsigned long pagetable); static inline pgd_t *pgd_alloc(struct mm_struct *mm) { @@ -86,21 +98,18 @@ static inline void pte_free(struct page *pte) #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) #ifdef CONFIG_32BIT -#define pgd_populate(mm, pmd, pte) BUG() /* * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(x) do { } while (0) #define __pmd_free_tlb(tlb,x) do { } while (0) + #endif #ifdef CONFIG_64BIT -#define pgd_populate(mm, pgd, pmd) set_pgd(pgd, __pgd(pmd)) - static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) { pmd_t *pmd; diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h index 7fec93b76da..8d66303eabc 100644 --- a/include/asm-mips/pgtable-32.h +++ b/include/asm-mips/pgtable-32.h @@ -17,6 +17,8 @@ #include <asm/cachectl.h> #include <asm/fixmap.h> +#include <asm-generic/pgtable-nopmd.h> + /* * - add_wired_entry() add a fixed TLB entry, and move wired register */ @@ -42,35 +44,35 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, */ /* PMD_SHIFT determines the size of the area a second-level page table can map */ -#ifdef CONFIG_64BIT_PHYS_ADDR -#define PMD_SHIFT 21 -#else -#define PMD_SHIFT 22 -#endif #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) /* PGDIR_SHIFT determines what a third-level page table entry can map */ -#define PGDIR_SHIFT PMD_SHIFT +#ifdef CONFIG_64BIT_PHYS_ADDR +#define PGDIR_SHIFT 21 +#else +#define PGDIR_SHIFT 22 +#endif #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) /* * Entries per page directory level: we use two-level, so - * we don't really have any PMD directory physically. + * we don't really have any PUD/PMD directory physically. */ #ifdef CONFIG_64BIT_PHYS_ADDR #define PGD_ORDER 1 -#define PMD_ORDER 0 +#define PUD_ORDER aieeee_attempt_to_allocate_pud +#define PMD_ORDER 1 #define PTE_ORDER 0 #else #define PGD_ORDER 0 -#define PMD_ORDER 0 +#define PUD_ORDER aieeee_attempt_to_allocate_pud +#define PMD_ORDER 1 #define PTE_ORDER 0 #endif #define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t)) -#define PTRS_PER_PMD 1 #define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t)) #define USER_PTRS_PER_PGD (0x80000000UL/PGDIR_SIZE) @@ -91,8 +93,6 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, #define pte_ERROR(e) \ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) #endif -#define pmd_ERROR(e) \ - printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) @@ -120,16 +120,6 @@ static inline void pmd_clear(pmd_t *pmdp) pmd_val(*pmdp) = ((unsigned long) invalid_pte_table); } -/* - * The "pgd_xxx()" functions here are trivial for a folded two-level - * setup: the pgd is never bad, and a pmd always exists (as it's folded - * into the pgd entry) - */ -static inline int pgd_none(pgd_t pgd) { return 0; } -static inline int pgd_bad(pgd_t pgd) { return 0; } -static inline int pgd_present(pgd_t pgd) { return 1; } -static inline void pgd_clear(pgd_t *pgdp) { } - #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) #define pte_page(x) pfn_to_page(pte_pfn(x)) #define pte_pfn(x) ((unsigned long)((x).pte_high >> 6)) @@ -166,12 +156,6 @@ pfn_pte(unsigned long pfn, pgprot_t prot) /* to find an entry in a page-table-directory */ #define pgd_offset(mm,addr) ((mm)->pgd + pgd_index(addr)) -/* Find an entry in the second-level page table.. */ -static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address) -{ - return (pmd_t *) dir; -} - /* Find an entry in the third-level page table.. */ #define __pte_offset(address) \ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h index 1011e0635f5..ac5517fa1ee 100644 --- a/include/asm-mips/pgtable-64.h +++ b/include/asm-mips/pgtable-64.h @@ -16,13 +16,15 @@ #include <asm/page.h> #include <asm/cachectl.h> +#include <asm-generic/pgtable-nopud.h> + /* * Each address space has 2 4K pages as its page directory, giving 1024 * (== PTRS_PER_PGD) 8 byte pointers to pmd tables. Each pmd table is a - * pair of 4K pages, giving 1024 (== PTRS_PER_PMD) 8 byte pointers to - * page tables. Each page table is a single 4K page, giving 512 (== - * PTRS_PER_PTE) 8 byte ptes. Each pgde is initialized to point to - * invalid_pmd_table, each pmde is initialized to point to + * single 4K page, giving 512 (== PTRS_PER_PMD) 8 byte pointers to page + * tables. Each page table is also a single 4K page, giving 512 (== + * PTRS_PER_PTE) 8 byte ptes. Each pud entry is initialized to point to + * invalid_pmd_table, each pmd entry is initialized to point to * invalid_pte_table, each pte is initialized to 0. When memory is low, * and a pmd table or a page table allocation fails, empty_bad_pmd_table * and empty_bad_page_table is returned back to higher layer code, so @@ -36,17 +38,17 @@ */ /* PMD_SHIFT determines the size of the area a second-level page table can map */ -#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3)) +#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT + PTE_ORDER - 3)) #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) /* PGDIR_SHIFT determines what a third-level page table entry can map */ -#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT + 1 - 3)) +#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3)) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) /* - * For 4kB page size we use a 3 level page tree and a 8kB pmd and pgds which + * For 4kB page size we use a 3 level page tree and an 8kB pud, which * permits us mapping 40 bits of virtual address space. * * We used to implement 41 bits by having an order 1 pmd level but that seemed @@ -65,21 +67,25 @@ */ #ifdef CONFIG_PAGE_SIZE_4KB #define PGD_ORDER 1 +#define PUD_ORDER aieeee_attempt_to_allocate_pud #define PMD_ORDER 0 #define PTE_ORDER 0 #endif #ifdef CONFIG_PAGE_SIZE_8KB #define PGD_ORDER 0 +#define PUD_ORDER aieeee_attempt_to_allocate_pud #define PMD_ORDER 0 #define PTE_ORDER 0 #endif #ifdef CONFIG_PAGE_SIZE_16KB #define PGD_ORDER 0 +#define PUD_ORDER aieeee_attempt_to_allocate_pud #define PMD_ORDER 0 #define PTE_ORDER 0 #endif #ifdef CONFIG_PAGE_SIZE_64KB #define PGD_ORDER 0 +#define PUD_ORDER aieeee_attempt_to_allocate_pud #define PMD_ORDER 0 #define PTE_ORDER 0 #endif @@ -102,10 +108,10 @@ #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) -extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)]; -extern pte_t empty_bad_page_table[PAGE_SIZE/sizeof(pte_t)]; -extern pmd_t invalid_pmd_table[2*PAGE_SIZE/sizeof(pmd_t)]; -extern pmd_t empty_bad_pmd_table[2*PAGE_SIZE/sizeof(pmd_t)]; +extern pte_t invalid_pte_table[PTRS_PER_PTE]; +extern pte_t empty_bad_page_table[PTRS_PER_PTE]; +extern pmd_t invalid_pmd_table[PTRS_PER_PMD]; +extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; /* * Empty pmd entries point to the invalid_pte_table. @@ -130,21 +136,24 @@ static inline void pmd_clear(pmd_t *pmdp) /* * Empty pgd entries point to the invalid_pmd_table. */ -static inline int pgd_none(pgd_t pgd) +static inline int pud_none(pud_t pud) { - return pgd_val(pgd) == (unsigned long) invalid_pmd_table; + return pud_val(pud) == (unsigned long) invalid_pmd_table; } -#define pgd_bad(pgd) (pgd_val(pgd) &~ PAGE_MASK) +static inline int pud_bad(pud_t pud) +{ + return pud_val(pud) & ~PAGE_MASK; +} -static inline int pgd_present(pgd_t pgd) +static inline int pud_present(pud_t pud) { - return pgd_val(pgd) != (unsigned long) invalid_pmd_table; + return pud_val(pud) != (unsigned long) invalid_pmd_table; } -static inline void pgd_clear(pgd_t *pgdp) +static inline void pud_clear(pud_t *pudp) { - pgd_val(*pgdp) = ((unsigned long) invalid_pmd_table); + pud_val(*pudp) = ((unsigned long) invalid_pmd_table); } #define pte_page(x) pfn_to_page((unsigned long)((pte_val(x) >> PAGE_SHIFT))) @@ -162,20 +171,20 @@ static inline void pgd_clear(pgd_t *pgdp) /* to find an entry in a kernel page-table-directory */ #define pgd_offset_k(address) pgd_offset(&init_mm, 0) -#define pgd_index(address) ((address) >> PGDIR_SHIFT) +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) /* to find an entry in a page-table-directory */ #define pgd_offset(mm,addr) ((mm)->pgd + pgd_index(addr)) -static inline unsigned long pgd_page(pgd_t pgd) +static inline unsigned long pud_page(pud_t pud) { - return pgd_val(pgd); + return pud_val(pud); } /* Find an entry in the second-level page table.. */ -static inline pmd_t *pmd_offset(pgd_t * dir, unsigned long address) +static inline pmd_t *pmd_offset(pud_t * pud, unsigned long address) { - return (pmd_t *) pgd_page(*dir) + + return (pmd_t *) pud_page(*pud) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); } diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index eaf5d9b3a0e..34d06fe7caa 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -8,8 +8,6 @@ #ifndef _ASM_PGTABLE_H #define _ASM_PGTABLE_H -#include <asm-generic/4level-fixup.h> - #include <linux/config.h> #ifdef CONFIG_32BIT #include <asm/pgtable-32.h> @@ -148,11 +146,18 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt #endif /* - * (pmds are folded into pgds so this doesn't get actually called, + * (pmds are folded into puds so this doesn't get actually called, * but the define is needed for a generic inline function.) */ #define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while(0) -#define set_pgd(pgdptr, pgdval) do { *(pgdptr) = (pgdval); } while(0) + +#ifdef CONFIG_64BIT +/* + * (puds are folded into pgds so this doesn't get actually called, + * but the define is needed for a generic inline function.) + */ +#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while(0) +#endif #define PGD_T_LOG2 ffz(~sizeof(pgd_t)) #define PMD_T_LOG2 ffz(~sizeof(pmd_t)) |