powerpc: Fix hpte_decode to use the correct decoding for page sizes
[firefly-linux-kernel-4.4.55.git] / arch / powerpc / mm / hash_native_64.c
index 14e3fe896baf1514b865aa4c23aeef18bfd01a09..bb920ee156274c45d3a6599c2f7f4470e2af9178 100644 (file)
@@ -245,19 +245,10 @@ static long native_hpte_remove(unsigned long hpte_group)
        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;
        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 */
        for (i = 1; i < MMU_PAGE_COUNT; i++) {
@@ -284,6 +275,21 @@ static inline int hpte_actual_psize(struct hash_pte *hptep, int psize)
        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,
                                 unsigned long vpn, int psize, int ssize,
                                 int local)
@@ -425,42 +431,27 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
                        int *psize, int *apsize, int *ssize, unsigned long *vpn)
 {
        unsigned long avpn, pteg, vpi;
-       unsigned long hpte_r = hpte->r;
        unsigned long hpte_v = hpte->v;
        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)) {
                size   = MMU_PAGE_4K;
                a_size = MMU_PAGE_4K;
        } 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++) {
 
                        /* valid entries have a shift value */
                        if (!mmu_psize_defs[size].shift)
                                continue;
-                       for (a_size = 0; a_size < MMU_PAGE_COUNT; a_size++) {
-
-                               /* 4K pages are not represented by LP */
-                               if (a_size == MMU_PAGE_4K)
-                                       continue;
 
-                               /* 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;
-                       }
+                       a_size = __hpte_actual_psize(lp, size);
+                       if (a_size != -1)
+                               break;
                }
        }
-
-out:
        /* This works for all page sizes, and for 256M and 1T segments */
        *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT;
        shift = mmu_psize_defs[size].shift;