aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2013-04-28 05:37:36 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-04-30 02:00:18 -0400
commit7e74c3921ad9610c0b49f28b8fc69f7480505841 (patch)
treeb675a41480e84369e4d8406fe5fd7b05f35488dd /arch/powerpc/mm
parentb1022fbd293564de91596b8775340cf41ad5214c (diff)
powerpc: Fix hpte_decode to use the correct decoding for page sizes
As per ISA doc, we encode base and actual page size in the LP bits of PTE. The number of bit used to encode the page sizes depend on actual page size. ISA doc lists this as PTE LP actual page size rrrr rrrz >=8KB rrrr rrzz >=16KB rrrr rzzz >=32KB rrrr zzzz >=64KB rrrz zzzz >=128KB rrzz zzzz >=256KB rzzz zzzz >=512KB zzzz zzzz >=1MB ISA doc also says "The values of the “z” bits used to specify each size, along with all possible values of “r” bits in the LP field, must result in LP values distinct from other LP values for other sizes." based on the above update hpte_decode to use the correct decoding for LP bits. Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Acked-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/hash_native_64.c53
1 files changed, 22 insertions, 31 deletions
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 14e3fe896baf..bb920ee15627 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -245,19 +245,10 @@ static long native_hpte_remove(unsigned long hpte_group)
245 return i; 245 return i;
246} 246}
247 247
248static inline int hpte_actual_psize(struct hash_pte *hptep, int psize) 248static inline int __hpte_actual_psize(unsigned int lp, int psize)
249{ 249{
250 int i, shift; 250 int i, shift;
251 unsigned int mask; 251 unsigned int mask;
252 /* Look at the 8 bit LP value */
253 unsigned int lp = (hptep->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
254
255 if (!(hptep->v & HPTE_V_VALID))
256 return -1;
257
258 /* First check if it is large page */
259 if (!(hptep->v & HPTE_V_LARGE))
260 return MMU_PAGE_4K;
261 252
262 /* start from 1 ignoring MMU_PAGE_4K */ 253 /* start from 1 ignoring MMU_PAGE_4K */
263 for (i = 1; i < MMU_PAGE_COUNT; i++) { 254 for (i = 1; i < MMU_PAGE_COUNT; i++) {
@@ -284,6 +275,21 @@ static inline int hpte_actual_psize(struct hash_pte *hptep, int psize)
284 return -1; 275 return -1;
285} 276}
286 277
278static inline int hpte_actual_psize(struct hash_pte *hptep, int psize)
279{
280 /* Look at the 8 bit LP value */
281 unsigned int lp = (hptep->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
282
283 if (!(hptep->v & HPTE_V_VALID))
284 return -1;
285
286 /* First check if it is large page */
287 if (!(hptep->v & HPTE_V_LARGE))
288 return MMU_PAGE_4K;
289
290 return __hpte_actual_psize(lp, psize);
291}
292
287static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, 293static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
288 unsigned long vpn, int psize, int ssize, 294 unsigned long vpn, int psize, int ssize,
289 int local) 295 int local)
@@ -425,42 +431,27 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
425 int *psize, int *apsize, int *ssize, unsigned long *vpn) 431 int *psize, int *apsize, int *ssize, unsigned long *vpn)
426{ 432{
427 unsigned long avpn, pteg, vpi; 433 unsigned long avpn, pteg, vpi;
428 unsigned long hpte_r = hpte->r;
429 unsigned long hpte_v = hpte->v; 434 unsigned long hpte_v = hpte->v;
430 unsigned long vsid, seg_off; 435 unsigned long vsid, seg_off;
431 int i, size, a_size, shift, penc; 436 int size, a_size, shift;
437 /* Look at the 8 bit LP value */
438 unsigned int lp = (hpte->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
432 439
433 if (!(hpte_v & HPTE_V_LARGE)) { 440 if (!(hpte_v & HPTE_V_LARGE)) {
434 size = MMU_PAGE_4K; 441 size = MMU_PAGE_4K;
435 a_size = MMU_PAGE_4K; 442 a_size = MMU_PAGE_4K;
436 } else { 443 } else {
437 for (i = 0; i < LP_BITS; i++) {
438 if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1))
439 break;
440 }
441 penc = LP_MASK(i+1) >> LP_SHIFT;
442 for (size = 0; size < MMU_PAGE_COUNT; size++) { 444 for (size = 0; size < MMU_PAGE_COUNT; size++) {
443 445
444 /* valid entries have a shift value */ 446 /* valid entries have a shift value */
445 if (!mmu_psize_defs[size].shift) 447 if (!mmu_psize_defs[size].shift)
446 continue; 448 continue;
447 for (a_size = 0; a_size < MMU_PAGE_COUNT; a_size++) {
448
449 /* 4K pages are not represented by LP */
450 if (a_size == MMU_PAGE_4K)
451 continue;
452 449
453 /* valid entries have a shift value */ 450 a_size = __hpte_actual_psize(lp, size);
454 if (!mmu_psize_defs[a_size].shift) 451 if (a_size != -1)
455 continue; 452 break;
456
457 if (penc == mmu_psize_defs[size].penc[a_size])
458 goto out;
459 }
460 } 453 }
461 } 454 }
462
463out:
464 /* This works for all page sizes, and for 256M and 1T segments */ 455 /* This works for all page sizes, and for 256M and 1T segments */
465 *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT; 456 *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT;
466 shift = mmu_psize_defs[size].shift; 457 shift = mmu_psize_defs[size].shift;