Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 13 Aug 2016 16:16:02 +0000 (UTC)
From:      Justin Hibbits <jhibbits@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r304047 - in head/sys/powerpc: booke mpc85xx
Message-ID:  <201608131616.u7DGG2K9048353@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhibbits
Date: Sat Aug 13 16:16:02 2016
New Revision: 304047
URL: https://svnweb.freebsd.org/changeset/base/304047

Log:
  Add ePAPR boot support for PowerPC book-E (MPC85xx) hardware
  
  Summary:
  u-boot, following the ePAPR specification, puts secondary cores into a
  spinloop at boot, rather than leaving them shut off.  It then relies on the host
  OS to write the correct values to a special spin table, located in coherent
  memory (on newer implementations), or noncoherent memory (older
  implementations).
  
  This supports both implementations of ePAPR, as well as continuing to support
  non-ePAPR booting, by first attempting to use the spintable, and falling back to
  expecting non-started CPUs.
  
  Test Plan:
  Booted on a P5020 board.  Tested before and after the changes.
  Before the changes, prints the error "SMP: CPU 1 already out of hold-off state!"
  and panics shortly thereafter.  After the changes, same boot method lets it
  complete boot.
  
  Reviewed by:	nwhitehorn
  MFC after:	2 weeks
  Relnotes:	Yes
  Sponsored by:	Alex Perez/Inertial Computing
  Differential Revision: https://reviews.freebsd.org/D7494

Modified:
  head/sys/powerpc/booke/locore.S
  head/sys/powerpc/mpc85xx/platform_mpc85xx.c

Modified: head/sys/powerpc/booke/locore.S
==============================================================================
--- head/sys/powerpc/booke/locore.S	Sat Aug 13 16:09:49 2016	(r304046)
+++ head/sys/powerpc/booke/locore.S	Sat Aug 13 16:16:02 2016	(r304047)
@@ -412,6 +412,8 @@ bp_kernload:
 	ori	%r3, %r3, (MAS3_SX | MAS3_SW | MAS3_SR)@l
 	mtspr	SPR_MAS3, %r3
 	isync
+	bl	zero_mas7
+	bl	zero_mas8
 	tlbwe
 	isync
 	msync

Modified: head/sys/powerpc/mpc85xx/platform_mpc85xx.c
==============================================================================
--- head/sys/powerpc/mpc85xx/platform_mpc85xx.c	Sat Aug 13 16:09:49 2016	(r304046)
+++ head/sys/powerpc/mpc85xx/platform_mpc85xx.c	Sat Aug 13 16:16:02 2016	(r304047)
@@ -39,7 +39,9 @@ __FBSDID("$FreeBSD$");
 #include <machine/bus.h>
 #include <machine/cpu.h>
 #include <machine/hid.h>
+#include <machine/_inttypes.h>
 #include <machine/machdep.h>
+#include <machine/md_var.h>
 #include <machine/platform.h>
 #include <machine/platformvar.h>
 #include <machine/smp.h>
@@ -53,6 +55,7 @@ __FBSDID("$FreeBSD$");
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
+#include <vm/vm_extern.h>
 
 #include <powerpc/mpc85xx/mpc85xx.h>
 
@@ -63,6 +66,15 @@ extern void *ap_pcpu;
 extern vm_paddr_t kernload;		/* Kernel physical load address */
 extern uint8_t __boot_page[];		/* Boot page body */
 extern uint32_t bp_kernload;
+
+struct cpu_release {
+	uint32_t entry_h;
+	uint32_t entry_l;
+	uint32_t r3_h;
+	uint32_t r3_l;
+	uint32_t reserved;
+	uint32_t pir;
+};
 #endif
 
 extern uint32_t *bootinfo;
@@ -316,6 +328,51 @@ mpc85xx_smp_get_bsp(platform_t plat, str
 	return (0);
 }
 
