svn commit: r304047 - in head/sys/powerpc: booke mpc85xx
Justin Hibbits
jhibbits at FreeBSD.org
Sat Aug 13 16:16:03 UTC 2016
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);
More information about the svn-src-head
mailing list