Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c55130b authored by Michael Ellerman's avatar Michael Ellerman Committed by Stephen Rothwell
Browse files

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: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarStephen Rothwell <sfr@canb.auug.org.au>
parent ba293fff
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -84,6 +84,25 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
	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;
+0 −60
Original line number Diff line number Diff line
@@ -75,7 +75,6 @@ extern void ppcdbg_initialize(void);

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 @@ static void __init iSeries_init_early(void)
		}
	}

	/* 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();
@@ -636,62 +632,6 @@ static void __init setup_iSeries_cache_sizes(void)
			(unsigned int)ppc64_caches.iline_size);
}

/*
 * 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.
 */
+11 −4
Original line number Diff line number Diff line
@@ -90,7 +90,6 @@ static inline void loop_forever(void)
		;
}

#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 @@ static inline void create_pte_mapping(unsigned long start, unsigned long end,
		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 @@ static inline void create_pte_mapping(unsigned long start, unsigned long end,

		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 @@ void __init htab_initialize(void)
}
#undef KB
#undef MB
#endif /* CONFIG_PPC_MULTIPLATFORM */

/*
 * Called by asm hashtable.S for doing lazy icache flush
+4 −0
Original line number Diff line number Diff line
@@ -206,6 +206,10 @@ extern long native_hpte_insert(unsigned long hpte_group, unsigned long va,
			       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__ */