#define HPTE_V_SECONDARY       ASM_CONST(0x0000000000000002)
 #define HPTE_V_VALID           ASM_CONST(0x0000000000000001)
 
+/*
+ * ISA 3.0 have a different HPTE format.
+ */
+#define HPTE_R_3_0_SSIZE_SHIFT 58
 #define HPTE_R_PP0             ASM_CONST(0x8000000000000000)
 #define HPTE_R_TS              ASM_CONST(0x4000000000000000)
 #define HPTE_R_KEY_HI          ASM_CONST(0x3000000000000000)
         */
        v = (vpn >> (23 - VPN_SHIFT)) & ~(mmu_psize_defs[psize].avpnm);
        v <<= HPTE_V_AVPN_SHIFT;
-       v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT;
+       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+               v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT;
        return v;
 }
 
  * aligned for the requested page size
  */
 static inline unsigned long hpte_encode_r(unsigned long pa, int base_psize,
-                                         int actual_psize)
+                                         int actual_psize, int ssize)
 {
+
+       if (cpu_has_feature(CPU_FTR_ARCH_300))
+               pa |= ((unsigned long) ssize) << HPTE_R_3_0_SSIZE_SHIFT;
+
        /* A 4K page needs no special encoding */
        if (actual_psize == MMU_PAGE_4K)
                return pa & HPTE_R_RPN;
 
        if (!cpu_has_feature(CPU_FTR_HVMODE) ||
            !cpu_has_feature(CPU_FTR_ARCH_206))
                return -EIO;
+       /*
+        * Disable KVM for Power9, untill the required bits merged.
+        */
+       if (cpu_has_feature(CPU_FTR_ARCH_300))
+               return -EIO;
+
        return 0;
 }
 
 
 
 static int kvmppc_core_check_processor_compat_pr(void)
 {
-       /* we are always compatible */
+       /*
+        * Disable KVM for Power9 untill the required bits merged.
+        */
+       if (cpu_has_feature(CPU_FTR_ARCH_300))
+               return -EIO;
        return 0;
 }
 
 
                return -1;
 
        hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
-       hpte_r = hpte_encode_r(pa, psize, apsize) | rflags;
+       hpte_r = hpte_encode_r(pa, psize, apsize, ssize) | rflags;
 
        if (!(vflags & HPTE_V_BOLTED)) {
                DBG_LOW(" i=%x hpte_v=%016lx, hpte_r=%016lx\n",
        local_irq_restore(flags);
 }
 
+static int native_update_partition_table(u64 patb1)
+{
+       partition_tb->patb1 = cpu_to_be64(patb1);
+       return 0;
+}
+
 void __init hpte_init_native(void)
 {
        ppc_md.hpte_invalidate  = native_hpte_invalidate;
        ppc_md.hpte_clear_all   = native_hpte_clear;
        ppc_md.flush_hash_range = native_flush_hash_range;
        ppc_md.hugepage_invalidate   = native_hugepage_invalidate;
+
+       if (cpu_has_feature(CPU_FTR_ARCH_300))
+               ppc_md.update_partition_table = native_update_partition_table;
 }
 
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
+static void __init hash_init_partition_table(phys_addr_t hash_table,
+                                            unsigned long pteg_count)
+{
+       unsigned long ps_field;
+       unsigned long htab_size;
+       unsigned long patb_size = 1UL << PATB_SIZE_SHIFT;
+
+       /*
+        * slb llp encoding for the page size used in VPM real mode.
+        * We can ignore that for lpid 0
+        */
+       ps_field = 0;
+       htab_size =  __ilog2(pteg_count) - 11;
+
+       BUILD_BUG_ON_MSG((PATB_SIZE_SHIFT > 24), "Partition table size too large.");
+       partition_tb = __va(memblock_alloc_base(patb_size, patb_size,
+                                               MEMBLOCK_ALLOC_ANYWHERE));
+
+       /* Initialize the Partition Table with no entries */
+       memset((void *)partition_tb, 0, patb_size);
+       partition_tb->patb0 = cpu_to_be64(ps_field | hash_table | htab_size);
+       /*
+        * FIXME!! This should be done via update_partition table
+        * For now UPRT is 0 for us.
+        */
+       partition_tb->patb1 = 0;
+       DBG("Partition table %p\n", partition_tb);
+       /*
+        * update partition table control register,
+        * 64 K size.
+        */
+       mtspr(SPRN_PTCR, __pa(partition_tb) | (PATB_SIZE_SHIFT - 12));
+
+}
+
 static void __init htab_initialize(void)
 {
        unsigned long table;
                /* Initialize the HPT with no entries */
                memset((void *)table, 0, htab_size_bytes);
 
-               /* Set SDR1 */
-               mtspr(SPRN_SDR1, _SDR1);
+               if (!cpu_has_feature(CPU_FTR_ARCH_300))
+                       /* Set SDR1 */
+                       mtspr(SPRN_SDR1, _SDR1);
+               else
+                       hash_init_partition_table(table, pteg_count);
        }
 
        prot = pgprot_val(PAGE_KERNEL);
 
 #endif
 #endif
 
+#ifdef CONFIG_PPC_BOOK3S_64
+/*
+ * partition table and process table for ISA 3.0
+ */
+struct prtb_entry *process_tb;
+struct patb_entry *partition_tb;
+#endif
 unsigned long ioremap_bot = IOREMAP_BASE;
 
 #ifdef CONFIG_PPC_MMU_NOHASH
 
        vflags &= ~HPTE_V_SECONDARY;
 
        hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
-       hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize) | rflags;
+       hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize, ssize) | rflags;
 
        spin_lock_irqsave(&ps3_htab_lock, flags);
 
 
                         hpte_group, vpn,  pa, rflags, vflags, psize);
 
        hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
-       hpte_r = hpte_encode_r(pa, psize, apsize) | rflags;
+       hpte_r = hpte_encode_r(pa, psize, apsize, ssize) | rflags;
 
        if (!(vflags & HPTE_V_BOLTED))
                pr_devel(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);