summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
authorjhibbits <jhibbits@FreeBSD.org>2016-12-23 03:08:27 +0000
committerjhibbits <jhibbits@FreeBSD.org>2016-12-23 03:08:27 +0000
commita3627bf7d397d64c8538b3ce0356b968d05d649a (patch)
tree3ea14ca378f8e17f0267db750393bc023fcd7e9c /sys/powerpc
parent8d8d7e6cef2c7820b223fe6c498703d92bb906ff (diff)
downloadFreeBSD-src-a3627bf7d397d64c8538b3ce0356b968d05d649a.zip
FreeBSD-src-a3627bf7d397d64c8538b3ce0356b968d05d649a.tar.gz
MFC r304047,r304068:
r304047: Add ePAPR boot support for PowerPC book-E (MPC85xx) hardware r304068: Only flush bp_kernload from the dcache, no need to sync the icache on the boot CPU.
Diffstat (limited to 'sys/powerpc')
-rw-r--r--sys/powerpc/booke/locore.S2
-rw-r--r--sys/powerpc/mpc85xx/platform_mpc85xx.c88
2 files changed, 82 insertions, 8 deletions
diff --git a/sys/powerpc/booke/locore.S b/sys/powerpc/booke/locore.S
index 9e47ee6..d6f8ac0 100644
--- a/sys/powerpc/booke/locore.S
+++ b/sys/powerpc/booke/locore.S
@@ -409,6 +409,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
diff --git a/sys/powerpc/mpc85xx/platform_mpc85xx.c b/sys/powerpc/mpc85xx/platform_mpc85xx.c
index fe29967..00c8a17 100644
--- a/sys/powerpc/mpc85xx/platform_mpc85xx.c
+++ b/sys/powerpc/mpc85xx/platform_mpc85xx.c
@@ -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, struct cpuref *cpuref)
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, struct pcpu *pc)
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, struct pcpu *pc)
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.
+ */
+ cpu_flush_dcache(&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, struct pcpu *pc)
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, struct pcpu *pc)
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, struct pcpu *pc)
* 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);
OpenPOWER on IntegriCloud