smp: Added A7-A11 start support

This includes:

- EL3 handling
- "Slow" IPI support
- New start offsets

Signed-off-by: Nick Chan <towinchenmi@gmail.com>
This commit is contained in:
Nick Chan 2024-08-25 15:32:28 +08:00 committed by Hector Martin
parent 32ca84c769
commit cb0ceb4ee8
5 changed files with 79 additions and 10 deletions

View file

@ -201,6 +201,11 @@ void aic_set_sw(int irq, bool active)
MASK_BIT(irq)); MASK_BIT(irq));
} }
void aic_write(u32 reg, u32 val)
{
write32(aic->base + reg, val);
}
uint32_t aic_ack(void) uint32_t aic_ack(void)
{ {
return read32(aic->base + aic->regs.event); return read32(aic->base + aic->regs.event);

View file

@ -39,6 +39,7 @@ extern struct aic *aic;
void aic_init(void); void aic_init(void);
void aic_set_sw(int irq, bool active); void aic_set_sw(int irq, bool active);
void aic_write(u32 reg, u32 val);
uint32_t aic_ack(void); uint32_t aic_ack(void);
#endif #endif

View file

@ -2,6 +2,8 @@
#include "smp.h" #include "smp.h"
#include "adt.h" #include "adt.h"
#include "aic.h"
#include "aic_regs.h"
#include "cpu_regs.h" #include "cpu_regs.h"
#include "malloc.h" #include "malloc.h"
#include "pmgr.h" #include "pmgr.h"
@ -10,6 +12,8 @@
#include "types.h" #include "types.h"
#include "utils.h" #include "utils.h"
#define CPU_START_OFF_S5L8960X 0x30000
#define CPU_START_OFF_S8000 0xd4000
#define CPU_START_OFF_T8103 0x54000 #define CPU_START_OFF_T8103 0x54000
#define CPU_START_OFF_T8112 0x34000 #define CPU_START_OFF_T8112 0x34000
#define CPU_START_OFF_T6020 0x28000 #define CPU_START_OFF_T6020 0x28000
@ -28,11 +32,14 @@ struct spin_table {
}; };
void *_reset_stack; void *_reset_stack;
void *_reset_stack_el1;
#define DUMMY_STACK_SIZE 0x1000 #define DUMMY_STACK_SIZE 0x1000
u8 dummy_stack[DUMMY_STACK_SIZE]; u8 dummy_stack[DUMMY_STACK_SIZE]; // Highest EL
u8 dummy_stack_el1[DUMMY_STACK_SIZE]; // EL1 stack if EL3 exists
u8 *secondary_stacks[MAX_CPUS] = {dummy_stack}; u8 *secondary_stacks[MAX_CPUS] = {dummy_stack};
u8 *secondary_stacks_el3[MAX_EL3_CPUS];
static bool wfe_mode = false; static bool wfe_mode = false;
@ -63,14 +70,28 @@ void smp_secondary_entry(void)
me->flag = 1; me->flag = 1;
sysop("dmb sy"); sysop("dmb sy");
u64 target; u64 target;
if (!cpufeat_fast_ipi)
aic_write(AIC_IPI_MASK_SET, AIC_IPI_SELF); // we only use the "other" IPI
while (1) { while (1) {
while (!(target = me->target)) { while (!(target = me->target)) {
if (wfe_mode) { if (wfe_mode) {
sysop("wfe"); sysop("wfe");
} else {
if (!supports_arch_retention()) {
// A7 - A11 does not support state retention across deep WFI
// i.e. CPU always ends up at rvbar after deep WFI
sysop("wfi");
} else { } else {
deep_wfi(); deep_wfi();
}
if (cpufeat_fast_ipi) {
msr(SYS_IMP_APL_IPI_SR_EL1, 1); msr(SYS_IMP_APL_IPI_SR_EL1, 1);
} else {
aic_ack(); // Actually read IPI reason
aic_write(AIC_IPI_ACK, AIC_IPI_OTHER);
aic_write(AIC_IPI_MASK_CLR, AIC_IPI_OTHER);
}
} }
sysop("isb"); sysop("isb");
} }
@ -92,6 +113,9 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u
if (index >= MAX_CPUS) if (index >= MAX_CPUS)
return; return;
if (has_el3() && index >= MAX_EL3_CPUS)
return;
if (spin_table[index].flag) if (spin_table[index].flag)
return; return;
@ -101,6 +125,11 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u
target_cpu = index; target_cpu = index;
secondary_stacks[index] = memalign(0x4000, SECONDARY_STACK_SIZE); secondary_stacks[index] = memalign(0x4000, SECONDARY_STACK_SIZE);
if (has_el3()) {
secondary_stacks_el3[index] = memalign(0x4000, SECONDARY_STACK_SIZE);
_reset_stack = secondary_stacks_el3[index] + SECONDARY_STACK_SIZE; // EL3
_reset_stack_el1 = secondary_stacks[index] + SECONDARY_STACK_SIZE; // EL1
} else
_reset_stack = secondary_stacks[index] + SECONDARY_STACK_SIZE; _reset_stack = secondary_stacks[index] + SECONDARY_STACK_SIZE;
sysop("dmb sy"); sysop("dmb sy");
@ -129,6 +158,7 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 impl, u
printf(" Started.\n"); printf(" Started.\n");
_reset_stack = dummy_stack + DUMMY_STACK_SIZE; _reset_stack = dummy_stack + DUMMY_STACK_SIZE;
_reset_stack_el1 = dummy_stack_el1 + DUMMY_STACK_SIZE;
} }
static void smp_stop_cpu(int index, int die, int cluster, int core, u64 impl, u64 cpu_start_base, static void smp_stop_cpu(int index, int die, int cluster, int core, u64 impl, u64 cpu_start_base,
@ -202,6 +232,20 @@ void smp_start_secondaries(void)
memset(cpu_nodes, 0, sizeof(cpu_nodes)); memset(cpu_nodes, 0, sizeof(cpu_nodes));
switch (chip_id) { switch (chip_id) {
case S5L8960X:
case T7000:
case T7001:
cpu_start_off = CPU_START_OFF_S5L8960X;
break;
case S8000:
case S8001:
case S8003:
case T8010:
case T8011:
case T8012:
case T8015:
cpu_start_off = CPU_START_OFF_S8000;
break;
case T8103: case T8103:
case T6000: case T6000:
case T6001: case T6001:
@ -324,7 +368,11 @@ void smp_send_ipi(int cpu)
return; return;
u64 mpidr = spin_table[cpu].mpidr; u64 mpidr = spin_table[cpu].mpidr;
if (cpufeat_fast_ipi) {
msr(SYS_IMP_APL_IPI_RR_GLOBAL_EL1, (mpidr & 0xff) | ((mpidr & 0xff00) << 8)); msr(SYS_IMP_APL_IPI_RR_GLOBAL_EL1, (mpidr & 0xff) | ((mpidr & 0xff00) << 8));
} else {
aic_write(AIC_IPI_SEND, AIC_IPI_SEND_CPU(cpu));
}
} }
void smp_call4(int cpu, void *func, u64 arg0, u64 arg1, u64 arg2, u64 arg3) void smp_call4(int cpu, void *func, u64 arg0, u64 arg1, u64 arg2, u64 arg3)

View file

@ -7,9 +7,11 @@
#include "utils.h" #include "utils.h"
#define MAX_CPUS 24 #define MAX_CPUS 24
#define MAX_EL3_CPUS 4
#define SECONDARY_STACK_SIZE 0x10000 #define SECONDARY_STACK_SIZE 0x10000
extern u8 *secondary_stacks[MAX_CPUS]; extern u8 *secondary_stacks[MAX_CPUS];
extern u8 *secondary_stacks_el3[MAX_EL3_CPUS];
void smp_secondary_entry(void); void smp_secondary_entry(void);

View file

@ -161,9 +161,22 @@ cpu_reset:
bl debug_putc bl debug_putc
mov x0, sp mov x0, sp
mrs x8, CurrentEL
cmp x8, #0xc
beq cpu_reset_el3
bl _cpu_reset_c bl _cpu_reset_c
b . b .
cpu_reset_el3:
bl _cpu_reset_c
adrp x6, _reset_stack_el1
add x6, x6, :lo12:_reset_stack_el1
ldr x6, [x6]
mov x0, x6
adr x7, _cpu_reset_c
el3_eret_to_el1: el3_eret_to_el1:
adr x8, _vectors_start adr x8, _vectors_start
msr sctlr_el1, xzr msr sctlr_el1, xzr