#ifdef CONFIG_PPC64
        void            (*hpte_invalidate)(unsigned long slot,
                                           unsigned long vpn,
-                                          int psize, int ssize,
-                                          int local);
+                                          int bpsize, int apsize,
+                                          int ssize, int local);
        long            (*hpte_updatepp)(unsigned long slot, 
                                         unsigned long newpp, 
                                         unsigned long vpn,
-                                        int psize, int ssize,
-                                        int local);
+                                        int bpsize, int apsize,
+                                        int ssize, int local);
        void            (*hpte_updateboltedpp)(unsigned long newpp, 
                                               unsigned long ea,
                                               int psize, int ssize);
 
 void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
 {
        ppc_md.hpte_invalidate(pte->slot, pte->host_vpn,
-                              MMU_PAGE_4K, MMU_SEGSIZE_256M,
+                              MMU_PAGE_4K, MMU_PAGE_4K, MMU_SEGSIZE_256M,
                               false);
 }
 
 
 
        /* Call ppc_md.hpte_updatepp */
        mr      r5,r29                  /* vpn */
-       li      r6,MMU_PAGE_4K          /* page size */
-       ld      r7,STK_PARAM(R9)(r1)    /* segment size */
-       ld      r8,STK_PARAM(R8)(r1)    /* get "local" param */
+       li      r6,MMU_PAGE_4K          /* base page size */
+       li      r7,MMU_PAGE_4K          /* actual page size */
+       ld      r8,STK_PARAM(R9)(r1)    /* segment size */
+       ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
 _GLOBAL(htab_call_hpte_updatepp)
        bl      .                       /* Patched by htab_finish_init() */
 
 
        /* Call ppc_md.hpte_updatepp */
        mr      r5,r29                  /* vpn */
-       li      r6,MMU_PAGE_4K          /* page size */
-       ld      r7,STK_PARAM(R9)(r1)    /* segment size */
-       ld      r8,STK_PARAM(R8)(r1)    /* get "local" param */
+       li      r6,MMU_PAGE_4K          /* base page size */
+       li      r7,MMU_PAGE_4K          /* actual page size */
+       ld      r8,STK_PARAM(R9)(r1)    /* segment size */
+       ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
 _GLOBAL(htab_call_hpte_updatepp)
        bl      .                       /* patched by htab_finish_init() */
 
 
        /* Call ppc_md.hpte_updatepp */
        mr      r5,r29                  /* vpn */
-       li      r6,MMU_PAGE_64K
-       ld      r7,STK_PARAM(R9)(r1)    /* segment size */
-       ld      r8,STK_PARAM(R8)(r1)    /* get "local" param */
+       li      r6,MMU_PAGE_64K         /* base page size */
+       li      r7,MMU_PAGE_64K         /* actual page size */
+       ld      r8,STK_PARAM(R9)(r1)    /* segment size */
+       ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
 _GLOBAL(ht64_call_hpte_updatepp)
        bl      .                       /* patched by htab_finish_init() */
 
 
        return i;
 }
 
-static inline int __hpte_actual_psize(unsigned int lp, int psize)
-{
-       int i, shift;
-       unsigned int mask;
-
-       /* start from 1 ignoring MMU_PAGE_4K */
-       for (i = 1; i < MMU_PAGE_COUNT; i++) {
-
-               /* invalid penc */
-               if (mmu_psize_defs[psize].penc[i] == -1)
-                       continue;
-               /*
-                * encoding bits per actual page size
-                *        PTE LP     actual page size
-                *    rrrr rrrz         >=8KB
-                *    rrrr rrzz         >=16KB
-                *    rrrr rzzz         >=32KB
-                *    rrrr zzzz         >=64KB
-                * .......
-                */
-               shift = mmu_psize_defs[i].shift - LP_SHIFT;
-               if (shift > LP_BITS)
-                       shift = LP_BITS;
-               mask = (1 << shift) - 1;
-               if ((lp & mask) == mmu_psize_defs[psize].penc[i])
-                       return i;
-       }
-       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)
+                                unsigned long vpn, int bpsize,
+                                int apsize, int ssize, int local)
 {
        struct hash_pte *hptep = htab_address + slot;
        unsigned long hpte_v, want_v;
        int ret = 0;
-       int actual_psize;
 
-       want_v = hpte_encode_avpn(vpn, psize, ssize);
+       want_v = hpte_encode_avpn(vpn, bpsize, ssize);
 
        DBG_LOW("    update(vpn=%016lx, avpnv=%016lx, group=%lx, newpp=%lx)",
                vpn, want_v & HPTE_V_AVPN, slot, newpp);
        native_lock_hpte(hptep);
 
        hpte_v = hptep->v;
-       actual_psize = hpte_actual_psize(hptep, psize);
        /*
         * We need to invalidate the TLB always because hpte_remove doesn't do
         * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less
         * (hpte_remove) because we assume the old translation is still
         * technically "valid".
         */
-       if (actual_psize < 0) {
-               actual_psize = psize;
-               ret = -1;
-               goto err_out;
-       }
-       if (!HPTE_V_COMPARE(hpte_v, want_v)) {
+       if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
                DBG_LOW(" -> miss\n");
                ret = -1;
        } else {
                hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
                        (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C));
        }
