Commit 7e74c392 authored by Aneesh Kumar K.V's avatar Aneesh Kumar K.V Committed by Benjamin Herrenschmidt

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: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Acked-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent b1022fbd
...@@ -245,19 +245,10 @@ static long native_hpte_remove(unsigned long hpte_group) ...@@ -245,19 +245,10 @@ static long native_hpte_remove(unsigned long hpte_group)
return i; return i;
} }
static inline int hpte_actual_psize(struct hash_pte *hptep, int psize) static inline int __hpte_actual_psize(unsigned int lp, int psize)
{ {
int i, shift; int i, shift;
unsigned int mask; unsigned int mask;
/* Look at the 8 bit LP value */
unsigned int lp = (hptep->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
if (!(hptep->v & HPTE_V_VALID))
return -1;
/* First check if it is large page */
if (!(hptep->v & HPTE_V_LARGE))
return MMU_PAGE_4K;
/* start from 1 ignoring MMU_PAGE_4K */ /* start from 1 ignoring MMU_PAGE_4K */
for (i = 1; i < MMU_PAGE_COUNT; i++) { 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,6 +275,21 @@ static inline int hpte_actual_psize(struct hash_pte *hptep, int psize)
return -1; return -1;
} }
static inline int hpte_actual_psize(struct hash_pte *hptep, int psize)
{
/* Look at the 8 bit LP value */
unsigned int lp = (hptep->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
if (!(hptep->v & HPTE_V_VALID))
return -1;
/* First check if it is large page */
if (!(hptep->v & HPTE_V_LARGE))
return MMU_PAGE_4K;
return __hpte_actual_psize(lp, psize);
}
static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
unsigned long vpn, int psize, int ssize, unsigned long vpn, int psize, int ssize,
int local) int local)
...@@ -425,42 +431,27 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, ...@@ -425,42 +431,27 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
int *psize, int *apsize, int *ssize, unsigned long *vpn) int *psize, int *apsize, int *ssize, unsigned long *vpn)
{ {
unsigned long avpn, pteg, vpi; unsigned long avpn, pteg, vpi;
unsigned long hpte_r = hpte->r;
unsigned long hpte_v = hpte->v; unsigned long hpte_v = hpte->v;
unsigned long vsid, seg_off; unsigned long vsid, seg_off;
int i, size, a_size, shift, penc; int size, a_size, shift;
/* Look at the 8 bit LP value */
unsigned int lp = (hpte->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
if (!(hpte_v & HPTE_V_LARGE)) { if (!(hpte_v & HPTE_V_LARGE)) {
size = MMU_PAGE_4K; size = MMU_PAGE_4K;
a_size = MMU_PAGE_4K; a_size = MMU_PAGE_4K;
} else { } else {
for (i = 0; i < LP_BITS; i++) {
if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1))
break;
}
penc = LP_MASK(i+1) >> LP_SHIFT;
for (size = 0; size < MMU_PAGE_COUNT; size++) { for (size = 0; size < MMU_PAGE_COUNT; size++) {
/* valid entries have a shift value */ /* valid entries have a shift value */
if (!mmu_psize_defs[size].shift) if (!mmu_psize_defs[size].shift)
continue; continue;
for (a_size = 0; a_size < MMU_PAGE_COUNT; a_size++) {
/* 4K pages are not represented by LP */ a_size = __hpte_actual_psize(lp, size);
if (a_size == MMU_PAGE_4K) if (a_size != -1)
continue; break;
/* valid entries have a shift value */
if (!mmu_psize_defs[a_size].shift)
continue;
if (penc == mmu_psize_defs[size].penc[a_size])
goto out;
}
} }
} }
out:
/* This works for all page sizes, and for 256M and 1T segments */ /* This works for all page sizes, and for 256M and 1T segments */
*ssize = hpte_v >> HPTE_V_SSIZE_SHIFT; *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT;
shift = mmu_psize_defs[size].shift; shift = mmu_psize_defs[size].shift;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment