diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-05-08 02:27:27 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-09 02:35:00 -0400 |
commit | d0f13e3c20b6fb73ccb467bdca97fa7cf5a574cd (patch) | |
tree | a2de01a21dbb28449893102742e6b516a519c03e /include | |
parent | 16f1c746755836aa823658000493cdab8ce7b098 (diff) |
[POWERPC] Introduce address space "slices"
The basic issue is to be able to do what hugetlbfs does but with
different page sizes for some other special filesystems; more
specifically, my need is:
- Huge pages
- SPE local store mappings using 64K pages on a 4K base page size
kernel on Cell
- Some special 4K segments in 64K-page kernels for mapping a dodgy
type of powerpc-specific infiniband hardware that requires 4K MMU
mappings for various reasons I won't explain here.
The main issues are:
- To maintain/keep track of the page size per "segment" (as we can
only have one page size per segment on powerpc, which are 256MB
divisions of the address space).
- To make sure special mappings stay within their allotted
"segments" (including MAP_FIXED crap)
- To make sure everybody else doesn't mmap/brk/grow_stack into a
"segment" that is used for a special mapping
Some of the necessary mechanisms to handle that were present in the
hugetlbfs code, but mostly in ways not suitable for anything else.
The patch relies on some changes to the generic get_unmapped_area()
that just got merged. It still hijacks hugetlb callbacks here or
there as the generic code hasn't been entirely cleaned up yet but
that shouldn't be a problem.
So what is a slice ? Well, I re-used the mechanism used formerly by our
hugetlbfs implementation which divides the address space in
"meta-segments" which I called "slices". The division is done using
256MB slices below 4G, and 1T slices above. Thus the address space is
divided currently into 16 "low" slices and 16 "high" slices. (Special
case: high slice 0 is the area between 4G and 1T).
Doing so simplifies significantly the tracking of segments and avoids
having to keep track of all the 256MB segments in the address space.
While I used the "concepts" of hugetlbfs, I mostly re-implemented
everything in a more generic way and "ported" hugetlbfs to it.
Slices can have an associated page size, which is encoded in the mmu
context and used by the SLB miss handler to set the segment sizes. The
hash code currently doesn't care, it has a specific check for hugepages,
though I might add a mechanism to provide per-slice hash mapping
functions in the future.
The slice code provide a pair of "generic" get_unmapped_area() (bottomup
and topdown) functions that should work with any slice size. There is
some trickiness here so I would appreciate people to have a look at the
implementation of these and let me know if I got something wrong.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-powerpc/mmu-hash64.h | 11 | ||||
-rw-r--r-- | include/asm-powerpc/paca.h | 2 | ||||
-rw-r--r-- | include/asm-powerpc/page_64.h | 86 |
3 files changed, 50 insertions, 49 deletions
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h index 6739457d8bc0..e2ca55bcfe0b 100644 --- a/include/asm-powerpc/mmu-hash64.h +++ b/include/asm-powerpc/mmu-hash64.h | |||
@@ -350,10 +350,13 @@ typedef unsigned long mm_context_id_t; | |||
350 | 350 | ||
351 | typedef struct { | 351 | typedef struct { |
352 | mm_context_id_t id; | 352 | mm_context_id_t id; |
353 | u16 user_psize; /* page size index */ | 353 | u16 user_psize; /* page size index */ |
354 | u16 sllp; /* SLB entry page size encoding */ | 354 | |
355 | #ifdef CONFIG_HUGETLB_PAGE | 355 | #ifdef CONFIG_PPC_MM_SLICES |
356 | u16 low_htlb_areas, high_htlb_areas; | 356 | u64 low_slices_psize; /* SLB page size encodings */ |
357 | u64 high_slices_psize; /* 4 bits per slice for now */ | ||
358 | #else | ||
359 | u16 sllp; /* SLB page size encoding */ | ||
357 | #endif | 360 | #endif |
358 | unsigned long vdso_base; | 361 | unsigned long vdso_base; |
359 | } mm_context_t; | 362 | } mm_context_t; |
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index cf95274f735e..c6a5b1735666 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h | |||
@@ -83,8 +83,8 @@ struct paca_struct { | |||
83 | 83 | ||
84 | mm_context_t context; | 84 | mm_context_t context; |
85 | u16 vmalloc_sllp; | 85 | u16 vmalloc_sllp; |
86 | u16 slb_cache[SLB_CACHE_ENTRIES]; | ||
87 | u16 slb_cache_ptr; | 86 | u16 slb_cache_ptr; |
87 | u16 slb_cache[SLB_CACHE_ENTRIES]; | ||
88 | 88 | ||
89 | /* | 89 | /* |
90 | * then miscellaneous read-write fields | 90 | * then miscellaneous read-write fields |
diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h index eab779c21995..3448a3d4bc64 100644 --- a/include/asm-powerpc/page_64.h +++ b/include/asm-powerpc/page_64.h | |||
@@ -88,57 +88,55 @@ extern unsigned int HPAGE_SHIFT; | |||
88 | 88 | ||
89 | #endif /* __ASSEMBLY__ */ | 89 | #endif /* __ASSEMBLY__ */ |
90 | 90 | ||
91 | #ifdef CONFIG_HUGETLB_PAGE | 91 | #ifdef CONFIG_PPC_MM_SLICES |
92 | 92 | ||
93 | #define HTLB_AREA_SHIFT 40 | 93 | #define SLICE_LOW_SHIFT 28 |
94 | #define HTLB_AREA_SIZE (1UL << HTLB_AREA_SHIFT) | 94 | #define SLICE_HIGH_SHIFT 40 |
95 | #define GET_HTLB_AREA(x) ((x) >> HTLB_AREA_SHIFT) | ||
96 | 95 | ||
97 | #define LOW_ESID_MASK(addr, len) \ | 96 | #define SLICE_LOW_TOP (0x100000000ul) |
98 | (((1U << (GET_ESID(min((addr)+(len)-1, 0x100000000UL))+1)) \ | 97 | #define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT) |
99 | - (1U << GET_ESID(min((addr), 0x100000000UL)))) & 0xffff) | 98 | #define SLICE_NUM_HIGH (PGTABLE_RANGE >> SLICE_HIGH_SHIFT) |
100 | #define HTLB_AREA_MASK(addr, len) (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \ | ||
101 | - (1U << GET_HTLB_AREA(addr))) & 0xffff) | ||
102 | 99 | ||
103 | #define ARCH_HAS_HUGEPAGE_ONLY_RANGE | 100 | #define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT) |
104 | #define ARCH_HAS_HUGETLB_FREE_PGD_RANGE | 101 | #define GET_HIGH_SLICE_INDEX(addr) ((addr) >> SLICE_HIGH_SHIFT) |
105 | #define ARCH_HAS_PREPARE_HUGEPAGE_RANGE | ||
106 | #define ARCH_HAS_SETCLEAR_HUGE_PTE | ||
107 | 102 | ||
108 | #define touches_hugepage_low_range(mm, addr, len) \ | 103 | #ifndef __ASSEMBLY__ |
109 | (((addr) < 0x100000000UL) \ | 104 | |
110 | && (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas)) | 105 | struct slice_mask { |
111 | #define touches_hugepage_high_range(mm, addr, len) \ | 106 | u16 low_slices; |
112 | ((((addr) + (len)) > 0x100000000UL) \ | 107 | u16 high_slices; |
113 | && (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas)) | 108 | }; |
114 | 109 | ||
115 | #define __within_hugepage_low_range(addr, len, segmask) \ | 110 | struct mm_struct; |
116 | ( (((addr)+(len)) <= 0x100000000UL) \ | ||
117 | && ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask))) | ||
118 | #define within_hugepage_low_range(addr, len) \ | ||
119 | __within_hugepage_low_range((addr), (len), \ | ||
120 | current->mm->context.low_htlb_areas) | ||
121 | #define __within_hugepage_high_range(addr, len, zonemask) \ | ||
122 | ( ((addr) >= 0x100000000UL) \ | ||
123 | && ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask))) | ||
124 | #define within_hugepage_high_range(addr, len) \ | ||
125 | __within_hugepage_high_range((addr), (len), \ | ||
126 | current->mm->context.high_htlb_areas) | ||
127 | |||
128 | #define is_hugepage_only_range(mm, addr, len) \ | ||
129 | (touches_hugepage_high_range((mm), (addr), (len)) || \ | ||
130 | touches_hugepage_low_range((mm), (addr), (len))) | ||
131 | #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA | ||
132 | 111 | ||
133 | #define in_hugepage_area(context, addr) \ | 112 | extern unsigned long slice_get_unmapped_area(unsigned long addr, |
134 | (cpu_has_feature(CPU_FTR_16M_PAGE) && \ | 113 | unsigned long len, |
135 | ( ( (addr) >= 0x100000000UL) \ | 114 | unsigned long flags, |
136 | ? ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) \ | 115 | unsigned int psize, |
137 | : ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) ) | 116 | int topdown, |
117 | int use_cache); | ||
138 | 118 | ||
139 | #else /* !CONFIG_HUGETLB_PAGE */ | 119 | extern unsigned int get_slice_psize(struct mm_struct *mm, |
120 | unsigned long addr); | ||
140 | 121 | ||
141 | #define in_hugepage_area(mm, addr) 0 | 122 | extern void slice_init_context(struct mm_struct *mm, unsigned int psize); |
123 | extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize); | ||
124 | |||
125 | #define ARCH_HAS_HUGEPAGE_ONLY_RANGE | ||
126 | extern int is_hugepage_only_range(struct mm_struct *m, | ||
127 | unsigned long addr, | ||
128 | unsigned long len); | ||
129 | |||
130 | #endif /* __ASSEMBLY__ */ | ||
131 | #else | ||
132 | #define slice_init() | ||
133 | #endif /* CONFIG_PPC_MM_SLICES */ | ||
134 | |||
135 | #ifdef CONFIG_HUGETLB_PAGE | ||
136 | |||
137 | #define ARCH_HAS_HUGETLB_FREE_PGD_RANGE | ||
138 | #define ARCH_HAS_SETCLEAR_HUGE_PTE | ||
139 | #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA | ||
142 | 140 | ||
143 | #endif /* !CONFIG_HUGETLB_PAGE */ | 141 | #endif /* !CONFIG_HUGETLB_PAGE */ |
144 | 142 | ||