diff options
author | Anton Blanchard <anton@samba.org> | 2013-09-22 22:04:36 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-10-11 01:48:26 -0400 |
commit | 12f04f2be80dd8d9da24534828f3ab3189ca5af2 (patch) | |
tree | 0cdc5e766e3c3406286f808721ccd4ab9b134a20 /arch/powerpc | |
parent | 32ee1e188eadd7c997837649a107fd1c50feef7a (diff) |
powerpc: Book 3S MMU little endian support
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/mmu-hash64.h | 4 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_native_64.c | 46 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 38 |
3 files changed, 46 insertions, 42 deletions
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index c4cf01197273..807014dde821 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h | |||
@@ -135,8 +135,8 @@ extern char initial_stab[]; | |||
135 | #ifndef __ASSEMBLY__ | 135 | #ifndef __ASSEMBLY__ |
136 | 136 | ||
137 | struct hash_pte { | 137 | struct hash_pte { |
138 | unsigned long v; | 138 | __be64 v; |
139 | unsigned long r; | 139 | __be64 r; |
140 | }; | 140 | }; |
141 | 141 | ||
142 | extern struct hash_pte *htab_address; | 142 | extern struct hash_pte *htab_address; |
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index c33d939120c9..3ea26c25590b 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c | |||
@@ -35,7 +35,11 @@ | |||
35 | #define DBG_LOW(fmt...) | 35 | #define DBG_LOW(fmt...) |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #ifdef __BIG_ENDIAN__ | ||
38 | #define HPTE_LOCK_BIT 3 | 39 | #define HPTE_LOCK_BIT 3 |
40 | #else | ||
41 | #define HPTE_LOCK_BIT (56+3) | ||
42 | #endif | ||
39 | 43 | ||
40 | DEFINE_RAW_SPINLOCK(native_tlbie_lock); | 44 | DEFINE_RAW_SPINLOCK(native_tlbie_lock); |
41 | 45 | ||
@@ -172,7 +176,7 @@ static inline void tlbie(unsigned long vpn, int psize, int apsize, | |||
172 | 176 | ||
173 | static inline void native_lock_hpte(struct hash_pte *hptep) | 177 | static inline void native_lock_hpte(struct hash_pte *hptep) |
174 | { | 178 | { |
175 | unsigned long *word = &hptep->v; | 179 | unsigned long *word = (unsigned long *)&hptep->v; |
176 | 180 | ||
177 | while (1) { | 181 | while (1) { |
178 | if (!test_and_set_bit_lock(HPTE_LOCK_BIT, word)) | 182 | if (!test_and_set_bit_lock(HPTE_LOCK_BIT, word)) |
@@ -184,7 +188,7 @@ static inline void native_lock_hpte(struct hash_pte *hptep) | |||
184 | 188 | ||
185 | static inline void native_unlock_hpte(struct hash_pte *hptep) | 189 | static inline void native_unlock_hpte(struct hash_pte *hptep) |
186 | { | 190 | { |
187 | unsigned long *word = &hptep->v; | 191 | unsigned long *word = (unsigned long *)&hptep->v; |
188 | 192 | ||
189 | clear_bit_unlock(HPTE_LOCK_BIT, word); | 193 | clear_bit_unlock(HPTE_LOCK_BIT, word); |
190 | } | 194 | } |
@@ -204,10 +208,10 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn, | |||
204 | } | 208 | } |
205 | 209 | ||
206 | for (i = 0; i < HPTES_PER_GROUP; i++) { | 210 | for (i = 0; i < HPTES_PER_GROUP; i++) { |
207 | if (! (hptep->v & HPTE_V_VALID)) { | 211 | if (! (be64_to_cpu(hptep->v) & HPTE_V_VALID)) { |
208 | /* retry with lock held */ | 212 | /* retry with lock held */ |
209 | native_lock_hpte(hptep); | 213 | native_lock_hpte(hptep); |
210 | if (! (hptep->v & HPTE_V_VALID)) | 214 | if (! (be64_to_cpu(hptep->v) & HPTE_V_VALID)) |
211 | break; | 215 | break; |
212 | native_unlock_hpte(hptep); | 216 | native_unlock_hpte(hptep); |
213 | } | 217 | } |
@@ -226,14 +230,14 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn, | |||
226 | i, hpte_v, hpte_r); | 230 | i, hpte_v, hpte_r); |
227 | } | 231 | } |
228 | 232 | ||
229 | hptep->r = hpte_r; | 233 | hptep->r = cpu_to_be64(hpte_r); |
230 | /* Guarantee the second dword is visible before the valid bit */ | 234 | /* Guarantee the second dword is visible before the valid bit */ |
231 | eieio(); | 235 | eieio(); |
232 | /* | 236 | /* |
233 | * Now set the first dword including the valid bit | 237 | * Now set the first dword including the valid bit |
234 | * NOTE: this also unlocks the hpte | 238 | * NOTE: this also unlocks the hpte |
235 | */ | 239 | */ |
236 | hptep->v = hpte_v; | 240 | hptep->v = cpu_to_be64(hpte_v); |
237 | 241 | ||
238 | __asm__ __volatile__ ("ptesync" : : : "memory"); | 242 | __asm__ __volatile__ ("ptesync" : : : "memory"); |
239 | 243 | ||
@@ -254,12 +258,12 @@ static long native_hpte_remove(unsigned long hpte_group) | |||
254 | 258 | ||
255 | for (i = 0; i < HPTES_PER_GROUP; i++) { | 259 | for (i = 0; i < HPTES_PER_GROUP; i++) { |
256 | hptep = htab_address + hpte_group + slot_offset; | 260 | hptep = htab_address + hpte_group + slot_offset; |
257 | hpte_v = hptep->v; | 261 | hpte_v = be64_to_cpu(hptep->v); |
258 | 262 | ||
259 | if ((hpte_v & HPTE_V_VALID) && !(hpte_v & HPTE_V_BOLTED)) { | 263 | if ((hpte_v & HPTE_V_VALID) && !(hpte_v & HPTE_V_BOLTED)) { |
260 | /* retry with lock held */ | 264 | /* retry with lock held */ |
261 | native_lock_hpte(hptep); | 265 | native_lock_hpte(hptep); |
262 | hpte_v = hptep->v; | 266 | hpte_v = be64_to_cpu(hptep->v); |
263 | if ((hpte_v & HPTE_V_VALID) | 267 | if ((hpte_v & HPTE_V_VALID) |
264 | && !(hpte_v & HPTE_V_BOLTED)) | 268 | && !(hpte_v & HPTE_V_BOLTED)) |
265 | break; | 269 | break; |
@@ -294,7 +298,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | |||
294 | 298 | ||
295 | native_lock_hpte(hptep); | 299 | native_lock_hpte(hptep); |
296 | 300 | ||
297 | hpte_v = hptep->v; | 301 | hpte_v = be64_to_cpu(hptep->v); |
298 | /* | 302 | /* |
299 | * We need to invalidate the TLB always because hpte_remove doesn't do | 303 | * We need to invalidate the TLB always because hpte_remove doesn't do |
300 | * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less | 304 | * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less |
@@ -308,8 +312,8 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | |||
308 | } else { | 312 | } else { |
309 | DBG_LOW(" -> hit\n"); | 313 | DBG_LOW(" -> hit\n"); |
310 | /* Update the HPTE */ | 314 | /* Update the HPTE */ |
311 | hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | | 315 | hptep->r = cpu_to_be64((be64_to_cpu(hptep->r) & ~(HPTE_R_PP | HPTE_R_N)) | |
312 | (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C)); | 316 | (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C))); |
313 | } | 317 | } |
314 | native_unlock_hpte(hptep); | 318 | native_unlock_hpte(hptep); |
315 | 319 | ||
@@ -334,7 +338,7 @@ static long native_hpte_find(unsigned long vpn, int psize, int ssize) | |||
334 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | 338 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; |
335 | for (i = 0; i < HPTES_PER_GROUP; i++) { | 339 | for (i = 0; i < HPTES_PER_GROUP; i++) { |
336 | hptep = htab_address + slot; | 340 | hptep = htab_address + slot; |
337 | hpte_v = hptep->v; | 341 | hpte_v = be64_to_cpu(hptep->v); |
338 | 342 | ||
339 | if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) | 343 | if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) |
340 | /* HPTE matches */ | 344 | /* HPTE matches */ |
@@ -369,8 +373,9 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, | |||
369 | hptep = htab_address + slot; | 373 | hptep = htab_address + slot; |
370 | 374 | ||
371 | /* Update the HPTE */ | 375 | /* Update the HPTE */ |
372 | hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | | 376 | hptep->r = cpu_to_be64((be64_to_cpu(hptep->r) & |
373 | (newpp & (HPTE_R_PP | HPTE_R_N)); | 377 | ~(HPTE_R_PP | HPTE_R_N)) | |
378 | (newpp & (HPTE_R_PP | HPTE_R_N))); | ||
374 | /* | 379 | /* |
375 | * Ensure it is out of the tlb too. Bolted entries base and | 380 | * Ensure it is out of the tlb too. Bolted entries base and |
376 | * actual page size will be same. | 381 | * actual page size will be same. |
@@ -392,7 +397,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn, | |||
392 | 397 | ||
393 | want_v = hpte_encode_avpn(vpn, bpsize, ssize); | 398 | want_v = hpte_encode_avpn(vpn, bpsize, ssize); |
394 | native_lock_hpte(hptep); | 399 | native_lock_hpte(hptep); |
395 | hpte_v = hptep->v; | 400 | hpte_v = be64_to_cpu(hptep->v); |
396 | 401 | ||
397 | /* | 402 | /* |
398 | * We need to invalidate the TLB always because hpte_remove doesn't do | 403 | * We need to invalidate the TLB always because hpte_remove doesn't do |
@@ -458,7 +463,7 @@ static void native_hugepage_invalidate(struct mm_struct *mm, | |||
458 | hptep = htab_address + slot; | 463 | hptep = htab_address + slot; |
459 | want_v = hpte_encode_avpn(vpn, psize, ssize); | 464 | want_v = hpte_encode_avpn(vpn, psize, ssize); |
460 | native_lock_hpte(hptep); | 465 | native_lock_hpte(hptep); |
461 | hpte_v = hptep->v; | 466 | hpte_v = be64_to_cpu(hptep->v); |
462 | 467 | ||
463 | /* Even if we miss, we need to invalidate the TLB */ | 468 | /* Even if we miss, we need to invalidate the TLB */ |
464 | if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) | 469 | if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) |
@@ -519,11 +524,12 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, | |||
519 | int *psize, int *apsize, int *ssize, unsigned long *vpn) | 524 | int *psize, int *apsize, int *ssize, unsigned long *vpn) |
520 | { | 525 | { |
521 | unsigned long avpn, pteg, vpi; | 526 | unsigned long avpn, pteg, vpi; |
522 | unsigned long hpte_v = hpte->v; | 527 | unsigned long hpte_v = be64_to_cpu(hpte->v); |
528 | unsigned long hpte_r = be64_to_cpu(hpte->r); | ||
523 | unsigned long vsid, seg_off; | 529 | unsigned long vsid, seg_off; |
524 | int size, a_size, shift; | 530 | int size, a_size, shift; |
525 | /* Look at the 8 bit LP value */ | 531 | /* Look at the 8 bit LP value */ |
526 | unsigned int lp = (hpte->r >> LP_SHIFT) & ((1 << LP_BITS) - 1); | 532 | unsigned int lp = (hpte_r >> LP_SHIFT) & ((1 << LP_BITS) - 1); |
527 | 533 | ||
528 | if (!(hpte_v & HPTE_V_LARGE)) { | 534 | if (!(hpte_v & HPTE_V_LARGE)) { |
529 | size = MMU_PAGE_4K; | 535 | size = MMU_PAGE_4K; |
@@ -612,7 +618,7 @@ static void native_hpte_clear(void) | |||
612 | * running, right? and for crash dump, we probably | 618 | * running, right? and for crash dump, we probably |
613 | * don't want to wait for a maybe bad cpu. | 619 | * don't want to wait for a maybe bad cpu. |
614 | */ | 620 | */ |
615 | hpte_v = hptep->v; | 621 | hpte_v = be64_to_cpu(hptep->v); |
616 | 622 | ||
617 | /* | 623 | /* |
618 | * Call __tlbie() here rather than tlbie() since we | 624 | * Call __tlbie() here rather than tlbie() since we |
@@ -664,7 +670,7 @@ static void native_flush_hash_range(unsigned long number, int local) | |||
664 | hptep = htab_address + slot; | 670 | hptep = htab_address + slot; |
665 | want_v = hpte_encode_avpn(vpn, psize, ssize); | 671 | want_v = hpte_encode_avpn(vpn, psize, ssize); |
666 | native_lock_hpte(hptep); | 672 | native_lock_hpte(hptep); |
667 | hpte_v = hptep->v; | 673 | hpte_v = be64_to_cpu(hptep->v); |
668 | if (!HPTE_V_COMPARE(hpte_v, want_v) || | 674 | if (!HPTE_V_COMPARE(hpte_v, want_v) || |
669 | !(hpte_v & HPTE_V_VALID)) | 675 | !(hpte_v & HPTE_V_VALID)) |
670 | native_unlock_hpte(hptep); | 676 | native_unlock_hpte(hptep); |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index bde8b5589755..6176b3cdf579 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -251,19 +251,18 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node, | |||
251 | void *data) | 251 | void *data) |
252 | { | 252 | { |
253 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 253 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
254 | u32 *prop; | 254 | __be32 *prop; |
255 | unsigned long size = 0; | 255 | unsigned long size = 0; |
256 | 256 | ||
257 | /* We are scanning "cpu" nodes only */ | 257 | /* We are scanning "cpu" nodes only */ |
258 | if (type == NULL || strcmp(type, "cpu") != 0) | 258 | if (type == NULL || strcmp(type, "cpu") != 0) |
259 | return 0; | 259 | return 0; |
260 | 260 | ||
261 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,processor-segment-sizes", | 261 | prop = of_get_flat_dt_prop(node, "ibm,processor-segment-sizes", &size); |
262 | &size); | ||
263 | if (prop == NULL) | 262 | if (prop == NULL) |
264 | return 0; | 263 | return 0; |
265 | for (; size >= 4; size -= 4, ++prop) { | 264 | for (; size >= 4; size -= 4, ++prop) { |
266 | if (prop[0] == 40) { | 265 | if (be32_to_cpu(prop[0]) == 40) { |
267 | DBG("1T segment support detected\n"); | 266 | DBG("1T segment support detected\n"); |
268 | cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT; | 267 | cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT; |
269 | return 1; | 268 | return 1; |
@@ -307,23 +306,22 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, | |||
307 | void *data) | 306 | void *data) |
308 | { | 307 | { |
309 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 308 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
310 | u32 *prop; | 309 | __be32 *prop; |
311 | unsigned long size = 0; | 310 | unsigned long size = 0; |
312 | 311 | ||
313 | /* We are scanning "cpu" nodes only */ | 312 | /* We are scanning "cpu" nodes only */ |
314 | if (type == NULL || strcmp(type, "cpu") != 0) | 313 | if (type == NULL || strcmp(type, "cpu") != 0) |
315 | return 0; | 314 | return 0; |
316 | 315 | ||
317 | prop = (u32 *)of_get_flat_dt_prop(node, | 316 | prop = of_get_flat_dt_prop(node, "ibm,segment-page-sizes", &size); |
318 | "ibm,segment-page-sizes", &size); | ||
319 | if (prop != NULL) { | 317 | if (prop != NULL) { |
320 | pr_info("Page sizes from device-tree:\n"); | 318 | pr_info("Page sizes from device-tree:\n"); |
321 | size /= 4; | 319 | size /= 4; |
322 | cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE); | 320 | cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE); |
323 | while(size > 0) { | 321 | while(size > 0) { |
324 | unsigned int base_shift = prop[0]; | 322 | unsigned int base_shift = be32_to_cpu(prop[0]); |
325 | unsigned int slbenc = prop[1]; | 323 | unsigned int slbenc = be32_to_cpu(prop[1]); |
326 | unsigned int lpnum = prop[2]; | 324 | unsigned int lpnum = be32_to_cpu(prop[2]); |
327 | struct mmu_psize_def *def; | 325 | struct mmu_psize_def *def; |
328 | int idx, base_idx; | 326 | int idx, base_idx; |
329 | 327 | ||
@@ -356,8 +354,8 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, | |||
356 | def->tlbiel = 0; | 354 | def->tlbiel = 0; |
357 | 355 | ||
358 | while (size > 0 && lpnum) { | 356 | while (size > 0 && lpnum) { |
359 | unsigned int shift = prop[0]; | 357 | unsigned int shift = be32_to_cpu(prop[0]); |
360 | int penc = prop[1]; | 358 | int penc = be32_to_cpu(prop[1]); |
361 | 359 | ||
362 | prop += 2; size -= 2; | 360 | prop += 2; size -= 2; |
363 | lpnum--; | 361 | lpnum--; |
@@ -390,8 +388,8 @@ static int __init htab_dt_scan_hugepage_blocks(unsigned long node, | |||
390 | const char *uname, int depth, | 388 | const char *uname, int depth, |
391 | void *data) { | 389 | void *data) { |
392 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 390 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
393 | unsigned long *addr_prop; | 391 | __be64 *addr_prop; |
394 | u32 *page_count_prop; | 392 | __be32 *page_count_prop; |
395 | unsigned int expected_pages; | 393 | unsigned int expected_pages; |
396 | long unsigned int phys_addr; | 394 | long unsigned int phys_addr; |
397 | long unsigned int block_size; | 395 | long unsigned int block_size; |
@@ -405,12 +403,12 @@ static int __init htab_dt_scan_hugepage_blocks(unsigned long node, | |||
405 | page_count_prop = of_get_flat_dt_prop(node, "ibm,expected#pages", NULL); | 403 | page_count_prop = of_get_flat_dt_prop(node, "ibm,expected#pages", NULL); |
406 | if (page_count_prop == NULL) | 404 | if (page_count_prop == NULL) |
407 | return 0; | 405 | return 0; |
408 | expected_pages = (1 << page_count_prop[0]); | 406 | expected_pages = (1 << be32_to_cpu(page_count_prop[0])); |
409 | addr_prop = of_get_flat_dt_prop(node, "reg", NULL); | 407 | addr_prop = of_get_flat_dt_prop(node, "reg", NULL); |
410 | if (addr_prop == NULL) | 408 | if (addr_prop == NULL) |
411 | return 0; | 409 | return 0; |
412 | phys_addr = addr_prop[0]; | 410 | phys_addr = be64_to_cpu(addr_prop[0]); |
413 | block_size = addr_prop[1]; | 411 | block_size = be64_to_cpu(addr_prop[1]); |
414 | if (block_size != (16 * GB)) | 412 | if (block_size != (16 * GB)) |
415 | return 0; | 413 | return 0; |
416 | printk(KERN_INFO "Huge page(16GB) memory: " | 414 | printk(KERN_INFO "Huge page(16GB) memory: " |
@@ -534,16 +532,16 @@ static int __init htab_dt_scan_pftsize(unsigned long node, | |||
534 | void *data) | 532 | void *data) |
535 | { | 533 | { |
536 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 534 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
537 | u32 *prop; | 535 | __be32 *prop; |
538 | 536 | ||
539 | /* We are scanning "cpu" nodes only */ | 537 | /* We are scanning "cpu" nodes only */ |
540 | if (type == NULL || strcmp(type, "cpu") != 0) | 538 | if (type == NULL || strcmp(type, "cpu") != 0) |
541 | return 0; | 539 | return 0; |
542 | 540 | ||
543 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,pft-size", NULL); | 541 | prop = of_get_flat_dt_prop(node, "ibm,pft-size", NULL); |
544 | if (prop != NULL) { | 542 | if (prop != NULL) { |
545 | /* pft_size[0] is the NUMA CEC cookie */ | 543 | /* pft_size[0] is the NUMA CEC cookie */ |
546 | ppc64_pft_size = prop[1]; | 544 | ppc64_pft_size = be32_to_cpu(prop[1]); |
547 | return 1; | 545 | return 1; |
548 | } | 546 | } |
549 | return 0; | 547 | return 0; |