ppc64 iSeries: Update create_pte_mapping to replace iSeries_bolt_kernel()

early_setup() calls htab_initialize() which is similar, but not identical
to iSeries_bolt_kernel().

On iSeries the Hypervisor has already inserted some ptes for us, and we
simply have to detect that and bolt them. iSeries_hpte_bolt_or_insert()
implements that logic.

For the case of a non-existing pte we just call iSeries_hpte_insert(). This
appears to work, although it's not entirely equivalent to the old code in
iSeries_make_pte() which panicked if we got a secondary slot. Not sure if
that's important.

Finally we call iSeries_hpte_bolt_or_insert() from create_pte_mapping(),
which is called from htab_initialize() for each lmb region.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c
index 2192055..9a2be3a 100644
--- a/arch/ppc64/kernel/iSeries_htab.c
+++ b/arch/ppc64/kernel/iSeries_htab.c
@@ -84,6 +84,25 @@
 	return (secondary << 3) | (slot & 7);
 }
 
+long iSeries_hpte_bolt_or_insert(unsigned long hpte_group,
+		unsigned long va, unsigned long prpn, unsigned long vflags,
+		unsigned long rflags)
+{
+	long slot;
+	hpte_t lhpte;
+
+	slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT);
+
+	if (lhpte.v & HPTE_V_VALID) {
+		/* Bolt the existing HPTE */
+		HvCallHpt_setSwBits(slot, 0x10, 0);
+		HvCallHpt_setPp(slot, PP_RWXX);
+		return 0;
+	}
+
+	return iSeries_hpte_insert(hpte_group, va, prpn, vflags, rflags);
+}
+
 static unsigned long iSeries_hpte_getword0(unsigned long slot)
 {
 	hpte_t hpte;
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
index 75d8db4..49d0f99 100644
--- a/arch/ppc64/kernel/iSeries_setup.c
+++ b/arch/ppc64/kernel/iSeries_setup.c
@@ -75,7 +75,6 @@
 
 static void build_iSeries_Memory_Map(void);
 static void setup_iSeries_cache_sizes(void);
-static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
 static int iseries_shared_idle(void);
 static int iseries_dedicated_idle(void);
 #ifdef CONFIG_PCI
@@ -383,9 +382,6 @@
 		}
 	}
 
-	/* Bolt kernel mappings for all of memory (or just a bit if we've got a limit) */
-	iSeries_bolt_kernel(0, systemcfg->physicalMemorySize);
-
 	lmb_init();
 	lmb_add(0, systemcfg->physicalMemorySize);
 	lmb_analyze();
@@ -637,62 +633,6 @@
 }
 
 /*
- * Create a pte. Used during initialization only.
- */
-static void iSeries_make_pte(unsigned long va, unsigned long pa,
-			     int mode)
-{
-	hpte_t local_hpte, rhpte;
-	unsigned long hash, vpn;
-	long slot;
-
-	vpn = va >> PAGE_SHIFT;
-	hash = hpt_hash(vpn, 0);
-
-	local_hpte.r = pa | mode;
-	local_hpte.v = ((va >> 23) << HPTE_V_AVPN_SHIFT)
-		| HPTE_V_BOLTED | HPTE_V_VALID;
-
-	slot = HvCallHpt_findValid(&rhpte, vpn);
-	if (slot < 0) {
-		/* Must find space in primary group */
-		panic("hash_page: hpte already exists\n");
-	}
-	HvCallHpt_addValidate(slot, 0, &local_hpte);
-}
-
-/*
- * Bolt the kernel addr space into the HPT
- */
-static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
-{
-	unsigned long pa;
-	unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
-	hpte_t hpte;
-
-	for (pa = saddr; pa < eaddr ;pa += PAGE_SIZE) {
-		unsigned long ea = (unsigned long)__va(pa);
-		unsigned long vsid = get_kernel_vsid(ea);
-		unsigned long va = (vsid << 28) | (pa & 0xfffffff);
-		unsigned long vpn = va >> PAGE_SHIFT;
-		unsigned long slot = HvCallHpt_findValid(&hpte, vpn);
-
-		/* Make non-kernel text non-executable */
-		if (!in_kernel_text(ea))
-			mode_rw |= HW_NO_EXEC;
-
-		if (hpte.v & HPTE_V_VALID) {
-			/* HPTE exists, so just bolt it */
-			HvCallHpt_setSwBits(slot, 0x10, 0);
-			/* And make sure the pp bits are correct */
-			HvCallHpt_setPp(slot, PP_RWXX);
-		} else
-			/* No HPTE exists, so create a new bolted one */
-			iSeries_make_pte(va, phys_to_abs(pa), mode_rw);
-	}
-}
-
-/*
  * Document me.
  */
 static void __init iSeries_setup_arch(void)
diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c
index 36cf474..8350743 100644
--- a/arch/ppc64/mm/hash_utils.c
+++ b/arch/ppc64/mm/hash_utils.c
@@ -90,7 +90,6 @@
 		;
 }
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
 static inline void create_pte_mapping(unsigned long start, unsigned long end,
 				      unsigned long mode, int large)
 {
@@ -111,7 +110,7 @@
 		unsigned long vpn, hash, hpteg;
 		unsigned long vsid = get_kernel_vsid(addr);
 		unsigned long va = (vsid << 28) | (addr & 0xfffffff);
-		int ret;
+		int ret = -1;
 
 		if (large)
 			vpn = va >> HPAGE_SHIFT;
@@ -129,16 +128,25 @@
 
 		hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
 
+#ifdef CONFIG_PPC_ISERIES
+		if (systemcfg->platform & PLATFORM_ISERIES_LPAR)
+			ret = iSeries_hpte_bolt_or_insert(hpteg, va,
+				virt_to_abs(addr) >> PAGE_SHIFT,
+				vflags, tmp_mode);
+		else
+#endif
 #ifdef CONFIG_PPC_PSERIES
 		if (systemcfg->platform & PLATFORM_LPAR)
 			ret = pSeries_lpar_hpte_insert(hpteg, va,
 				virt_to_abs(addr) >> PAGE_SHIFT,
 				vflags, tmp_mode);
 		else
-#endif /* CONFIG_PPC_PSERIES */
+#endif
+#ifdef CONFIG_PPC_MULTIPLATFORM
 			ret = native_hpte_insert(hpteg, va,
 				virt_to_abs(addr) >> PAGE_SHIFT,
 				vflags, tmp_mode);
+#endif
 
 		if (ret == -1) {
 			ppc64_terminate_msg(0x20, "create_pte_mapping");
@@ -261,7 +269,6 @@
 }
 #undef KB
 #undef MB
-#endif /* CONFIG_PPC_MULTIPLATFORM */
 
 /*
  * Called by asm hashtable.S for doing lazy icache flush
diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
index d2b0b79..e0505ac 100644
--- a/include/asm-ppc64/mmu.h
+++ b/include/asm-ppc64/mmu.h
@@ -206,6 +206,10 @@
 			       unsigned long prpn,
 			       unsigned long vflags, unsigned long rflags);
 
+extern long iSeries_hpte_bolt_or_insert(unsigned long hpte_group,
+		unsigned long va, unsigned long prpn,
+		unsigned long vflags, unsigned long rflags);
+
 extern void stabs_alloc(void);
 
 #endif /* __ASSEMBLY__ */