Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/25752
Change subject: soc/cavium: Add secondary CPU support ......................................................................
soc/cavium: Add secondary CPU support
Change-Id: I07428161615bcd3d03a3eea0df2dd813e08c8f66 --- M src/mainboard/cavium/cn8100_sff_evb/Kconfig M src/mainboard/cavium/cn8100_sff_evb/mainboard.c M src/soc/cavium/cn81xx/Kconfig M src/soc/cavium/cn81xx/Makefile.inc M src/soc/cavium/cn81xx/cpu.c A src/soc/cavium/cn81xx/cpu_secondary.S M src/soc/cavium/cn81xx/include/soc/addressmap.h M src/soc/cavium/cn81xx/include/soc/cpu.h M src/soc/cavium/cn81xx/include/soc/memlayout.ld M src/soc/cavium/cn81xx/soc.c M src/soc/cavium/common/Makefile.inc 11 files changed, 286 insertions(+), 11 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/52/25752/1
diff --git a/src/mainboard/cavium/cn8100_sff_evb/Kconfig b/src/mainboard/cavium/cn8100_sff_evb/Kconfig index 15dd814..3f13ad5 100644 --- a/src/mainboard/cavium/cn8100_sff_evb/Kconfig +++ b/src/mainboard/cavium/cn8100_sff_evb/Kconfig @@ -56,6 +56,9 @@ string default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd"
+config MAX_CPUS + default 4 + ########################################################## #### Update below when adding a new derivative board. #### ########################################################## diff --git a/src/mainboard/cavium/cn8100_sff_evb/mainboard.c b/src/mainboard/cavium/cn8100_sff_evb/mainboard.c index 31163d2..3dbfbfd 100644 --- a/src/mainboard/cavium/cn8100_sff_evb/mainboard.c +++ b/src/mainboard/cavium/cn8100_sff_evb/mainboard.c @@ -62,7 +62,7 @@ printk(BIOS_INFO, "MB: COREclk : %llu MHz\n", thunderx_get_core_clock() / 1000000ULL);
- printk(BIOS_INFO, "MB: #CPU cores : %zu\n", cpu_get_num_cores()); + printk(BIOS_INFO, "MB: #CPU cores : %zu\n", cpu_get_num_available_cores()); }
static void mainboard_init(device_t dev) @@ -77,6 +77,10 @@
/* Init timer */ soc_timer_init(); + + /* Init CPUs */ + for (i = 1; i < CONFIG_MAX_CPUS; i++) + start_cpu(i, NULL); }
static void mainboard_enable(device_t dev) diff --git a/src/soc/cavium/cn81xx/Kconfig b/src/soc/cavium/cn81xx/Kconfig index cec0ada..d98378b 100644 --- a/src/soc/cavium/cn81xx/Kconfig +++ b/src/soc/cavium/cn81xx/Kconfig @@ -22,4 +22,7 @@
if SOC_CAVIUM_CN81XX
+config STACK_SIZE + default 0x2000 + endif diff --git a/src/soc/cavium/cn81xx/Makefile.inc b/src/soc/cavium/cn81xx/Makefile.inc index f98e890..6fb664e 100644 --- a/src/soc/cavium/cn81xx/Makefile.inc +++ b/src/soc/cavium/cn81xx/Makefile.inc @@ -65,6 +65,7 @@ ramstage-y += cpu.c ramstage-y += l2c.c ramstage-y += ecam0.c +ramstage-y += cpu_secondary.S
ramstage-y += bl31_plat_params.c BL31_MAKEARGS += PLAT=t81 M0_CROSS_COMPILE="$(CROSS_COMPILE_arm)" ENABLE_SPE_FOR_LOWER_ELS=0 diff --git a/src/soc/cavium/cn81xx/cpu.c b/src/soc/cavium/cn81xx/cpu.c index c054aa8..ee6feb4 100644 --- a/src/soc/cavium/cn81xx/cpu.c +++ b/src/soc/cavium/cn81xx/cpu.c @@ -14,13 +14,121 @@ */
#include <types.h> +#include <soc/addressmap.h> #include <arch/io.h> #include <soc/cpu.h> #include <bdk-coreboot.h> +#include <console/console.h> +#include <timer.h> +#include <delay.h>
-/* Return the number of cores available in the chip */ -size_t cpu_get_num_cores(void) +uint64_t cpu_get_available_core_mask(void) { - uint64_t available = read64((void *)0x87e006001738ll); - return bdk_dpop(available); + return read64((void *)RST_PP_AVAILABLE); +} + +size_t cpu_get_num_available_cores(void) +{ + return bdk_dpop(cpu_get_available_core_mask()); +} + +static void (* secondary_c_entry)(size_t core_id) = NULL; +static size_t secondary_booted; + +void secondary_cpu_init(size_t core_id) +{ + write64(&secondary_booted, 1); + dmb(); + + if (secondary_c_entry) + secondary_c_entry(core_id); + else + asm("wfi"); +} + +size_t cpu_self_get_core_id(void) +{ + u32 mpidr_el1; + asm("mrs %0, MPIDR_EL1\n\t" : "=r" (mpidr_el1) :: "memory"); + + /* Core is 4 bits from AFF0 and rest from AFF1 */ + size_t core_num; + core_num = mpidr_el1 & 0xf; + core_num |= (mpidr_el1 & 0xff00) >> 4; + + return core_num; +} + +uint64_t cpu_self_get_core_mask(void) +{ + return 1ULL << cpu_self_get_core_id(); +} + +size_t start_cpu(size_t cpu, void (* entry_64)(size_t core_id)) +{ + const uint64_t coremask = 1ULL << cpu; + struct stopwatch sw; + uint64_t pending; + + printk(BIOS_DEBUG, "CPU: Starting CPU%zu @ %p.\n", cpu, entry_64); + + /* Core not available */ + if (!(coremask & cpu_get_available_core_mask())) + return 1; + + /* Only secondary CPUs are supported */ + if (cpu == cpu_self_get_core_id()) + return 1; + + /* Check stack here, instead of in cpu_secondary.S */ + if ((CONFIG_STACK_SIZE * cpu) > _stack_sec_size) + return 1; + + /* Write the address of the main entry point */ + write64((void *)MIO_BOOT_AP_JUMP, (uintptr_t)secondary_init); + + /* Get coremask of cores in reset */ + const uint64_t reset = read64((void *)RST_PP_RESET); + printk(BIOS_INFO, "CPU: Cores currently in reset: 0x%llx\n", reset); + + /* Setup entry for secondary core */ + write64(&secondary_c_entry, (uintptr_t)entry_64); + write64(&secondary_booted, 0); + dmb(); + + printk(BIOS_DEBUG, "CPU: Taking core %zu out of reset.\n", cpu); + + /* Release core from reset */ + write64((void *)RST_PP_RESET, reset & ~coremask); + + /* Wait for cores to finish coming out of reset */ + udelay(1); + + stopwatch_init_usecs_expire(&sw, 1000000); + do { + pending = read64((void *)RST_PP_PENDING); + } while (!stopwatch_expired(&sw) && (pending & coremask)); + + if (stopwatch_expired(&sw)) { + printk(BIOS_ERR, "ERROR: Timeout waiting for reset " + "pending to clear."); + return 1; + } + + stopwatch_init_usecs_expire(&sw, 1000000); + + printk(BIOS_DEBUG, "CPU: Wait up to 1s for the core to boot...\n"); + while (!stopwatch_expired(&sw) && !read64(&secondary_booted)); + + /* Cleanup */ + write64(&secondary_c_entry, 0); + dmb(); + + if (!read64(&secondary_booted)) { + printk(BIOS_ERR, "ERROR: Core %zu failed to start.\n", cpu); + return 1; + } + + printk(BIOS_INFO, "CPU: Core %zu booted\n", cpu); + return 0; } diff --git a/src/soc/cavium/cn81xx/cpu_secondary.S b/src/soc/cavium/cn81xx/cpu_secondary.S new file mode 100644 index 0000000..d4b4d3c --- /dev/null +++ b/src/soc/cavium/cn81xx/cpu_secondary.S @@ -0,0 +1,91 @@ +/* + * Early initialization code for aarch64 (a.k.a. armv8) + * + * Copyright 2016 Cavium, Inc. support@cavium.com + * Copyright 2018-present Facebook, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/asm.h> +#include <soc/addressmap.h> + +// based on arm64_init_cpu +ENTRY(secondary_init) + /* Initialize PSTATE (unmask all exceptions, select SP_EL0). */ + msr SPSel, #0 + msr DAIFClr, #0xf + + /* TODO: This is where we'd put non-boot CPUs into WFI if needed. */ + + /* x22: SCTLR, return address: x23 (callee-saved by subroutine) */ + mov x23, x30 + /* TODO: Assert that we always start running at EL3 */ + mrs x22, sctlr_el3 + + /* Activate ICache (12) already for speed during cache flush below. */ + orr x22, x22, #(1 << 12) + msr sctlr_el3, x22 + isb + + /* Invalidate dcache */ + bl dcache_invalidate_all + + /* Deactivate MMU (0), Alignment Check (1) and DCache (2) */ + and x22, x22, # ~(1 << 0) & ~(1 << 1) & ~(1 << 2) + /* Activate Stack Alignment (3) because why not */ + orr x22, x22, #(1 << 3) + /* Set to little-endian (25) */ + and x22, x22, # ~(1 << 25) + /* Deactivate write-xor-execute enforcement (19) */ + and x22, x22, # ~(1 << 19) + msr sctlr_el3, x22 + + /* Invalidate icache and TLB for good measure */ + ic iallu + tlbi alle3 + dsb sy + isb + + /* Load core ID to x0 */ + mrs x0, MPIDR_EL1 + and x1, x0, # 0xf + lsr x0, x0, 4 + and x0, x0, # 0xff0 + orr x0, x0, x1 + + /* Each core gets CONFIG_STACK_SIZE bytes of stack */ + mov x2, # CONFIG_STACK_SIZE + mul x1, x0, x2 + /* Backup core id */ + mov x22, x0 + ldr x0, =_stack_sec + add x0, x1, x0 // x0 = CONFIG_STACK_SIZE * coreid + _stack_sec + add x1, x0, # CONFIG_STACK_SIZE // x1 = x0 + CONFIG_STACK_SIZE + + /* Initialize stack with sentinel value to later check overflow. */ + ldr x2, =0xdeadbeefdeadbeef + +1: + stp x2, x2, [x0], #16 + cmp x0, x1 + bne 1b + + /* Leave a line of beef dead for easier visibility in stack dumps. */ + sub sp, x0, #16 + + /* Set arg0 to core id */ + mov x0, x22 + + /* Call C entry */ + bl secondary_cpu_init + +ENDPROC(secondary_init) diff --git a/src/soc/cavium/cn81xx/include/soc/addressmap.h b/src/soc/cavium/cn81xx/include/soc/addressmap.h index e235494..f902963 100644 --- a/src/soc/cavium/cn81xx/include/soc/addressmap.h +++ b/src/soc/cavium/cn81xx/include/soc/addressmap.h @@ -54,9 +54,14 @@
/* RST */ #define RST_PF_BAR0 (0x87E006000000ULL + 0x1600) +#define RST_PP_AVAILABLE (RST_PF_BAR0 + 0x138ULL) +#define RST_PP_RESET (RST_PF_BAR0 + 0x140ULL) +#define RST_PP_PENDING (RST_PF_BAR0 + 0x148ULL) + #define FUSF_PF_BAR0 0x87E004000000ULL #define MIO_FUS_PF_BAR0 0x87E003000000ULL #define MIO_BOOT_PF_BAR0 0x87E000000000ULL +#define MIO_BOOT_AP_JUMP (MIO_BOOT_PF_BAR0 + 0xD0ULL)
/* PTP */ #define MIO_PTP_PF_BAR0 0x807000000000ULL diff --git a/src/soc/cavium/cn81xx/include/soc/cpu.h b/src/soc/cavium/cn81xx/include/soc/cpu.h index e4ee99b..3720750 100644 --- a/src/soc/cavium/cn81xx/include/soc/cpu.h +++ b/src/soc/cavium/cn81xx/include/soc/cpu.h @@ -9,6 +9,59 @@ #ifndef __SOC_CAVIUM_CN81XX_CPU_H__ #define __SOC_CAVIUM_CN81XX_CPU_H__
-size_t cpu_get_num_cores(void); +/** + * Number of the Core on which the program is currently running. + * + * @return Number of cores + */ +size_t cpu_self_get_core_id(void); + +/** + * Return a mask representing this core in a 64bit bitmask + * + * @return The mask of active core. + */ +uint64_t cpu_self_get_core_mask(void); + +/** + * Return the mask of available cores. + * + * @return Mask of available cores + */ +uint64_t cpu_get_available_core_mask(void); + +/** + * Return the number of cores available in the chip. + * + * @return The number of available cores. + */ +size_t cpu_get_num_available_cores(void); + +/** + * Init secondary cores and call the provided entry for given core. + * A stack of size 0x1000 is set up for each core in REGION stack_sec. + * The unique core id is passed to the entry point functions. + * + * @return zero on success + */ +size_t start_cpu(size_t cpu, void (* entry_64)(size_t core_id)); + +/** + * Secondary ASM CPU entry point. + * For internal use only. + */ +void secondary_init(void); + +/** + * Secondary CPU C entry point. + * For internal use only. + */ +void secondary_cpu_init(size_t core_id); + +/* Symbols in memlayout.ld */ + +extern u8 _stack_sec[]; +extern u8 _estack_sec[]; +#define _stack_sec_size (_estack_sec - _stack_sec)
#endif /* __SOC_CAVIUM_CN81XX_CPU_H__ */ diff --git a/src/soc/cavium/cn81xx/include/soc/memlayout.ld b/src/soc/cavium/cn81xx/include/soc/memlayout.ld index e4a71eb..96acb3f 100644 --- a/src/soc/cavium/cn81xx/include/soc/memlayout.ld +++ b/src/soc/cavium/cn81xx/include/soc/memlayout.ld @@ -38,6 +38,9 @@ SRAM_END(BOOTROM_OFFSET + 0x80000) TTB(BOOTROM_OFFSET + 0x80000, 128K) RAMSTAGE(BOOTROM_OFFSET + 0xa0000, 512K) + /* Stack for secondary CPUs */ + REGION(stack_sec, BOOTROM_OFFSET + 0x120000, + CONFIG_MAX_CPUS * CONFIG_STACK_SIZE, 0x1000)
/* Leave some space for the payload */ POSTRAM_CBFS_CACHE(0x2000000, 16M) diff --git a/src/soc/cavium/cn81xx/soc.c b/src/soc/cavium/cn81xx/soc.c index 3471ce2..1c79226 100644 --- a/src/soc/cavium/cn81xx/soc.c +++ b/src/soc/cavium/cn81xx/soc.c @@ -83,9 +83,12 @@ }
static struct device_operations soc_ops = { - .read_resources = soc_read_resources, - .init = soc_init, - .final = soc_final, + .read_resources = soc_read_resources, + .set_resources = DEVICE_NOOP, + .enable_resources = DEVICE_NOOP, + .init = soc_init, + .final = soc_final, + .scan_bus = NULL, };
static void enable_soc_dev(device_t dev) @@ -93,7 +96,8 @@ if (dev->path.type == DEVICE_PATH_DOMAIN && dev->path.domain.domain == 0) { dev->ops = &pci_domain_ops_ecam0; - } + } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) + dev->ops = &soc_ops; }
struct chip_operations soc_cavium_cn81xx_ops = { diff --git a/src/soc/cavium/common/Makefile.inc b/src/soc/cavium/common/Makefile.inc index 1c959e3..5e49755 100644 --- a/src/soc/cavium/common/Makefile.inc +++ b/src/soc/cavium/common/Makefile.inc @@ -15,7 +15,7 @@
ifeq ($(CONFIG_SOC_CAVIUM_COMMON),y)
-CFLAGS_arm64 += -Wstack-usage=8192 +CFLAGS_arm64 += -Wstack-usage=$(CONFIG_STACK_SIZE)
bootblock-$(CONFIG_BOOTBLOCK_CUSTOM) += bootblock.c