+#ifdef SMP
+static int
+mpc85xx_smp_start_cpu_epapr(platform_t plat, struct pcpu *pc)
+{
+	vm_paddr_t rel_pa, bptr;
+	volatile struct cpu_release *rel;
+	vm_offset_t rel_va, rel_page;
+	phandle_t node;
+	int i;
+
+	/* If we're calling this, the node already exists. */
+	node = OF_finddevice("/cpus");
+	for (i = 0, node = OF_child(node); i < pc->pc_cpuid;
+	    i++, node = OF_peer(node))
+		;
+	if (OF_getencprop(node, "cpu-release-addr", (pcell_t *)&rel_pa,
+	    sizeof(rel_pa)) == -1) {
+		return (ENOENT);
+	}
+
+	rel_page = kva_alloc(PAGE_SIZE);
+	if (rel_page == 0)
+		return (ENOMEM);
+
+	critical_enter();
+	rel_va = rel_page + (rel_pa & PAGE_MASK);
+	pmap_kenter(rel_page, rel_pa & ~PAGE_MASK);
+	rel = (struct cpu_release *)rel_va;
+	bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload;
+	cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
+	rel->pir = pc->pc_cpuid; __asm __volatile("sync");
+	rel->entry_h = (bptr >> 32);
+	rel->entry_l = bptr; __asm __volatile("sync");
+	cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
+	if (bootverbose)
+		printf("Waking up CPU %d via CPU release page %p\n",
+		    pc->pc_cpuid, rel);
+	critical_exit();
+	pmap_kremove(rel_page);
+	kva_free(rel_page, PAGE_SIZE);
+
+	return (0);
+}
+#endif
+
 static int
 mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
 {
@@ -325,6 +382,7 @@ mpc85xx_smp_start_cpu(platform_t plat, s
 	int timeout;
 	uintptr_t brr;
 	int cpuid;
+	int epapr_boot = 0;
 	uint32_t tgt;
 
 	if (mpc85xx_is_qoriq()) {
@@ -342,6 +400,20 @@ mpc85xx_smp_start_cpu(platform_t plat, s
 		cpuid = pc->pc_cpuid + 24;
 	}
 	bp_kernload = kernload;
+	/*
+	 * bp_kernload is in the boot page.  Sync the cache because ePAPR
+	 * booting has the other core(s) already running.
+	 */
+	__syncicache(&bp_kernload, sizeof(bp_kernload));
+
+	ap_pcpu = pc;
+	__asm __volatile("msync; isync");
+
+	/* First try the ePAPR way. */
+	if (mpc85xx_smp_start_cpu_epapr(plat, pc) == 0) {
+		epapr_boot = 1;
+		goto spin_wait;
+	}
 
 	reg = ccsr_read4(brr);
 	if ((reg & (1 << cpuid)) != 0) {
@@ -350,9 +422,6 @@ mpc85xx_smp_start_cpu(platform_t plat, s
 		return (ENXIO);
 	}
 
-	ap_pcpu = pc;
-	__asm __volatile("msync; isync");
-
 	/* Flush caches to have our changes hit DRAM. */
 	cpu_flush_dcache(__boot_page, 4096);
 
@@ -413,6 +482,7 @@ mpc85xx_smp_start_cpu(platform_t plat, s
 	ccsr_write4(brr, reg | (1 << cpuid));
 	__asm __volatile("isync; msync");
 
+spin_wait:
 	timeout = 500;
 	while (!pc->pc_awake && timeout--)
 		DELAY(1000);	/* wait 1ms */
@@ -422,11 +492,13 @@ mpc85xx_smp_start_cpu(platform_t plat, s
 	 * address (= 0xfffff000) isn't permanently remapped and thus not
 	 * usable otherwise.
 	 */
-	if (mpc85xx_is_qoriq())
-		ccsr_write4(OCP85XX_BSTAR, 0);
-	else
-		ccsr_write4(OCP85XX_BPTR, 0);
-	__asm __volatile("isync; msync");
+	if (!epapr_boot) {
+		if (mpc85xx_is_qoriq())
+			ccsr_write4(OCP85XX_BSTAR, 0);
+		else
+			ccsr_write4(OCP85XX_BPTR, 0);
+		__asm __volatile("isync; msync");
+	}
 
 	if (!pc->pc_awake)
 		panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608131616.u7DGG2K9048353>