-err_out:
        native_unlock_hpte(hptep);
 
        /* Ensure it is out of the tlb too. */
-       tlbie(vpn, psize, actual_psize, ssize, local);
+       tlbie(vpn, bpsize, apsize, ssize, local);
 
        return ret;
 }
 static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
                                       int psize, int ssize)
 {
-       int actual_psize;
        unsigned long vpn;
        unsigned long vsid;
        long slot;
        if (slot == -1)
                panic("could not find page to bolt\n");
        hptep = htab_address + slot;
-       actual_psize = hpte_actual_psize(hptep, psize);
-       if (actual_psize < 0)
-               actual_psize = psize;
 
        /* Update the HPTE */
        hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
                (newpp & (HPTE_R_PP | HPTE_R_N));
-
-       /* Ensure it is out of the tlb too. */
-       tlbie(vpn, psize, actual_psize, ssize, 0);
+       /*
+        * Ensure it is out of the tlb too. Bolted entries base and
+        * actual page size will be same.
+        */
+       tlbie(vpn, psize, psize, ssize, 0);
 }
 
 static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
-                                  int psize, int ssize, int local)
+                                  int bpsize, int apsize, int ssize, int local)
 {
        struct hash_pte *hptep = htab_address + slot;
        unsigned long hpte_v;
        unsigned long want_v;
        unsigned long flags;
-       int actual_psize;
 
        local_irq_save(flags);
 
        DBG_LOW("    invalidate(vpn=%016lx, hash: %lx)\n", vpn, slot);
 
-       want_v = hpte_encode_avpn(vpn, psize, ssize);
+       want_v = hpte_encode_avpn(vpn, bpsize, ssize);
        native_lock_hpte(hptep);
        hpte_v = hptep->v;
 
-       actual_psize = hpte_actual_psize(hptep, psize);
        /*
         * We need to invalidate the TLB always because hpte_remove doesn't do
         * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less
         * (hpte_remove) because we assume the old translation is still
         * technically "valid".
         */
-       if (actual_psize < 0) {
-               actual_psize = psize;
-               native_unlock_hpte(hptep);
-               goto err_out;
-       }
-       if (!HPTE_V_COMPARE(hpte_v, want_v))
+       if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
                native_unlock_hpte(hptep);
        else
                /* Invalidate the hpte. NOTE: this also unlocks it */
                hptep->v = 0;
 
-err_out:
        /* Invalidate the TLB */
-       tlbie(vpn, psize, actual_psize, ssize, local);
+       tlbie(vpn, bpsize, apsize, ssize, local);
+
        local_irq_restore(flags);
 }
 
+static inline int __hpte_actual_psize(unsigned int lp, int psize)
+{
+       int i, shift;
+       unsigned int mask;
+
+       /* start from 1 ignoring MMU_PAGE_4K */
+       for (i = 1; i < MMU_PAGE_COUNT; i++) {
+
+               /* invalid penc */
+               if (mmu_psize_defs[psize].penc[i] == -1)
+                       continue;
+               /*
+                * encoding bits per actual page size
+                *        PTE LP     actual page size
+                *    rrrr rrrz         >=8KB
+                *    rrrr rrzz         >=16KB
+                *    rrrr rzzz         >=32KB
+                *    rrrr zzzz         >=64KB
+                * .......
+                */
+               shift = mmu_psize_defs[i].shift - LP_SHIFT;
+               if (shift > LP_BITS)
+                       shift = LP_BITS;
+               mask = (1 << shift) - 1;
+               if ((lp & mask) == mmu_psize_defs[psize].penc[i])
+                       return i;
+       }
+       return -1;
+}
+
 static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
                        int *psize, int *apsize, int *ssize, unsigned long *vpn)
 {
 
                slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
                slot += hidx & _PTEIDX_GROUP_IX;
                DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx);
