diff options
author | Jon Tollefson <kniht@linux.vnet.ibm.com> | 2008-01-03 17:59:50 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-01-16 22:57:36 -0500 |
commit | 4ec161cf73bc0b4e5c36843638ef9171896fc0b9 (patch) | |
tree | fd8d5c652bbc54f54e0b880a7540ce387ee1f34d | |
parent | 5b14e5f9ddbb1bd32a876cac75f5f3ecfd353063 (diff) |
[POWERPC] Add hugepagesz boot-time parameter
This adds the hugepagesz boot-time parameter for ppc64. It lets one
pick the size for huge pages. The choices available are 64K and 16M
when the base page size is 4k. It defaults to 16M (previously the
only only choice) if nothing or an invalid choice is specified.
Tested 64K huge pages successfully with the libhugetlbfs 1.2.
Signed-off-by: Jon Tollefson <kniht@linux.vnet.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | Documentation/kernel-parameters.txt | 1 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 11 | ||||
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 119 | ||||
-rw-r--r-- | include/asm-powerpc/mmu-hash64.h | 1 |
4 files changed, 98 insertions, 34 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 33121d6c827c..2fc1fb896afc 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -685,6 +685,7 @@ and is between 256 and 4096 characters. It is defined in the file | |||
685 | See Documentation/isdn/README.HiSax. | 685 | See Documentation/isdn/README.HiSax. |
686 | 686 | ||
687 | hugepages= [HW,X86-32,IA-64] Maximal number of HugeTLB pages. | 687 | hugepages= [HW,X86-32,IA-64] Maximal number of HugeTLB pages. |
688 | hugepagesz= [HW,IA-64,PPC] The size of the HugeTLB pages. | ||
688 | 689 | ||
689 | i8042.direct [HW] Put keyboard port into non-translated mode | 690 | i8042.direct [HW] Put keyboard port into non-translated mode |
690 | i8042.dumbkbd [HW] Pretend that controller can only read data from | 691 | i8042.dumbkbd [HW] Pretend that controller can only read data from |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index cbbd8b0bc8f4..9326a6962b42 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -369,18 +369,11 @@ static void __init htab_init_page_sizes(void) | |||
369 | * on what is available | 369 | * on what is available |
370 | */ | 370 | */ |
371 | if (mmu_psize_defs[MMU_PAGE_16M].shift) | 371 | if (mmu_psize_defs[MMU_PAGE_16M].shift) |
372 | mmu_huge_psize = MMU_PAGE_16M; | 372 | set_huge_psize(MMU_PAGE_16M); |
373 | /* With 4k/4level pagetables, we can't (for now) cope with a | 373 | /* With 4k/4level pagetables, we can't (for now) cope with a |
374 | * huge page size < PMD_SIZE */ | 374 | * huge page size < PMD_SIZE */ |
375 | else if (mmu_psize_defs[MMU_PAGE_1M].shift) | 375 | else if (mmu_psize_defs[MMU_PAGE_1M].shift) |
376 | mmu_huge_psize = MMU_PAGE_1M; | 376 | set_huge_psize(MMU_PAGE_1M); |
377 | |||
378 | /* Calculate HPAGE_SHIFT and sanity check it */ | ||
379 | if (mmu_psize_defs[mmu_huge_psize].shift > MIN_HUGEPTE_SHIFT && | ||
380 | mmu_psize_defs[mmu_huge_psize].shift < SID_SHIFT) | ||
381 | HPAGE_SHIFT = mmu_psize_defs[mmu_huge_psize].shift; | ||
382 | else | ||
383 | HPAGE_SHIFT = 0; /* No huge pages dude ! */ | ||
384 | #endif /* CONFIG_HUGETLB_PAGE */ | 377 | #endif /* CONFIG_HUGETLB_PAGE */ |
385 | } | 378 | } |
386 | 379 | ||
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 71efb38d599b..a02266dad215 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c | |||
@@ -24,18 +24,17 @@ | |||
24 | #include <asm/cputable.h> | 24 | #include <asm/cputable.h> |
25 | #include <asm/spu.h> | 25 | #include <asm/spu.h> |
26 | 26 | ||
27 | #define HPAGE_SHIFT_64K 16 | ||
28 | #define HPAGE_SHIFT_16M 24 | ||
29 | |||
27 | #define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT) | 30 | #define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT) |
28 | #define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT) | 31 | #define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT) |
29 | 32 | ||
30 | #ifdef CONFIG_PPC_64K_PAGES | 33 | unsigned int hugepte_shift; |
31 | #define HUGEPTE_INDEX_SIZE (PMD_SHIFT-HPAGE_SHIFT) | 34 | #define PTRS_PER_HUGEPTE (1 << hugepte_shift) |
32 | #else | 35 | #define HUGEPTE_TABLE_SIZE (sizeof(pte_t) << hugepte_shift) |
33 | #define HUGEPTE_INDEX_SIZE (PUD_SHIFT-HPAGE_SHIFT) | ||
34 | #endif | ||
35 | #define PTRS_PER_HUGEPTE (1 << HUGEPTE_INDEX_SIZE) | ||
36 | #define HUGEPTE_TABLE_SIZE (sizeof(pte_t) << HUGEPTE_INDEX_SIZE) | ||
37 | 36 | ||
38 | #define HUGEPD_SHIFT (HPAGE_SHIFT + HUGEPTE_INDEX_SIZE) | 37 | #define HUGEPD_SHIFT (HPAGE_SHIFT + hugepte_shift) |
39 | #define HUGEPD_SIZE (1UL << HUGEPD_SHIFT) | 38 | #define HUGEPD_SIZE (1UL << HUGEPD_SHIFT) |
40 | #define HUGEPD_MASK (~(HUGEPD_SIZE-1)) | 39 | #define HUGEPD_MASK (~(HUGEPD_SIZE-1)) |
41 | 40 | ||
@@ -82,11 +81,35 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, | |||
82 | return 0; | 81 | return 0; |
83 | } | 82 | } |
84 | 83 | ||
84 | /* Base page size affects how we walk hugetlb page tables */ | ||
85 | #ifdef CONFIG_PPC_64K_PAGES | ||
86 | #define hpmd_offset(pud, addr) pmd_offset(pud, addr) | ||
87 | #define hpmd_alloc(mm, pud, addr) pmd_alloc(mm, pud, addr) | ||
88 | #else | ||
89 | static inline | ||
90 | pmd_t *hpmd_offset(pud_t *pud, unsigned long addr) | ||
91 | { | ||
92 | if (HPAGE_SHIFT == HPAGE_SHIFT_64K) | ||
93 | return pmd_offset(pud, addr); | ||
94 | else | ||
95 | return (pmd_t *) pud; | ||
96 | } | ||
97 | static inline | ||
98 | pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr) | ||
99 | { | ||
100 | if (HPAGE_SHIFT == HPAGE_SHIFT_64K) | ||
101 | return pmd_alloc(mm, pud, addr); | ||
102 | else | ||
103 | return (pmd_t *) pud; | ||
104 | } | ||
105 | #endif | ||
106 | |||
85 | /* Modelled after find_linux_pte() */ | 107 | /* Modelled after find_linux_pte() */ |
86 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | 108 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) |
87 | { | 109 | { |
88 | pgd_t *pg; | 110 | pgd_t *pg; |
89 | pud_t *pu; | 111 | pud_t *pu; |
112 | pmd_t *pm; | ||
90 | 113 | ||
91 | BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize); | 114 | BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize); |
92 | 115 | ||
@@ -96,14 +119,9 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | |||
96 | if (!pgd_none(*pg)) { | 119 | if (!pgd_none(*pg)) { |
97 | pu = pud_offset(pg, addr); | 120 | pu = pud_offset(pg, addr); |
98 | if (!pud_none(*pu)) { | 121 | if (!pud_none(*pu)) { |
99 | #ifdef CONFIG_PPC_64K_PAGES | 122 | pm = hpmd_offset(pu, addr); |
100 | pmd_t *pm; | ||
101 | pm = pmd_offset(pu, addr); | ||
102 | if (!pmd_none(*pm)) | 123 | if (!pmd_none(*pm)) |
103 | return hugepte_offset((hugepd_t *)pm, addr); | 124 | return hugepte_offset((hugepd_t *)pm, addr); |
104 | #else | ||
105 | return hugepte_offset((hugepd_t *)pu, addr); | ||
106 | #endif | ||
107 | } | 125 | } |
108 | } | 126 | } |
109 | 127 | ||
@@ -114,6 +132,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) | |||
114 | { | 132 | { |
115 | pgd_t *pg; | 133 | pgd_t *pg; |
116 | pud_t *pu; | 134 | pud_t *pu; |
135 | pmd_t *pm; | ||
117 | hugepd_t *hpdp = NULL; | 136 | hugepd_t *hpdp = NULL; |
118 | 137 | ||
119 | BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize); | 138 | BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize); |
@@ -124,14 +143,9 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) | |||
124 | pu = pud_alloc(mm, pg, addr); | 143 | pu = pud_alloc(mm, pg, addr); |
125 | 144 | ||
126 | if (pu) { | 145 | if (pu) { |
127 | #ifdef CONFIG_PPC_64K_PAGES | 146 | pm = hpmd_alloc(mm, pu, addr); |
128 | pmd_t *pm; | ||
129 | pm = pmd_alloc(mm, pu, addr); | ||
130 | if (pm) | 147 | if (pm) |
131 | hpdp = (hugepd_t *)pm; | 148 | hpdp = (hugepd_t *)pm; |
132 | #else | ||
133 | hpdp = (hugepd_t *)pu; | ||
134 | #endif | ||
135 | } | 149 | } |
136 | 150 | ||
137 | if (! hpdp) | 151 | if (! hpdp) |
@@ -158,7 +172,6 @@ static void free_hugepte_range(struct mmu_gather *tlb, hugepd_t *hpdp) | |||
158 | PGF_CACHENUM_MASK)); | 172 | PGF_CACHENUM_MASK)); |
159 | } | 173 | } |
160 | 174 | ||
161 | #ifdef CONFIG_PPC_64K_PAGES | ||
162 | static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, | 175 | static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, |
163 | unsigned long addr, unsigned long end, | 176 | unsigned long addr, unsigned long end, |
164 | unsigned long floor, unsigned long ceiling) | 177 | unsigned long floor, unsigned long ceiling) |
@@ -191,7 +204,6 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, | |||
191 | pud_clear(pud); | 204 | pud_clear(pud); |
192 | pmd_free_tlb(tlb, pmd); | 205 | pmd_free_tlb(tlb, pmd); |
193 | } | 206 | } |
194 | #endif | ||
195 | 207 | ||
196 | static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd, | 208 | static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd, |
197 | unsigned long addr, unsigned long end, | 209 | unsigned long addr, unsigned long end, |
@@ -210,9 +222,15 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd, | |||
210 | continue; | 222 | continue; |
211 | hugetlb_free_pmd_range(tlb, pud, addr, next, floor, ceiling); | 223 | hugetlb_free_pmd_range(tlb, pud, addr, next, floor, ceiling); |
212 | #else | 224 | #else |
213 | if (pud_none(*pud)) | 225 | if (HPAGE_SHIFT == HPAGE_SHIFT_64K) { |
214 | continue; | 226 | if (pud_none_or_clear_bad(pud)) |
215 | free_hugepte_range(tlb, (hugepd_t *)pud); | 227 | continue; |
228 | hugetlb_free_pmd_range(tlb, pud, addr, next, floor, ceiling); | ||
229 | } else { | ||
230 | if (pud_none(*pud)) | ||
231 | continue; | ||
232 | free_hugepte_range(tlb, (hugepd_t *)pud); | ||
233 | } | ||
216 | #endif | 234 | #endif |
217 | } while (pud++, addr = next, addr != end); | 235 | } while (pud++, addr = next, addr != end); |
218 | 236 | ||
@@ -526,6 +544,57 @@ repeat: | |||
526 | return err; | 544 | return err; |
527 | } | 545 | } |
528 | 546 | ||
547 | void set_huge_psize(int psize) | ||
548 | { | ||
549 | /* Check that it is a page size supported by the hardware and | ||
550 | * that it fits within pagetable limits. */ | ||
551 | if (mmu_psize_defs[psize].shift && mmu_psize_defs[psize].shift < SID_SHIFT && | ||
552 | (mmu_psize_defs[psize].shift > MIN_HUGEPTE_SHIFT || | ||
553 | mmu_psize_defs[psize].shift == HPAGE_SHIFT_64K)) { | ||
554 | HPAGE_SHIFT = mmu_psize_defs[psize].shift; | ||
555 | mmu_huge_psize = psize; | ||
556 | #ifdef CONFIG_PPC_64K_PAGES | ||
557 | hugepte_shift = (PMD_SHIFT-HPAGE_SHIFT); | ||
558 | #else | ||
559 | if (HPAGE_SHIFT == HPAGE_SHIFT_64K) | ||
560 | hugepte_shift = (PMD_SHIFT-HPAGE_SHIFT); | ||
561 | else | ||
562 | hugepte_shift = (PUD_SHIFT-HPAGE_SHIFT); | ||
563 | #endif | ||
564 | |||
565 | } else | ||
566 | HPAGE_SHIFT = 0; | ||
567 | } | ||
568 | |||
569 | static int __init hugepage_setup_sz(char *str) | ||
570 | { | ||
571 | unsigned long long size; | ||
572 | int mmu_psize = -1; | ||
573 | int shift; | ||
574 | |||
575 | size = memparse(str, &str); | ||
576 | |||
577 | shift = __ffs(size); | ||
578 | switch (shift) { | ||
579 | #ifndef CONFIG_PPC_64K_PAGES | ||
580 | case HPAGE_SHIFT_64K: | ||
581 | mmu_psize = MMU_PAGE_64K; | ||
582 | break; | ||
583 | #endif | ||
584 | case HPAGE_SHIFT_16M: | ||
585 | mmu_psize = MMU_PAGE_16M; | ||
586 | break; | ||
587 | } | ||
588 | |||
589 | if (mmu_psize >=0 && mmu_psize_defs[mmu_psize].shift) | ||
590 | set_huge_psize(mmu_psize); | ||
591 | else | ||
592 | printk(KERN_WARNING "Invalid huge page size specified(%llu)\n", size); | ||
593 | |||
594 | return 1; | ||
595 | } | ||
596 | __setup("hugepagesz=", hugepage_setup_sz); | ||
597 | |||
529 | static void zero_ctor(struct kmem_cache *cache, void *addr) | 598 | static void zero_ctor(struct kmem_cache *cache, void *addr) |
530 | { | 599 | { |
531 | memset(addr, 0, kmem_cache_size(cache)); | 600 | memset(addr, 0, kmem_cache_size(cache)); |
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h index f2d7d5ded2e5..2a1b4040e20d 100644 --- a/include/asm-powerpc/mmu-hash64.h +++ b/include/asm-powerpc/mmu-hash64.h | |||
@@ -278,6 +278,7 @@ extern int hash_huge_page(struct mm_struct *mm, unsigned long access, | |||
278 | extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | 278 | extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend, |
279 | unsigned long pstart, unsigned long mode, | 279 | unsigned long pstart, unsigned long mode, |
280 | int psize, int ssize); | 280 | int psize, int ssize); |
281 | extern void set_huge_psize(int psize); | ||
281 | 282 | ||
282 | extern void htab_initialize(void); | 283 | extern void htab_initialize(void); |
283 | extern void htab_initialize_secondary(void); | 284 | extern void htab_initialize_secondary(void); |