diff options
Diffstat (limited to 'arch/ppc64/mm')
-rw-r--r-- | arch/ppc64/mm/hash_native.c | 3 | ||||
-rw-r--r-- | arch/ppc64/mm/hash_utils.c | 4 | ||||
-rw-r--r-- | arch/ppc64/mm/hugetlbpage.c | 388 | ||||
-rw-r--r-- | arch/ppc64/mm/imalloc.c | 2 | ||||
-rw-r--r-- | arch/ppc64/mm/init.c | 96 | ||||
-rw-r--r-- | arch/ppc64/mm/numa.c | 2 | ||||
-rw-r--r-- | arch/ppc64/mm/slb_low.S | 25 | ||||
-rw-r--r-- | arch/ppc64/mm/tlb.c | 95 |
8 files changed, 339 insertions, 276 deletions
diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c index a6abd3a979bf..7626bb59954d 100644 --- a/arch/ppc64/mm/hash_native.c +++ b/arch/ppc64/mm/hash_native.c | |||
@@ -51,7 +51,6 @@ long native_hpte_insert(unsigned long hpte_group, unsigned long va, | |||
51 | unsigned long prpn, unsigned long vflags, | 51 | unsigned long prpn, unsigned long vflags, |
52 | unsigned long rflags) | 52 | unsigned long rflags) |
53 | { | 53 | { |
54 | unsigned long arpn = physRpn_to_absRpn(prpn); | ||
55 | hpte_t *hptep = htab_address + hpte_group; | 54 | hpte_t *hptep = htab_address + hpte_group; |
56 | unsigned long hpte_v, hpte_r; | 55 | unsigned long hpte_v, hpte_r; |
57 | int i; | 56 | int i; |
@@ -74,7 +73,7 @@ long native_hpte_insert(unsigned long hpte_group, unsigned long va, | |||
74 | hpte_v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID; | 73 | hpte_v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID; |
75 | if (vflags & HPTE_V_LARGE) | 74 | if (vflags & HPTE_V_LARGE) |
76 | va &= ~(1UL << HPTE_V_AVPN_SHIFT); | 75 | va &= ~(1UL << HPTE_V_AVPN_SHIFT); |
77 | hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags; | 76 | hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags; |
78 | 77 | ||
79 | hptep->r = hpte_r; | 78 | hptep->r = hpte_r; |
80 | /* Guarantee the second dword is visible before the valid bit */ | 79 | /* Guarantee the second dword is visible before the valid bit */ |
diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c index 623b5d130c31..09475c8edf7c 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/ppc64/mm/hash_utils.c | |||
@@ -210,7 +210,7 @@ void __init htab_initialize(void) | |||
210 | 210 | ||
211 | /* create bolted the linear mapping in the hash table */ | 211 | /* create bolted the linear mapping in the hash table */ |
212 | for (i=0; i < lmb.memory.cnt; i++) { | 212 | for (i=0; i < lmb.memory.cnt; i++) { |
213 | base = lmb.memory.region[i].physbase + KERNELBASE; | 213 | base = lmb.memory.region[i].base + KERNELBASE; |
214 | size = lmb.memory.region[i].size; | 214 | size = lmb.memory.region[i].size; |
215 | 215 | ||
216 | DBG("creating mapping for region: %lx : %lx\n", base, size); | 216 | DBG("creating mapping for region: %lx : %lx\n", base, size); |
@@ -302,7 +302,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
302 | int local = 0; | 302 | int local = 0; |
303 | cpumask_t tmp; | 303 | cpumask_t tmp; |
304 | 304 | ||
305 | if ((ea & ~REGION_MASK) > EADDR_MASK) | 305 | if ((ea & ~REGION_MASK) >= PGTABLE_RANGE) |
306 | return 1; | 306 | return 1; |
307 | 307 | ||
308 | switch (REGION_ID(ea)) { | 308 | switch (REGION_ID(ea)) { |
diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index f9524602818d..e7833c80eb68 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c | |||
@@ -27,124 +27,94 @@ | |||
27 | 27 | ||
28 | #include <linux/sysctl.h> | 28 | #include <linux/sysctl.h> |
29 | 29 | ||
30 | #define HUGEPGDIR_SHIFT (HPAGE_SHIFT + PAGE_SHIFT - 3) | 30 | #define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT) |
31 | #define HUGEPGDIR_SIZE (1UL << HUGEPGDIR_SHIFT) | 31 | #define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT) |
32 | #define HUGEPGDIR_MASK (~(HUGEPGDIR_SIZE-1)) | ||
33 | 32 | ||
34 | #define HUGEPTE_INDEX_SIZE 9 | 33 | /* Modelled after find_linux_pte() */ |
35 | #define HUGEPGD_INDEX_SIZE 10 | 34 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) |
36 | |||
37 | #define PTRS_PER_HUGEPTE (1 << HUGEPTE_INDEX_SIZE) | ||
38 | #define PTRS_PER_HUGEPGD (1 << HUGEPGD_INDEX_SIZE) | ||
39 | |||
40 | static inline int hugepgd_index(unsigned long addr) | ||
41 | { | ||
42 | return (addr & ~REGION_MASK) >> HUGEPGDIR_SHIFT; | ||
43 | } | ||
44 | |||
45 | static pud_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr) | ||
46 | { | 35 | { |
47 | int index; | 36 | pgd_t *pg; |
37 | pud_t *pu; | ||
38 | pmd_t *pm; | ||
39 | pte_t *pt; | ||
48 | 40 | ||
49 | if (! mm->context.huge_pgdir) | 41 | BUG_ON(! in_hugepage_area(mm->context, addr)); |
50 | return NULL; | ||
51 | 42 | ||
43 | addr &= HPAGE_MASK; | ||
44 | |||
45 | pg = pgd_offset(mm, addr); | ||
46 | if (!pgd_none(*pg)) { | ||
47 | pu = pud_offset(pg, addr); | ||
48 | if (!pud_none(*pu)) { | ||
49 | pm = pmd_offset(pu, addr); | ||
50 | pt = (pte_t *)pm; | ||
51 | BUG_ON(!pmd_none(*pm) | ||
52 | && !(pte_present(*pt) && pte_huge(*pt))); | ||
53 | return pt; | ||
54 | } | ||
55 | } | ||
52 | 56 | ||
53 | index = hugepgd_index(addr); | 57 | return NULL; |
54 | BUG_ON(index >= PTRS_PER_HUGEPGD); | ||
55 | return (pud_t *)(mm->context.huge_pgdir + index); | ||
56 | } | 58 | } |
57 | 59 | ||
58 | static inline pte_t *hugepte_offset(pud_t *dir, unsigned long addr) | 60 | pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) |
59 | { | 61 | { |
60 | int index; | 62 | pgd_t *pg; |
61 | 63 | pud_t *pu; | |
62 | if (pud_none(*dir)) | 64 | pmd_t *pm; |
63 | return NULL; | 65 | pte_t *pt; |
64 | 66 | ||
65 | index = (addr >> HPAGE_SHIFT) % PTRS_PER_HUGEPTE; | ||
66 | return (pte_t *)pud_page(*dir) + index; | ||
67 | } | ||
68 | |||
69 | static pud_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr) | ||
70 | { | ||
71 | BUG_ON(! in_hugepage_area(mm->context, addr)); | 67 | BUG_ON(! in_hugepage_area(mm->context, addr)); |
72 | 68 | ||
73 | if (! mm->context.huge_pgdir) { | 69 | addr &= HPAGE_MASK; |
74 | pgd_t *new; | ||
75 | spin_unlock(&mm->page_table_lock); | ||
76 | /* Don't use pgd_alloc(), because we want __GFP_REPEAT */ | ||
77 | new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT); | ||
78 | BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE)); | ||
79 | spin_lock(&mm->page_table_lock); | ||
80 | 70 | ||
81 | /* | 71 | pg = pgd_offset(mm, addr); |
82 | * Because we dropped the lock, we should re-check the | 72 | pu = pud_alloc(mm, pg, addr); |
83 | * entry, as somebody else could have populated it.. | ||
84 | */ | ||
85 | if (mm->context.huge_pgdir) | ||
86 | pgd_free(new); | ||
87 | else | ||
88 | mm->context.huge_pgdir = new; | ||
89 | } | ||
90 | return hugepgd_offset(mm, addr); | ||
91 | } | ||
92 | 73 | ||
93 | static pte_t *hugepte_alloc(struct mm_struct *mm, pud_t *dir, unsigned long addr) | 74 | if (pu) { |
94 | { | 75 | pm = pmd_alloc(mm, pu, addr); |
95 | if (! pud_present(*dir)) { | 76 | if (pm) { |
96 | pte_t *new; | 77 | pt = (pte_t *)pm; |
97 | 78 | BUG_ON(!pmd_none(*pm) | |
98 | spin_unlock(&mm->page_table_lock); | 79 | && !(pte_present(*pt) && pte_huge(*pt))); |
99 | new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT); | 80 | return pt; |
100 | BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE)); | ||
101 | spin_lock(&mm->page_table_lock); | ||
102 | /* | ||
103 | * Because we dropped the lock, we should re-check the | ||
104 | * entry, as somebody else could have populated it.. | ||
105 | */ | ||
106 | if (pud_present(*dir)) { | ||
107 | if (new) | ||
108 | kmem_cache_free(zero_cache, new); | ||
109 | } else { | ||
110 | struct page *ptepage; | ||
111 | |||
112 | if (! new) | ||
113 | return NULL; | ||
114 | ptepage = virt_to_page(new); | ||
115 | ptepage->mapping = (void *) mm; | ||
116 | ptepage->index = addr & HUGEPGDIR_MASK; | ||
117 | pud_populate(mm, dir, new); | ||
118 | } | 81 | } |
119 | } | 82 | } |
120 | 83 | ||
121 | return hugepte_offset(dir, addr); | 84 | return NULL; |
122 | } | 85 | } |
123 | 86 | ||
124 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | 87 | #define HUGEPTE_BATCH_SIZE (HPAGE_SIZE / PMD_SIZE) |
125 | { | ||
126 | pud_t *pud; | ||
127 | 88 | ||
128 | BUG_ON(! in_hugepage_area(mm->context, addr)); | 89 | void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, |
90 | pte_t *ptep, pte_t pte) | ||
91 | { | ||
92 | int i; | ||
129 | 93 | ||
130 | pud = hugepgd_offset(mm, addr); | 94 | if (pte_present(*ptep)) { |
131 | if (! pud) | 95 | pte_clear(mm, addr, ptep); |
132 | return NULL; | 96 | flush_tlb_pending(); |
97 | } | ||
133 | 98 | ||
134 | return hugepte_offset(pud, addr); | 99 | for (i = 0; i < HUGEPTE_BATCH_SIZE; i++) { |
100 | *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); | ||
101 | ptep++; | ||
102 | } | ||
135 | } | 103 | } |
136 | 104 | ||
137 | pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) | 105 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, |
106 | pte_t *ptep) | ||
138 | { | 107 | { |
139 | pud_t *pud; | 108 | unsigned long old = pte_update(ptep, ~0UL); |
109 | int i; | ||
140 | 110 | ||
141 | BUG_ON(! in_hugepage_area(mm->context, addr)); | 111 | if (old & _PAGE_HASHPTE) |
112 | hpte_update(mm, addr, old, 0); | ||
142 | 113 | ||
143 | pud = hugepgd_alloc(mm, addr); | 114 | for (i = 1; i < HUGEPTE_BATCH_SIZE; i++) |
144 | if (! pud) | 115 | ptep[i] = __pte(0); |
145 | return NULL; | ||
146 | 116 | ||
147 | return hugepte_alloc(mm, pud, addr); | 117 | return __pte(old); |
148 | } | 118 | } |
149 | 119 | ||
150 | /* | 120 | /* |
@@ -162,15 +132,17 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) | |||
162 | return 0; | 132 | return 0; |
163 | } | 133 | } |
164 | 134 | ||
165 | static void flush_segments(void *parm) | 135 | static void flush_low_segments(void *parm) |
166 | { | 136 | { |
167 | u16 segs = (unsigned long) parm; | 137 | u16 areas = (unsigned long) parm; |
168 | unsigned long i; | 138 | unsigned long i; |
169 | 139 | ||
170 | asm volatile("isync" : : : "memory"); | 140 | asm volatile("isync" : : : "memory"); |
171 | 141 | ||
172 | for (i = 0; i < 16; i++) { | 142 | BUILD_BUG_ON((sizeof(areas)*8) != NUM_LOW_AREAS); |
173 | if (! (segs & (1U << i))) | 143 | |
144 | for (i = 0; i < NUM_LOW_AREAS; i++) { | ||
145 | if (! (areas & (1U << i))) | ||
174 | continue; | 146 | continue; |
175 | asm volatile("slbie %0" : : "r" (i << SID_SHIFT)); | 147 | asm volatile("slbie %0" : : "r" (i << SID_SHIFT)); |
176 | } | 148 | } |
@@ -178,13 +150,33 @@ static void flush_segments(void *parm) | |||
178 | asm volatile("isync" : : : "memory"); | 150 | asm volatile("isync" : : : "memory"); |
179 | } | 151 | } |
180 | 152 | ||
181 | static int prepare_low_seg_for_htlb(struct mm_struct *mm, unsigned long seg) | 153 | static void flush_high_segments(void *parm) |
182 | { | 154 | { |
183 | unsigned long start = seg << SID_SHIFT; | 155 | u16 areas = (unsigned long) parm; |
184 | unsigned long end = (seg+1) << SID_SHIFT; | 156 | unsigned long i, j; |
157 | |||
158 | asm volatile("isync" : : : "memory"); | ||
159 | |||
160 | BUILD_BUG_ON((sizeof(areas)*8) != NUM_HIGH_AREAS); | ||
161 | |||
162 | for (i = 0; i < NUM_HIGH_AREAS; i++) { | ||
163 | if (! (areas & (1U << i))) | ||
164 | continue; | ||
165 | for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++) | ||
166 | asm volatile("slbie %0" | ||
167 | :: "r" ((i << HTLB_AREA_SHIFT) + (j << SID_SHIFT))); | ||
168 | } | ||
169 | |||
170 | asm volatile("isync" : : : "memory"); | ||
171 | } | ||
172 | |||
173 | static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area) | ||
174 | { | ||
175 | unsigned long start = area << SID_SHIFT; | ||
176 | unsigned long end = (area+1) << SID_SHIFT; | ||
185 | struct vm_area_struct *vma; | 177 | struct vm_area_struct *vma; |
186 | 178 | ||
187 | BUG_ON(seg >= 16); | 179 | BUG_ON(area >= NUM_LOW_AREAS); |
188 | 180 | ||
189 | /* Check no VMAs are in the region */ | 181 | /* Check no VMAs are in the region */ |
190 | vma = find_vma(mm, start); | 182 | vma = find_vma(mm, start); |
@@ -194,20 +186,39 @@ static int prepare_low_seg_for_htlb(struct mm_struct *mm, unsigned long seg) | |||
194 | return 0; | 186 | return 0; |
195 | } | 187 | } |
196 | 188 | ||
197 | static int open_low_hpage_segs(struct mm_struct *mm, u16 newsegs) | 189 | static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area) |
190 | { | ||
191 | unsigned long start = area << HTLB_AREA_SHIFT; | ||
192 | unsigned long end = (area+1) << HTLB_AREA_SHIFT; | ||
193 | struct vm_area_struct *vma; | ||
194 | |||
195 | BUG_ON(area >= NUM_HIGH_AREAS); | ||
196 | |||
197 | /* Check no VMAs are in the region */ | ||
198 | vma = find_vma(mm, start); | ||
199 | if (vma && (vma->vm_start < end)) | ||
200 | return -EBUSY; | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas) | ||
198 | { | 206 | { |
199 | unsigned long i; | 207 | unsigned long i; |
200 | 208 | ||
201 | newsegs &= ~(mm->context.htlb_segs); | 209 | BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS); |
202 | if (! newsegs) | 210 | BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS); |
211 | |||
212 | newareas &= ~(mm->context.low_htlb_areas); | ||
213 | if (! newareas) | ||
203 | return 0; /* The segments we want are already open */ | 214 | return 0; /* The segments we want are already open */ |
204 | 215 | ||
205 | for (i = 0; i < 16; i++) | 216 | for (i = 0; i < NUM_LOW_AREAS; i++) |
206 | if ((1 << i) & newsegs) | 217 | if ((1 << i) & newareas) |
207 | if (prepare_low_seg_for_htlb(mm, i) != 0) | 218 | if (prepare_low_area_for_htlb(mm, i) != 0) |
208 | return -EBUSY; | 219 | return -EBUSY; |
209 | 220 | ||
210 | mm->context.htlb_segs |= newsegs; | 221 | mm->context.low_htlb_areas |= newareas; |
211 | 222 | ||
212 | /* update the paca copy of the context struct */ | 223 | /* update the paca copy of the context struct */ |
213 | get_paca()->context = mm->context; | 224 | get_paca()->context = mm->context; |
@@ -215,29 +226,63 @@ static int open_low_hpage_segs(struct mm_struct *mm, u16 newsegs) | |||
215 | /* the context change must make it to memory before the flush, | 226 | /* the context change must make it to memory before the flush, |
216 | * so that further SLB misses do the right thing. */ | 227 | * so that further SLB misses do the right thing. */ |
217 | mb(); | 228 | mb(); |
218 | on_each_cpu(flush_segments, (void *)(unsigned long)newsegs, 0, 1); | 229 | on_each_cpu(flush_low_segments, (void *)(unsigned long)newareas, 0, 1); |
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas) | ||
235 | { | ||
236 | unsigned long i; | ||
237 | |||
238 | BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS); | ||
239 | BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8) | ||
240 | != NUM_HIGH_AREAS); | ||
241 | |||
242 | newareas &= ~(mm->context.high_htlb_areas); | ||
243 | if (! newareas) | ||
244 | return 0; /* The areas we want are already open */ | ||
245 | |||
246 | for (i = 0; i < NUM_HIGH_AREAS; i++) | ||
247 | if ((1 << i) & newareas) | ||
248 | if (prepare_high_area_for_htlb(mm, i) != 0) | ||
249 | return -EBUSY; | ||
250 | |||
251 | mm->context.high_htlb_areas |= newareas; | ||
252 | |||
253 | /* update the paca copy of the context struct */ | ||
254 | get_paca()->context = mm->context; | ||
255 | |||
256 | /* the context change must make it to memory before the flush, | ||
257 | * so that further SLB misses do the right thing. */ | ||
258 | mb(); | ||
259 | on_each_cpu(flush_high_segments, (void *)(unsigned long)newareas, 0, 1); | ||
219 | 260 | ||
220 | return 0; | 261 | return 0; |
221 | } | 262 | } |
222 | 263 | ||
223 | int prepare_hugepage_range(unsigned long addr, unsigned long len) | 264 | int prepare_hugepage_range(unsigned long addr, unsigned long len) |
224 | { | 265 | { |
225 | if (within_hugepage_high_range(addr, len)) | 266 | int err; |
226 | return 0; | 267 | |
227 | else if ((addr < 0x100000000UL) && ((addr+len) < 0x100000000UL)) { | 268 | if ( (addr+len) < addr ) |
228 | int err; | 269 | return -EINVAL; |
229 | /* Yes, we need both tests, in case addr+len overflows | 270 | |
230 | * 64-bit arithmetic */ | 271 | if ((addr + len) < 0x100000000UL) |
231 | err = open_low_hpage_segs(current->mm, | 272 | err = open_low_hpage_areas(current->mm, |
232 | LOW_ESID_MASK(addr, len)); | 273 | LOW_ESID_MASK(addr, len)); |
233 | if (err) | 274 | else |
234 | printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)" | 275 | err = open_high_hpage_areas(current->mm, |
235 | " failed (segs: 0x%04hx)\n", addr, len, | 276 | HTLB_AREA_MASK(addr, len)); |
236 | LOW_ESID_MASK(addr, len)); | 277 | if (err) { |
278 | printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)" | ||
279 | " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n", | ||
280 | addr, len, | ||
281 | LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len)); | ||
237 | return err; | 282 | return err; |
238 | } | 283 | } |
239 | 284 | ||
240 | return -EINVAL; | 285 | return 0; |
241 | } | 286 | } |
242 | 287 | ||
243 | struct page * | 288 | struct page * |
@@ -309,8 +354,8 @@ full_search: | |||
309 | vma = find_vma(mm, addr); | 354 | vma = find_vma(mm, addr); |
310 | continue; | 355 | continue; |
311 | } | 356 | } |
312 | if (touches_hugepage_high_range(addr, len)) { | 357 | if (touches_hugepage_high_range(mm, addr, len)) { |
313 | addr = TASK_HPAGE_END; | 358 | addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT); |
314 | vma = find_vma(mm, addr); | 359 | vma = find_vma(mm, addr); |
315 | continue; | 360 | continue; |
316 | } | 361 | } |
@@ -389,8 +434,9 @@ hugepage_recheck: | |||
389 | if (touches_hugepage_low_range(mm, addr, len)) { | 434 | if (touches_hugepage_low_range(mm, addr, len)) { |
390 | addr = (addr & ((~0) << SID_SHIFT)) - len; | 435 | addr = (addr & ((~0) << SID_SHIFT)) - len; |
391 | goto hugepage_recheck; | 436 | goto hugepage_recheck; |
392 | } else if (touches_hugepage_high_range(addr, len)) { | 437 | } else if (touches_hugepage_high_range(mm, addr, len)) { |
393 | addr = TASK_HPAGE_BASE - len; | 438 | addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len; |
439 | goto hugepage_recheck; | ||
394 | } | 440 | } |
395 | 441 | ||
396 | /* | 442 | /* |
@@ -481,23 +527,28 @@ static unsigned long htlb_get_low_area(unsigned long len, u16 segmask) | |||
481 | return -ENOMEM; | 527 | return -ENOMEM; |
482 | } | 528 | } |
483 | 529 | ||
484 | static unsigned long htlb_get_high_area(unsigned long len) | 530 | static unsigned long htlb_get_high_area(unsigned long len, u16 areamask) |
485 | { | 531 | { |
486 | unsigned long addr = TASK_HPAGE_BASE; | 532 | unsigned long addr = 0x100000000UL; |
487 | struct vm_area_struct *vma; | 533 | struct vm_area_struct *vma; |
488 | 534 | ||
489 | vma = find_vma(current->mm, addr); | 535 | vma = find_vma(current->mm, addr); |
490 | for (vma = find_vma(current->mm, addr); | 536 | while (addr + len <= TASK_SIZE_USER64) { |
491 | addr + len <= TASK_HPAGE_END; | ||
492 | vma = vma->vm_next) { | ||
493 | BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */ | 537 | BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */ |
494 | BUG_ON(! within_hugepage_high_range(addr, len)); | 538 | |
539 | if (! __within_hugepage_high_range(addr, len, areamask)) { | ||
540 | addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT); | ||
541 | vma = find_vma(current->mm, addr); | ||
542 | continue; | ||
543 | } | ||
495 | 544 | ||
496 | if (!vma || (addr + len) <= vma->vm_start) | 545 | if (!vma || (addr + len) <= vma->vm_start) |
497 | return addr; | 546 | return addr; |
498 | addr = ALIGN(vma->vm_end, HPAGE_SIZE); | 547 | addr = ALIGN(vma->vm_end, HPAGE_SIZE); |
499 | /* Because we're in a hugepage region, this alignment | 548 | /* Depending on segmask this might not be a confirmed |
500 | * should not skip us over any VMAs */ | 549 | * hugepage region, so the ALIGN could have skipped |
550 | * some VMAs */ | ||
551 | vma = find_vma(current->mm, addr); | ||
501 | } | 552 | } |
502 | 553 | ||
503 | return -ENOMEM; | 554 | return -ENOMEM; |
@@ -507,6 +558,9 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
507 | unsigned long len, unsigned long pgoff, | 558 | unsigned long len, unsigned long pgoff, |
508 | unsigned long flags) | 559 | unsigned long flags) |
509 | { | 560 | { |
561 | int lastshift; | ||
562 | u16 areamask, curareas; | ||
563 | |||
510 | if (len & ~HPAGE_MASK) | 564 | if (len & ~HPAGE_MASK) |
511 | return -EINVAL; | 565 | return -EINVAL; |
512 | 566 | ||
@@ -514,67 +568,49 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
514 | return -EINVAL; | 568 | return -EINVAL; |
515 | 569 | ||
516 | if (test_thread_flag(TIF_32BIT)) { | 570 | if (test_thread_flag(TIF_32BIT)) { |
517 | int lastshift = 0; | 571 | curareas = current->mm->context.low_htlb_areas; |
518 | u16 segmask, cursegs = current->mm->context.htlb_segs; | ||
519 | 572 | ||
520 | /* First see if we can do the mapping in the existing | 573 | /* First see if we can do the mapping in the existing |
521 | * low hpage segments */ | 574 | * low areas */ |
522 | addr = htlb_get_low_area(len, cursegs); | 575 | addr = htlb_get_low_area(len, curareas); |
523 | if (addr != -ENOMEM) | 576 | if (addr != -ENOMEM) |
524 | return addr; | 577 | return addr; |
525 | 578 | ||
526 | for (segmask = LOW_ESID_MASK(0x100000000UL-len, len); | 579 | lastshift = 0; |
527 | ! lastshift; segmask >>=1) { | 580 | for (areamask = LOW_ESID_MASK(0x100000000UL-len, len); |
528 | if (segmask & 1) | 581 | ! lastshift; areamask >>=1) { |
582 | if (areamask & 1) | ||
529 | lastshift = 1; | 583 | lastshift = 1; |
530 | 584 | ||
531 | addr = htlb_get_low_area(len, cursegs | segmask); | 585 | addr = htlb_get_low_area(len, curareas | areamask); |
532 | if ((addr != -ENOMEM) | 586 | if ((addr != -ENOMEM) |
533 | && open_low_hpage_segs(current->mm, segmask) == 0) | 587 | && open_low_hpage_areas(current->mm, areamask) == 0) |
534 | return addr; | 588 | return addr; |
535 | } | 589 | } |
536 | printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open" | ||
537 | " enough segments\n"); | ||
538 | return -ENOMEM; | ||
539 | } else { | 590 | } else { |
540 | return htlb_get_high_area(len); | 591 | curareas = current->mm->context.high_htlb_areas; |
541 | } | ||
542 | } | ||
543 | |||
544 | void hugetlb_mm_free_pgd(struct mm_struct *mm) | ||
545 | { | ||
546 | int i; | ||
547 | pgd_t *pgdir; | ||
548 | |||
549 | spin_lock(&mm->page_table_lock); | ||
550 | |||
551 | pgdir = mm->context.huge_pgdir; | ||
552 | if (! pgdir) | ||
553 | goto out; | ||
554 | |||
555 | mm->context.huge_pgdir = NULL; | ||
556 | 592 | ||
557 | /* cleanup any hugepte pages leftover */ | 593 | /* First see if we can do the mapping in the existing |
558 | for (i = 0; i < PTRS_PER_HUGEPGD; i++) { | 594 | * high areas */ |
559 | pud_t *pud = (pud_t *)(pgdir + i); | 595 | addr = htlb_get_high_area(len, curareas); |
560 | 596 | if (addr != -ENOMEM) | |
561 | if (! pud_none(*pud)) { | 597 | return addr; |
562 | pte_t *pte = (pte_t *)pud_page(*pud); | ||
563 | struct page *ptepage = virt_to_page(pte); | ||
564 | 598 | ||
565 | ptepage->mapping = NULL; | 599 | lastshift = 0; |
600 | for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len); | ||
601 | ! lastshift; areamask >>=1) { | ||
602 | if (areamask & 1) | ||
603 | lastshift = 1; | ||
566 | 604 | ||
567 | BUG_ON(memcmp(pte, empty_zero_page, PAGE_SIZE)); | 605 | addr = htlb_get_high_area(len, curareas | areamask); |
568 | kmem_cache_free(zero_cache, pte); | 606 | if ((addr != -ENOMEM) |
607 | && open_high_hpage_areas(current->mm, areamask) == 0) | ||
608 | return addr; | ||
569 | } | 609 | } |
570 | pud_clear(pud); | ||
571 | } | 610 | } |
572 | 611 | printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open" | |
573 | BUG_ON(memcmp(pgdir, empty_zero_page, PAGE_SIZE)); | 612 | " enough areas\n"); |
574 | kmem_cache_free(zero_cache, pgdir); | 613 | return -ENOMEM; |
575 | |||
576 | out: | ||
577 | spin_unlock(&mm->page_table_lock); | ||
578 | } | 614 | } |
579 | 615 | ||
580 | int hash_huge_page(struct mm_struct *mm, unsigned long access, | 616 | int hash_huge_page(struct mm_struct *mm, unsigned long access, |
diff --git a/arch/ppc64/mm/imalloc.c b/arch/ppc64/mm/imalloc.c index b6e75b891ac0..c65b87b92756 100644 --- a/arch/ppc64/mm/imalloc.c +++ b/arch/ppc64/mm/imalloc.c | |||
@@ -31,7 +31,7 @@ static int get_free_im_addr(unsigned long size, unsigned long *im_addr) | |||
31 | break; | 31 | break; |
32 | if ((unsigned long)tmp->addr >= ioremap_bot) | 32 | if ((unsigned long)tmp->addr >= ioremap_bot) |
33 | addr = tmp->size + (unsigned long) tmp->addr; | 33 | addr = tmp->size + (unsigned long) tmp->addr; |
34 | if (addr > IMALLOC_END-size) | 34 | if (addr >= IMALLOC_END-size) |
35 | return 1; | 35 | return 1; |
36 | } | 36 | } |
37 | *im_addr = addr; | 37 | *im_addr = addr; |
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index e58a24d42879..c02dc9809ca5 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c | |||
@@ -42,7 +42,6 @@ | |||
42 | 42 | ||
43 | #include <asm/pgalloc.h> | 43 | #include <asm/pgalloc.h> |
44 | #include <asm/page.h> | 44 | #include <asm/page.h> |
45 | #include <asm/abs_addr.h> | ||
46 | #include <asm/prom.h> | 45 | #include <asm/prom.h> |
47 | #include <asm/lmb.h> | 46 | #include <asm/lmb.h> |
48 | #include <asm/rtas.h> | 47 | #include <asm/rtas.h> |
@@ -66,6 +65,14 @@ | |||
66 | #include <asm/vdso.h> | 65 | #include <asm/vdso.h> |
67 | #include <asm/imalloc.h> | 66 | #include <asm/imalloc.h> |
68 | 67 | ||
68 | #if PGTABLE_RANGE > USER_VSID_RANGE | ||
69 | #warning Limited user VSID range means pagetable space is wasted | ||
70 | #endif | ||
71 | |||
72 | #if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE) | ||
73 | #warning TASK_SIZE is smaller than it needs to be. | ||
74 | #endif | ||
75 | |||
69 | int mem_init_done; | 76 | int mem_init_done; |
70 | unsigned long ioremap_bot = IMALLOC_BASE; | 77 | unsigned long ioremap_bot = IMALLOC_BASE; |
71 | static unsigned long phbs_io_bot = PHBS_IO_BASE; | 78 | static unsigned long phbs_io_bot = PHBS_IO_BASE; |
@@ -159,7 +166,6 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags) | |||
159 | ptep = pte_alloc_kernel(&init_mm, pmdp, ea); | 166 | ptep = pte_alloc_kernel(&init_mm, pmdp, ea); |
160 | if (!ptep) | 167 | if (!ptep) |
161 | return -ENOMEM; | 168 | return -ENOMEM; |
162 | pa = abs_to_phys(pa); | ||
163 | set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, | 169 | set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, |
164 | __pgprot(flags))); | 170 | __pgprot(flags))); |
165 | spin_unlock(&init_mm.page_table_lock); | 171 | spin_unlock(&init_mm.page_table_lock); |
@@ -226,7 +232,7 @@ void __iomem * __ioremap(unsigned long addr, unsigned long size, | |||
226 | * Before that, we map using addresses going | 232 | * Before that, we map using addresses going |
227 | * up from ioremap_bot. imalloc will use | 233 | * up from ioremap_bot. imalloc will use |
228 | * the addresses from ioremap_bot through | 234 | * the addresses from ioremap_bot through |
229 | * IMALLOC_END (0xE000001fffffffff) | 235 | * IMALLOC_END |
230 | * | 236 | * |
231 | */ | 237 | */ |
232 | pa = addr & PAGE_MASK; | 238 | pa = addr & PAGE_MASK; |
@@ -417,12 +423,6 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | |||
417 | int index; | 423 | int index; |
418 | int err; | 424 | int err; |
419 | 425 | ||
420 | #ifdef CONFIG_HUGETLB_PAGE | ||
421 | /* We leave htlb_segs as it was, but for a fork, we need to | ||
422 | * clear the huge_pgdir. */ | ||
423 | mm->context.huge_pgdir = NULL; | ||
424 | #endif | ||
425 | |||
426 | again: | 426 | again: |
427 | if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) | 427 | if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) |
428 | return -ENOMEM; | 428 | return -ENOMEM; |
@@ -453,8 +453,6 @@ void destroy_context(struct mm_struct *mm) | |||
453 | spin_unlock(&mmu_context_lock); | 453 | spin_unlock(&mmu_context_lock); |
454 | 454 | ||
455 | mm->context.id = NO_CONTEXT; | 455 | mm->context.id = NO_CONTEXT; |
456 | |||
457 | hugetlb_mm_free_pgd(mm); | ||
458 | } | 456 | } |
459 | 457 | ||
460 | /* | 458 | /* |
@@ -484,9 +482,9 @@ void __init mm_init_ppc64(void) | |||
484 | for (i = 1; i < lmb.memory.cnt; i++) { | 482 | for (i = 1; i < lmb.memory.cnt; i++) { |
485 | unsigned long base, prevbase, prevsize; | 483 | unsigned long base, prevbase, prevsize; |
486 | 484 | ||
487 | prevbase = lmb.memory.region[i-1].physbase; | 485 | prevbase = lmb.memory.region[i-1].base; |
488 | prevsize = lmb.memory.region[i-1].size; | 486 | prevsize = lmb.memory.region[i-1].size; |
489 | base = lmb.memory.region[i].physbase; | 487 | base = lmb.memory.region[i].base; |
490 | if (base > (prevbase + prevsize)) { | 488 | if (base > (prevbase + prevsize)) { |
491 | io_hole_start = prevbase + prevsize; | 489 | io_hole_start = prevbase + prevsize; |
492 | io_hole_size = base - (prevbase + prevsize); | 490 | io_hole_size = base - (prevbase + prevsize); |
@@ -513,11 +511,8 @@ int page_is_ram(unsigned long pfn) | |||
513 | for (i=0; i < lmb.memory.cnt; i++) { | 511 | for (i=0; i < lmb.memory.cnt; i++) { |
514 | unsigned long base; | 512 | unsigned long base; |
515 | 513 | ||
516 | #ifdef CONFIG_MSCHUNKS | ||
517 | base = lmb.memory.region[i].physbase; | ||
518 | #else | ||
519 | base = lmb.memory.region[i].base; | 514 | base = lmb.memory.region[i].base; |
520 | #endif | 515 | |
521 | if ((paddr >= base) && | 516 | if ((paddr >= base) && |
522 | (paddr < (base + lmb.memory.region[i].size))) { | 517 | (paddr < (base + lmb.memory.region[i].size))) { |
523 | return 1; | 518 | return 1; |
@@ -547,7 +542,7 @@ void __init do_init_bootmem(void) | |||
547 | */ | 542 | */ |
548 | bootmap_pages = bootmem_bootmap_pages(total_pages); | 543 | bootmap_pages = bootmem_bootmap_pages(total_pages); |
549 | 544 | ||
550 | start = abs_to_phys(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE)); | 545 | start = lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE); |
551 | BUG_ON(!start); | 546 | BUG_ON(!start); |
552 | 547 | ||
553 | boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages); | 548 | boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages); |
@@ -558,25 +553,25 @@ void __init do_init_bootmem(void) | |||
558 | * present. | 553 | * present. |
559 | */ | 554 | */ |
560 | for (i=0; i < lmb.memory.cnt; i++) { | 555 | for (i=0; i < lmb.memory.cnt; i++) { |
561 | unsigned long physbase, size; | 556 | unsigned long base, size; |
562 | unsigned long start_pfn, end_pfn; | 557 | unsigned long start_pfn, end_pfn; |
563 | 558 | ||
564 | physbase = lmb.memory.region[i].physbase; | 559 | base = lmb.memory.region[i].base; |
565 | size = lmb.memory.region[i].size; | 560 | size = lmb.memory.region[i].size; |
566 | 561 | ||
567 | start_pfn = physbase >> PAGE_SHIFT; | 562 | start_pfn = base >> PAGE_SHIFT; |
568 | end_pfn = start_pfn + (size >> PAGE_SHIFT); | 563 | end_pfn = start_pfn + (size >> PAGE_SHIFT); |
569 | memory_present(0, start_pfn, end_pfn); | 564 | memory_present(0, start_pfn, end_pfn); |
570 | 565 | ||
571 | free_bootmem(physbase, size); | 566 | free_bootmem(base, size); |
572 | } | 567 | } |
573 | 568 | ||
574 | /* reserve the sections we're already using */ | 569 | /* reserve the sections we're already using */ |
575 | for (i=0; i < lmb.reserved.cnt; i++) { | 570 | for (i=0; i < lmb.reserved.cnt; i++) { |
576 | unsigned long physbase = lmb.reserved.region[i].physbase; | 571 | unsigned long base = lmb.reserved.region[i].base; |
577 | unsigned long size = lmb.reserved.region[i].size; | 572 | unsigned long size = lmb.reserved.region[i].size; |
578 | 573 | ||
579 | reserve_bootmem(physbase, size); | 574 | reserve_bootmem(base, size); |
580 | } | 575 | } |
581 | } | 576 | } |
582 | 577 | ||
@@ -615,10 +610,10 @@ static int __init setup_kcore(void) | |||
615 | int i; | 610 | int i; |
616 | 611 | ||
617 | for (i=0; i < lmb.memory.cnt; i++) { | 612 | for (i=0; i < lmb.memory.cnt; i++) { |
618 | unsigned long physbase, size; | 613 | unsigned long base, size; |
619 | struct kcore_list *kcore_mem; | 614 | struct kcore_list *kcore_mem; |
620 | 615 | ||
621 | physbase = lmb.memory.region[i].physbase; | 616 | base = lmb.memory.region[i].base; |
622 | size = lmb.memory.region[i].size; | 617 | size = lmb.memory.region[i].size; |
623 | 618 | ||
624 | /* GFP_ATOMIC to avoid might_sleep warnings during boot */ | 619 | /* GFP_ATOMIC to avoid might_sleep warnings during boot */ |
@@ -626,7 +621,7 @@ static int __init setup_kcore(void) | |||
626 | if (!kcore_mem) | 621 | if (!kcore_mem) |
627 | panic("mem_init: kmalloc failed\n"); | 622 | panic("mem_init: kmalloc failed\n"); |
628 | 623 | ||
629 | kclist_add(kcore_mem, __va(physbase), size); | 624 | kclist_add(kcore_mem, __va(base), size); |
630 | } | 625 | } |
631 | 626 | ||
632 | kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); | 627 | kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); |
@@ -686,9 +681,6 @@ void __init mem_init(void) | |||
686 | 681 | ||
687 | mem_init_done = 1; | 682 | mem_init_done = 1; |
688 | 683 | ||
689 | #ifdef CONFIG_PPC_ISERIES | ||
690 | iommu_vio_init(); | ||
691 | #endif | ||
692 | /* Initialize the vDSO */ | 684 | /* Initialize the vDSO */ |
693 | vdso_init(); | 685 | vdso_init(); |
694 | } | 686 | } |
@@ -833,23 +825,43 @@ void __iomem * reserve_phb_iospace(unsigned long size) | |||
833 | return virt_addr; | 825 | return virt_addr; |
834 | } | 826 | } |
835 | 827 | ||
836 | kmem_cache_t *zero_cache; | 828 | static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) |
837 | |||
838 | static void zero_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) | ||
839 | { | 829 | { |
840 | memset(pte, 0, PAGE_SIZE); | 830 | memset(addr, 0, kmem_cache_size(cache)); |
841 | } | 831 | } |
842 | 832 | ||
833 | static const int pgtable_cache_size[2] = { | ||
834 | PTE_TABLE_SIZE, PMD_TABLE_SIZE | ||
835 | }; | ||
836 | static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { | ||
837 | "pgd_pte_cache", "pud_pmd_cache", | ||
838 | }; | ||
839 | |||
840 | kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)]; | ||
841 | |||
843 | void pgtable_cache_init(void) | 842 | void pgtable_cache_init(void) |
844 | { | 843 | { |
845 | zero_cache = kmem_cache_create("zero", | 844 | int i; |
846 | PAGE_SIZE, | 845 | |
847 | 0, | 846 | BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]); |
848 | SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, | 847 | BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]); |
849 | zero_ctor, | 848 | BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]); |
850 | NULL); | 849 | BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]); |
851 | if (!zero_cache) | 850 | |
852 | panic("pgtable_cache_init(): could not create zero_cache!\n"); | 851 | for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) { |
852 | int size = pgtable_cache_size[i]; | ||
853 | const char *name = pgtable_cache_name[i]; | ||
854 | |||
855 | pgtable_cache[i] = kmem_cache_create(name, | ||
856 | size, size, | ||
857 | SLAB_HWCACHE_ALIGN | ||
858 | | SLAB_MUST_HWCACHE_ALIGN, | ||
859 | zero_ctor, | ||
860 | NULL); | ||
861 | if (! pgtable_cache[i]) | ||
862 | panic("pgtable_cache_init(): could not create %s!\n", | ||
863 | name); | ||
864 | } | ||
853 | } | 865 | } |
854 | 866 | ||
855 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, | 867 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, |
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c index 0b191f2de016..c3116f0d788c 100644 --- a/arch/ppc64/mm/numa.c +++ b/arch/ppc64/mm/numa.c | |||
@@ -671,7 +671,7 @@ new_range: | |||
671 | * Mark reserved regions on this node | 671 | * Mark reserved regions on this node |
672 | */ | 672 | */ |
673 | for (i = 0; i < lmb.reserved.cnt; i++) { | 673 | for (i = 0; i < lmb.reserved.cnt; i++) { |
674 | unsigned long physbase = lmb.reserved.region[i].physbase; | 674 | unsigned long physbase = lmb.reserved.region[i].base; |
675 | unsigned long size = lmb.reserved.region[i].size; | 675 | unsigned long size = lmb.reserved.region[i].size; |
676 | 676 | ||
677 | if (pa_to_nid(physbase) != nid && | 677 | if (pa_to_nid(physbase) != nid && |
diff --git a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S index 8379d678f70f..bab255889c58 100644 --- a/arch/ppc64/mm/slb_low.S +++ b/arch/ppc64/mm/slb_low.S | |||
@@ -89,28 +89,29 @@ END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE) | |||
89 | b 9f | 89 | b 9f |
90 | 90 | ||
91 | 0: /* user address: proto-VSID = context<<15 | ESID */ | 91 | 0: /* user address: proto-VSID = context<<15 | ESID */ |
92 | li r11,SLB_VSID_USER | 92 | srdi. r9,r3,USER_ESID_BITS |
93 | |||
94 | srdi. r9,r3,13 | ||
95 | bne- 8f /* invalid ea bits set */ | 93 | bne- 8f /* invalid ea bits set */ |
96 | 94 | ||
97 | #ifdef CONFIG_HUGETLB_PAGE | 95 | #ifdef CONFIG_HUGETLB_PAGE |
98 | BEGIN_FTR_SECTION | 96 | BEGIN_FTR_SECTION |
99 | /* check against the hugepage ranges */ | 97 | lhz r9,PACAHIGHHTLBAREAS(r13) |
100 | cmpldi r3,(TASK_HPAGE_END>>SID_SHIFT) | 98 | srdi r11,r3,(HTLB_AREA_SHIFT-SID_SHIFT) |
101 | bge 6f /* >= TASK_HPAGE_END */ | 99 | srd r9,r9,r11 |
102 | cmpldi r3,(TASK_HPAGE_BASE>>SID_SHIFT) | 100 | andi. r9,r9,1 |
103 | bge 5f /* TASK_HPAGE_BASE..TASK_HPAGE_END */ | 101 | bne 5f |
102 | |||
103 | li r11,SLB_VSID_USER | ||
104 | |||
104 | cmpldi r3,16 | 105 | cmpldi r3,16 |
105 | bge 6f /* 4GB..TASK_HPAGE_BASE */ | 106 | bge 6f |
106 | 107 | ||
107 | lhz r9,PACAHTLBSEGS(r13) | 108 | lhz r9,PACALOWHTLBAREAS(r13) |
108 | srd r9,r9,r3 | 109 | srd r9,r9,r3 |
109 | andi. r9,r9,1 | 110 | andi. r9,r9,1 |
111 | |||
110 | beq 6f | 112 | beq 6f |
111 | 113 | ||
112 | 5: /* this is a hugepage user address */ | 114 | 5: li r11,SLB_VSID_USER|SLB_VSID_L |
113 | li r11,(SLB_VSID_USER|SLB_VSID_L) | ||
114 | END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE) | 115 | END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE) |
115 | #endif /* CONFIG_HUGETLB_PAGE */ | 116 | #endif /* CONFIG_HUGETLB_PAGE */ |
116 | 117 | ||
diff --git a/arch/ppc64/mm/tlb.c b/arch/ppc64/mm/tlb.c index 26f0172c4527..d8a6593a13f0 100644 --- a/arch/ppc64/mm/tlb.c +++ b/arch/ppc64/mm/tlb.c | |||
@@ -41,7 +41,58 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | |||
41 | DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); | 41 | DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); |
42 | unsigned long pte_freelist_forced_free; | 42 | unsigned long pte_freelist_forced_free; |
43 | 43 | ||
44 | void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage) | 44 | struct pte_freelist_batch |
45 | { | ||
46 | struct rcu_head rcu; | ||
47 | unsigned int index; | ||
48 | pgtable_free_t tables[0]; | ||
49 | }; | ||
50 | |||
51 | DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); | ||
52 | unsigned long pte_freelist_forced_free; | ||
53 | |||
54 | #define PTE_FREELIST_SIZE \ | ||
55 | ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \ | ||
56 | / sizeof(pgtable_free_t)) | ||
57 | |||
58 | #ifdef CONFIG_SMP | ||
59 | static void pte_free_smp_sync(void *arg) | ||
60 | { | ||
61 | /* Do nothing, just ensure we sync with all CPUs */ | ||
62 | } | ||
63 | #endif | ||
64 | |||
65 | /* This is only called when we are critically out of memory | ||
66 | * (and fail to get a page in pte_free_tlb). | ||
67 | */ | ||
68 | static void pgtable_free_now(pgtable_free_t pgf) | ||
69 | { | ||
70 | pte_freelist_forced_free++; | ||
71 | |||
72 | smp_call_function(pte_free_smp_sync, NULL, 0, 1); | ||
73 | |||
74 | pgtable_free(pgf); | ||
75 | } | ||
76 | |||
77 | static void pte_free_rcu_callback(struct rcu_head *head) | ||
78 | { | ||
79 | struct pte_freelist_batch *batch = | ||
80 | container_of(head, struct pte_freelist_batch, rcu); | ||
81 | unsigned int i; | ||
82 | |||
83 | for (i = 0; i < batch->index; i++) | ||
84 | pgtable_free(batch->tables[i]); | ||
85 | |||
86 | free_page((unsigned long)batch); | ||
87 | } | ||
88 | |||
89 | static void pte_free_submit(struct pte_freelist_batch *batch) | ||
90 | { | ||
91 | INIT_RCU_HEAD(&batch->rcu); | ||
92 | call_rcu(&batch->rcu, pte_free_rcu_callback); | ||
93 | } | ||
94 | |||
95 | void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) | ||
45 | { | 96 | { |
46 | /* This is safe as we are holding page_table_lock */ | 97 | /* This is safe as we are holding page_table_lock */ |
47 | cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id()); | 98 | cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id()); |
@@ -49,19 +100,19 @@ void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage) | |||
49 | 100 | ||
50 | if (atomic_read(&tlb->mm->mm_users) < 2 || | 101 | if (atomic_read(&tlb->mm->mm_users) < 2 || |
51 | cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) { | 102 | cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) { |
52 | pte_free(ptepage); | 103 | pgtable_free(pgf); |
53 | return; | 104 | return; |
54 | } | 105 | } |
55 | 106 | ||
56 | if (*batchp == NULL) { | 107 | if (*batchp == NULL) { |
57 | *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC); | 108 | *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC); |
58 | if (*batchp == NULL) { | 109 | if (*batchp == NULL) { |
59 | pte_free_now(ptepage); | 110 | pgtable_free_now(pgf); |
60 | return; | 111 | return; |
61 | } | 112 | } |
62 | (*batchp)->index = 0; | 113 | (*batchp)->index = 0; |
63 | } | 114 | } |
64 | (*batchp)->pages[(*batchp)->index++] = ptepage; | 115 | (*batchp)->tables[(*batchp)->index++] = pgf; |
65 | if ((*batchp)->index == PTE_FREELIST_SIZE) { | 116 | if ((*batchp)->index == PTE_FREELIST_SIZE) { |
66 | pte_free_submit(*batchp); | 117 | pte_free_submit(*batchp); |
67 | *batchp = NULL; | 118 | *batchp = NULL; |
@@ -132,42 +183,6 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch) | |||
132 | put_cpu(); | 183 | put_cpu(); |
133 | } | 184 | } |
134 | 185 | ||
135 | #ifdef CONFIG_SMP | ||
136 | static void pte_free_smp_sync(void *arg) | ||
137 | { | ||
138 | /* Do nothing, just ensure we sync with all CPUs */ | ||
139 | } | ||
140 | #endif | ||
141 | |||
142 | /* This is only called when we are critically out of memory | ||
143 | * (and fail to get a page in pte_free_tlb). | ||
144 | */ | ||
145 | void pte_free_now(struct page *ptepage) | ||
146 | { | ||
147 | pte_freelist_forced_free++; | ||
148 | |||
149 | smp_call_function(pte_free_smp_sync, NULL, 0, 1); | ||
150 | |||
151 | pte_free(ptepage); | ||
152 | } | ||
153 | |||
154 | static void pte_free_rcu_callback(struct rcu_head *head) | ||
155 | { | ||
156 | struct pte_freelist_batch *batch = | ||
157 | container_of(head, struct pte_freelist_batch, rcu); | ||
158 | unsigned int i; | ||
159 | |||
160 | for (i = 0; i < batch->index; i++) | ||
161 | pte_free(batch->pages[i]); | ||
162 | free_page((unsigned long)batch); | ||
163 | } | ||
164 | |||
165 | void pte_free_submit(struct pte_freelist_batch *batch) | ||
166 | { | ||
167 | INIT_RCU_HEAD(&batch->rcu); | ||
168 | call_rcu(&batch->rcu, pte_free_rcu_callback); | ||
169 | } | ||
170 | |||
171 | void pte_free_finish(void) | 186 | void pte_free_finish(void) |
172 | { | 187 | { |
173 | /* This is safe as we are holding page_table_lock */ | 188 | /* This is safe as we are holding page_table_lock */ |