diff options
Diffstat (limited to 'arch/powerpc/mm/hash_native_64.c')
-rw-r--r-- | arch/powerpc/mm/hash_native_64.c | 84 |
1 files changed, 62 insertions, 22 deletions
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 79aedaf36f2b..7b7fe2d7b9dc 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <asm/tlb.h> | 26 | #include <asm/tlb.h> |
27 | #include <asm/cputable.h> | 27 | #include <asm/cputable.h> |
28 | #include <asm/udbg.h> | 28 | #include <asm/udbg.h> |
29 | #include <asm/kexec.h> | ||
29 | 30 | ||
30 | #ifdef DEBUG_LOW | 31 | #ifdef DEBUG_LOW |
31 | #define DBG_LOW(fmt...) udbg_printf(fmt) | 32 | #define DBG_LOW(fmt...) udbg_printf(fmt) |
@@ -340,31 +341,70 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, | |||
340 | local_irq_restore(flags); | 341 | local_irq_restore(flags); |
341 | } | 342 | } |
342 | 343 | ||
343 | /* | 344 | #define LP_SHIFT 12 |
344 | * XXX This need fixing based on page size. It's only used by | 345 | #define LP_BITS 8 |
345 | * native_hpte_clear() for now which needs fixing too so they | 346 | #define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT) |
346 | * make a good pair... | ||
347 | */ | ||
348 | static unsigned long slot2va(unsigned long hpte_v, unsigned long slot) | ||
349 | { | ||
350 | unsigned long avpn = HPTE_V_AVPN_VAL(hpte_v); | ||
351 | unsigned long va; | ||
352 | 347 | ||
353 | va = avpn << 23; | 348 | static void hpte_decode(hpte_t *hpte, unsigned long slot, |
349 | int *psize, unsigned long *va) | ||
350 | { | ||
351 | unsigned long hpte_r = hpte->r; | ||
352 | unsigned long hpte_v = hpte->v; | ||
353 | unsigned long avpn; | ||
354 | int i, size, shift, penc, avpnm_bits; | ||
355 | |||
356 | if (!(hpte_v & HPTE_V_LARGE)) | ||
357 | size = MMU_PAGE_4K; | ||
358 | else { | ||
359 | for (i = 0; i < LP_BITS; i++) { | ||
360 | if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1)) | ||
361 | break; | ||
362 | } | ||
363 | penc = LP_MASK(i+1) >> LP_SHIFT; | ||
364 | for (size = 0; size < MMU_PAGE_COUNT; size++) { | ||
354 | 365 | ||
355 | if (! (hpte_v & HPTE_V_LARGE)) { | 366 | /* 4K pages are not represented by LP */ |
356 | unsigned long vpi, pteg; | 367 | if (size == MMU_PAGE_4K) |
368 | continue; | ||
357 | 369 | ||
358 | pteg = slot / HPTES_PER_GROUP; | 370 | /* valid entries have a shift value */ |
359 | if (hpte_v & HPTE_V_SECONDARY) | 371 | if (!mmu_psize_defs[size].shift) |
360 | pteg = ~pteg; | 372 | continue; |
361 | 373 | ||
362 | vpi = ((va >> 28) ^ pteg) & htab_hash_mask; | 374 | if (penc == mmu_psize_defs[size].penc) |
375 | break; | ||
376 | } | ||
377 | } | ||
363 | 378 | ||
364 | va |= vpi << PAGE_SHIFT; | 379 | /* |
380 | * FIXME, the code below works for 16M, 64K, and 4K pages as these | ||
381 | * fall under the p<=23 rules for calculating the virtual address. | ||
382 | * In the case of 16M pages, an extra bit is stolen from the AVPN | ||
383 | * field to achieve the requisite 24 bits. | ||
384 | * | ||
385 | * Does not work for 16G pages or 1 TB segments. | ||
386 | */ | ||
387 | shift = mmu_psize_defs[size].shift; | ||
388 | if (mmu_psize_defs[size].avpnm) | ||
389 | avpnm_bits = __ilog2_u64(mmu_psize_defs[size].avpnm) + 1; | ||
390 | else | ||
391 | avpnm_bits = 0; | ||
392 | if (shift - avpnm_bits <= 23) { | ||
393 | avpn = HPTE_V_AVPN_VAL(hpte_v) << 23; | ||
394 | |||
395 | if (shift < 23) { | ||
396 | unsigned long vpi, pteg; | ||
397 | |||
398 | pteg = slot / HPTES_PER_GROUP; | ||
399 | if (hpte_v & HPTE_V_SECONDARY) | ||
400 | pteg = ~pteg; | ||
401 | vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask; | ||
402 | avpn |= (vpi << mmu_psize_defs[size].shift); | ||
403 | } | ||
365 | } | 404 | } |
366 | 405 | ||
367 | return va; | 406 | *va = avpn; |
407 | *psize = size; | ||
368 | } | 408 | } |
369 | 409 | ||
370 | /* | 410 | /* |
@@ -374,15 +414,14 @@ static unsigned long slot2va(unsigned long hpte_v, unsigned long slot) | |||
374 | * | 414 | * |
375 | * TODO: add batching support when enabled. remember, no dynamic memory here, | 415 | * TODO: add batching support when enabled. remember, no dynamic memory here, |
376 | * athough there is the control page available... | 416 | * athough there is the control page available... |
377 | * | ||
378 | * XXX FIXME: 4k only for now ! | ||
379 | */ | 417 | */ |
380 | static void native_hpte_clear(void) | 418 | static void native_hpte_clear(void) |
381 | { | 419 | { |
382 | unsigned long slot, slots, flags; | 420 | unsigned long slot, slots, flags; |
383 | hpte_t *hptep = htab_address; | 421 | hpte_t *hptep = htab_address; |
384 | unsigned long hpte_v; | 422 | unsigned long hpte_v, va; |
385 | unsigned long pteg_count; | 423 | unsigned long pteg_count; |
424 | int psize; | ||
386 | 425 | ||
387 | pteg_count = htab_hash_mask + 1; | 426 | pteg_count = htab_hash_mask + 1; |
388 | 427 | ||
@@ -408,8 +447,9 @@ static void native_hpte_clear(void) | |||
408 | * already hold the native_tlbie_lock. | 447 | * already hold the native_tlbie_lock. |
409 | */ | 448 | */ |
410 | if (hpte_v & HPTE_V_VALID) { | 449 | if (hpte_v & HPTE_V_VALID) { |
450 | hpte_decode(hptep, slot, &psize, &va); | ||
411 | hptep->v = 0; | 451 | hptep->v = 0; |
412 | __tlbie(slot2va(hpte_v, slot), MMU_PAGE_4K); | 452 | __tlbie(va, psize); |
413 | } | 453 | } |
414 | } | 454 | } |
415 | 455 | ||