diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2005-08-05 05:39:06 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-08-28 20:53:31 -0400 |
commit | e28f7faf05159f1cfd564596f5e6178edba6bd49 (patch) | |
tree | 45534d2c33bff8b64e3fd155fba55146cb7518e6 /include/asm-ppc64/pgalloc.h | |
parent | decd300b30e499fe6be1bbfc5650fc971de8c1fa (diff) |
[PATCH] Four level pagetables for ppc64
Implement 4-level pagetables for ppc64
This patch implements full four-level page tables for ppc64, thereby
extending the usable user address range to 44 bits (16T).
The patch uses a full page for the tables at the bottom and top level,
and a quarter page for the intermediate levels. It uses full 64-bit
pointers at every level, thus also increasing the addressable range of
physical memory. This patch also tweaks the VSID allocation to allow
matching range for user addresses (this halves the number of available
contexts) and adds some #if and BUILD_BUG sanity checks.
Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include/asm-ppc64/pgalloc.h')
-rw-r--r-- | include/asm-ppc64/pgalloc.h | 93 |
1 files changed, 61 insertions, 32 deletions
diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h index 4fc4b739b380..26bc49c1108d 100644 --- a/include/asm-ppc64/pgalloc.h +++ b/include/asm-ppc64/pgalloc.h | |||
@@ -6,7 +6,12 @@ | |||
6 | #include <linux/cpumask.h> | 6 | #include <linux/cpumask.h> |
7 | #include <linux/percpu.h> | 7 | #include <linux/percpu.h> |
8 | 8 | ||
9 | extern kmem_cache_t *zero_cache; | 9 | extern kmem_cache_t *pgtable_cache[]; |
10 | |||
11 | #define PTE_CACHE_NUM 0 | ||
12 | #define PMD_CACHE_NUM 1 | ||
13 | #define PUD_CACHE_NUM 1 | ||
14 | #define PGD_CACHE_NUM 0 | ||
10 | 15 | ||
11 | /* | 16 | /* |
12 | * This program is free software; you can redistribute it and/or | 17 | * This program is free software; you can redistribute it and/or |
@@ -15,30 +20,40 @@ extern kmem_cache_t *zero_cache; | |||
15 | * 2 of the License, or (at your option) any later version. | 20 | * 2 of the License, or (at your option) any later version. |
16 | */ | 21 | */ |
17 | 22 | ||
18 | static inline pgd_t * | 23 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
19 | pgd_alloc(struct mm_struct *mm) | ||
20 | { | 24 | { |
21 | return kmem_cache_alloc(zero_cache, GFP_KERNEL); | 25 | return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL); |
22 | } | 26 | } |
23 | 27 | ||
24 | static inline void | 28 | static inline void pgd_free(pgd_t *pgd) |
25 | pgd_free(pgd_t *pgd) | ||
26 | { | 29 | { |
27 | kmem_cache_free(zero_cache, pgd); | 30 | kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd); |
31 | } | ||
32 | |||
33 | #define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD) | ||
34 | |||
35 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
36 | { | ||
37 | return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM], | ||
38 | GFP_KERNEL|__GFP_REPEAT); | ||
39 | } | ||
40 | |||
41 | static inline void pud_free(pud_t *pud) | ||
42 | { | ||
43 | kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud); | ||
28 | } | 44 | } |
29 | 45 | ||
30 | #define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) | 46 | #define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) |
31 | 47 | ||
32 | static inline pmd_t * | 48 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) |
33 | pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
34 | { | 49 | { |
35 | return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT); | 50 | return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM], |
51 | GFP_KERNEL|__GFP_REPEAT); | ||
36 | } | 52 | } |
37 | 53 | ||
38 | static inline void | 54 | static inline void pmd_free(pmd_t *pmd) |
39 | pmd_free(pmd_t *pmd) | ||
40 | { | 55 | { |
41 | kmem_cache_free(zero_cache, pmd); | 56 | kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd); |
42 | } | 57 | } |
43 | 58 | ||
44 | #define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte) | 59 | #define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte) |
@@ -47,44 +62,58 @@ pmd_free(pmd_t *pmd) | |||
47 | 62 | ||
48 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | 63 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) |
49 | { | 64 | { |
50 | return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT); | 65 | return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM], |
66 | GFP_KERNEL|__GFP_REPEAT); | ||
51 | } | 67 | } |
52 | 68 | ||
53 | static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) | 69 | static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) |
54 | { | 70 | { |
55 | pte_t *pte = kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT); | 71 | return virt_to_page(pte_alloc_one_kernel(mm, address)); |
56 | if (pte) | ||
57 | return virt_to_page(pte); | ||
58 | return NULL; | ||
59 | } | 72 | } |
60 | 73 | ||
61 | static inline void pte_free_kernel(pte_t *pte) | 74 | static inline void pte_free_kernel(pte_t *pte) |
62 | { | 75 | { |
63 | kmem_cache_free(zero_cache, pte); | 76 | kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte); |
64 | } | 77 | } |
65 | 78 | ||
66 | static inline void pte_free(struct page *ptepage) | 79 | static inline void pte_free(struct page *ptepage) |
67 | { | 80 | { |
68 | kmem_cache_free(zero_cache, page_address(ptepage)); | 81 | pte_free_kernel(page_address(ptepage)); |
69 | } | 82 | } |
70 | 83 | ||
71 | struct pte_freelist_batch | 84 | #define PGF_CACHENUM_MASK 0xf |
85 | |||
86 | typedef struct pgtable_free { | ||
87 | unsigned long val; | ||
88 | } pgtable_free_t; | ||
89 | |||
90 | static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum, | ||
91 | unsigned long mask) | ||
72 | { | 92 | { |
73 | struct rcu_head rcu; | 93 | BUG_ON(cachenum > PGF_CACHENUM_MASK); |
74 | unsigned int index; | ||
75 | struct page * pages[0]; | ||
76 | }; | ||
77 | 94 | ||
78 | #define PTE_FREELIST_SIZE ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) / \ | 95 | return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum}; |
79 | sizeof(struct page *)) | 96 | } |
80 | 97 | ||
81 | extern void pte_free_now(struct page *ptepage); | 98 | static inline void pgtable_free(pgtable_free_t pgf) |
82 | extern void pte_free_submit(struct pte_freelist_batch *batch); | 99 | { |
100 | void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK); | ||
101 | int cachenum = pgf.val & PGF_CACHENUM_MASK; | ||
83 | 102 | ||
84 | DECLARE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); | 103 | kmem_cache_free(pgtable_cache[cachenum], p); |
104 | } | ||
85 | 105 | ||
86 | void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage); | 106 | void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf); |
87 | #define __pmd_free_tlb(tlb, pmd) __pte_free_tlb(tlb, virt_to_page(pmd)) | 107 | |
108 | #define __pte_free_tlb(tlb, ptepage) \ | ||
109 | pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \ | ||
110 | PTE_CACHE_NUM, PTE_TABLE_SIZE-1)) | ||
111 | #define __pmd_free_tlb(tlb, pmd) \ | ||
112 | pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \ | ||
113 | PMD_CACHE_NUM, PMD_TABLE_SIZE-1)) | ||
114 | #define __pud_free_tlb(tlb, pmd) \ | ||
115 | pgtable_free_tlb(tlb, pgtable_free_cache(pud, \ | ||
116 | PUD_CACHE_NUM, PUD_TABLE_SIZE-1)) | ||
88 | 117 | ||
89 | #define check_pgt_cache() do { } while (0) | 118 | #define check_pgt_cache() do { } while (0) |
90 | 119 | ||