Changeset View
Changeset View
Standalone View
Standalone View
head/sys/powerpc/mpc85xx/platform_mpc85xx.c
Show All 33 Lines | |||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/pcpu.h> | #include <sys/pcpu.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/hid.h> | #include <machine/hid.h> | ||||
#include <machine/_inttypes.h> | |||||
#include <machine/machdep.h> | #include <machine/machdep.h> | ||||
#include <machine/md_var.h> | |||||
#include <machine/platform.h> | #include <machine/platform.h> | ||||
#include <machine/platformvar.h> | #include <machine/platformvar.h> | ||||
#include <machine/smp.h> | #include <machine/smp.h> | ||||
#include <machine/spr.h> | #include <machine/spr.h> | ||||
#include <machine/vmparam.h> | #include <machine/vmparam.h> | ||||
#include <dev/fdt/fdt_common.h> | #include <dev/fdt/fdt_common.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_extern.h> | |||||
#include <powerpc/mpc85xx/mpc85xx.h> | #include <powerpc/mpc85xx/mpc85xx.h> | ||||
#include "platform_if.h" | #include "platform_if.h" | ||||
#ifdef SMP | #ifdef SMP | ||||
extern void *ap_pcpu; | extern void *ap_pcpu; | ||||
extern vm_paddr_t kernload; /* Kernel physical load address */ | extern vm_paddr_t kernload; /* Kernel physical load address */ | ||||
extern uint8_t __boot_page[]; /* Boot page body */ | extern uint8_t __boot_page[]; /* Boot page body */ | ||||
extern uint32_t bp_kernload; | 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 | #endif | ||||
extern uint32_t *bootinfo; | extern uint32_t *bootinfo; | ||||
vm_offset_t ccsrbar_va; | vm_offset_t ccsrbar_va; | ||||
static int cpu, maxcpu; | static int cpu, maxcpu; | ||||
static int mpc85xx_probe(platform_t); | static int mpc85xx_probe(platform_t); | ||||
▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
cpuref->cr_cpuid = mfspr(SPR_PIR); | cpuref->cr_cpuid = mfspr(SPR_PIR); | ||||
cpuref->cr_hwref = cpuref->cr_cpuid; | cpuref->cr_hwref = cpuref->cr_cpuid; | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef SMP | |||||
static int | 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) | mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc) | ||||
{ | { | ||||
#ifdef SMP | #ifdef SMP | ||||
vm_paddr_t bptr; | vm_paddr_t bptr; | ||||
uint32_t reg; | uint32_t reg; | ||||
int timeout; | int timeout; | ||||
uintptr_t brr; | uintptr_t brr; | ||||
int cpuid; | int cpuid; | ||||
int epapr_boot = 0; | |||||
uint32_t tgt; | uint32_t tgt; | ||||
if (mpc85xx_is_qoriq()) { | if (mpc85xx_is_qoriq()) { | ||||
reg = ccsr_read4(OCP85XX_COREDISR); | reg = ccsr_read4(OCP85XX_COREDISR); | ||||
cpuid = pc->pc_cpuid; | cpuid = pc->pc_cpuid; | ||||
if ((reg & (1 << cpuid)) != 0) { | if ((reg & (1 << cpuid)) != 0) { | ||||
printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid); | printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
brr = OCP85XX_BRR; | brr = OCP85XX_BRR; | ||||
} else { | } else { | ||||
brr = OCP85XX_EEBPCR; | brr = OCP85XX_EEBPCR; | ||||
cpuid = pc->pc_cpuid + 24; | cpuid = pc->pc_cpuid + 24; | ||||
} | } | ||||
bp_kernload = kernload; | 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); | reg = ccsr_read4(brr); | ||||
if ((reg & (1 << cpuid)) != 0) { | if ((reg & (1 << cpuid)) != 0) { | ||||
printf("SMP: CPU %d already out of hold-off state!\n", | printf("SMP: CPU %d already out of hold-off state!\n", | ||||
pc->pc_cpuid); | pc->pc_cpuid); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
ap_pcpu = pc; | |||||
__asm __volatile("msync; isync"); | |||||
/* Flush caches to have our changes hit DRAM. */ | /* Flush caches to have our changes hit DRAM. */ | ||||
cpu_flush_dcache(__boot_page, 4096); | cpu_flush_dcache(__boot_page, 4096); | ||||
bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload; | bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload; | ||||
KASSERT((bptr & 0xfff) == 0, | KASSERT((bptr & 0xfff) == 0, | ||||
("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr)); | ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr)); | ||||
if (mpc85xx_is_qoriq()) { | if (mpc85xx_is_qoriq()) { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | #ifdef SMP | ||||
/* | /* | ||||
* Release AP from hold-off state | * Release AP from hold-off state | ||||
*/ | */ | ||||
reg = ccsr_read4(brr); | reg = ccsr_read4(brr); | ||||
ccsr_write4(brr, reg | (1 << cpuid)); | ccsr_write4(brr, reg | (1 << cpuid)); | ||||
__asm __volatile("isync; msync"); | __asm __volatile("isync; msync"); | ||||
spin_wait: | |||||
timeout = 500; | timeout = 500; | ||||
while (!pc->pc_awake && timeout--) | while (!pc->pc_awake && timeout--) | ||||
DELAY(1000); /* wait 1ms */ | DELAY(1000); /* wait 1ms */ | ||||
/* | /* | ||||
* Disable boot page translation so that the 4K page at the default | * Disable boot page translation so that the 4K page at the default | ||||
* address (= 0xfffff000) isn't permanently remapped and thus not | * address (= 0xfffff000) isn't permanently remapped and thus not | ||||
* usable otherwise. | * usable otherwise. | ||||
*/ | */ | ||||
if (!epapr_boot) { | |||||
if (mpc85xx_is_qoriq()) | if (mpc85xx_is_qoriq()) | ||||
ccsr_write4(OCP85XX_BSTAR, 0); | ccsr_write4(OCP85XX_BSTAR, 0); | ||||
else | else | ||||
ccsr_write4(OCP85XX_BPTR, 0); | ccsr_write4(OCP85XX_BPTR, 0); | ||||
__asm __volatile("isync; msync"); | __asm __volatile("isync; msync"); | ||||
} | |||||
if (!pc->pc_awake) | if (!pc->pc_awake) | ||||
panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid); | panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid); | ||||
return ((pc->pc_awake) ? 0 : EBUSY); | return ((pc->pc_awake) ? 0 : EBUSY); | ||||
#else | #else | ||||
/* No SMP support */ | /* No SMP support */ | ||||
return (ENXIO); | return (ENXIO); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 60 Lines • Show Last 20 Lines |