-               ppc_md.hpte_invalidate(slot, vpn, psize, ssize, local);
+               /*
+                * We use same base page size and actual psize, because we don't
+                * use these functions for hugepage
+                */
+               ppc_md.hpte_invalidate(slot, vpn, psize, psize, ssize, local);
        } pte_iterate_hashed_end();
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
                hash = ~hash;
        slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
        slot += hidx & _PTEIDX_GROUP_IX;
-       ppc_md.hpte_invalidate(slot, vpn, mmu_linear_psize, mmu_kernel_ssize, 0);
+       ppc_md.hpte_invalidate(slot, vpn, mmu_linear_psize, mmu_linear_psize,
+                              mmu_kernel_ssize, 0);
 }
 
 void kernel_map_pages(struct page *page, int numpages, int enable)
 
                slot += (old_pte & _PAGE_F_GIX) >> 12;
 
                if (ppc_md.hpte_updatepp(slot, rflags, vpn, mmu_psize,
-                                        ssize, local) == -1)
+                                        mmu_psize, ssize, local) == -1)
                        old_pte &= ~_PAGE_HPTEFLAGS;
        }
 
 
 static long beat_lpar_hpte_updatepp(unsigned long slot,
                                    unsigned long newpp,
                                    unsigned long vpn,
-                                   int psize, int ssize, int local)
+                                   int psize, int apsize,
+                                   int ssize, int local)
 {
        unsigned long lpar_rc;
        u64 dummy0, dummy1;
 }
 
 static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
-                                        int psize, int ssize, int local)
+                                     int psize, int apsize,
+                                     int ssize, int local)
 {
        unsigned long want_v;
        unsigned long lpar_rc;
  * already zero.  For now I am paranoid.
  */
 static long beat_lpar_hpte_updatepp_v3(unsigned long slot,
-                                   unsigned long newpp,
-                                   unsigned long vpn,
-                                   int psize, int ssize, int local)
+                                      unsigned long newpp,
+                                      unsigned long vpn,
+                                      int psize, int apsize,
+                                      int ssize, int local)
 {
        unsigned long lpar_rc;
        unsigned long want_v;
 }
 
 static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long vpn,
-                                        int psize, int ssize, int local)
+                                        int psize, int apsize,
+                                        int ssize, int local)
 {
        unsigned long want_v;
        unsigned long lpar_rc;
 
 }
 
 static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
-       unsigned long vpn, int psize, int ssize, int local)
+                             unsigned long vpn, int psize, int apsize,
+                             int ssize, int local)
 {
        int result;
        u64 hpte_v, want_v, hpte_rs;
 }
 
 static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn,
-       int psize, int ssize, int local)
+                               int psize, int apsize, int ssize, int local)
 {
        unsigned long flags;
        int result;
 
 static long pSeries_lpar_hpte_updatepp(unsigned long slot,
                                       unsigned long newpp,
                                       unsigned long vpn,
-                                      int psize, int ssize, int local)
+                                      int psize, int apsize,
+                                      int ssize, int local)
 {
        unsigned long lpar_rc;
        unsigned long flags = (newpp & 7) | H_AVPN;
 }
 
 static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
-                                        int psize, int ssize, int local)
+                                        int psize, int apsize,
+                                        int ssize, int local)
 {
        unsigned long want_v;
        unsigned long lpar_rc;
 
        slot = pSeries_lpar_hpte_find(vpn, psize, ssize);
        BUG_ON(slot == -1);
-
-       pSeries_lpar_hpte_invalidate(slot, vpn, psize, ssize, 0);
+       /*
+        * lpar doesn't use the passed actual page size
+        */
+       pSeries_lpar_hpte_invalidate(slot, vpn, psize, 0, ssize, 0);
 }
 
 /* Flag bits for H_BULK_REMOVE */
                        slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
                        slot += hidx & _PTEIDX_GROUP_IX;
                        if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) {
+                               /*
+                                * lpar doesn't use the passed actual page size
+                                */
                                pSeries_lpar_hpte_invalidate(slot, vpn, psize,
-                                                            ssize, local);
+                                                            0, ssize, local);
                        } else {
                                param[pix] = HBR_REQUEST | HBR_AVPN | slot;
                                param[pix+1] = hpte_encode_avpn(vpn, psize,