Skip to content

Commit

Permalink
feat(core/cpu): decouple CPU standby from CPU power down
Browse files Browse the repository at this point in the history
Decoupled the CPU idle state (now called standby) from the CPU power down state.
This change allows future implementations requiring CPU standby — where the
core may be needed shortly after an event — to avoid transitioning to a deeper
power down state.

Signed-off-by: João Peixoto <[email protected]>
  • Loading branch information
joaopeixoto13 committed Oct 22, 2024
1 parent a62f42c commit 12b93d3
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 24 deletions.
10 changes: 9 additions & 1 deletion src/arch/armv8/armv8-a/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@ void cpu_arch_profile_init(cpuid_t cpuid, paddr_t load_addr)
}
}

void cpu_arch_profile_idle()
void cpu_arch_profile_standby()
{
int32_t err = psci_standby();
if (err) {
ERROR("PSCI cpu%d standby failed with error %ld", cpu()->id, err);
}
}

void cpu_arch_profile_powerdown()
{
int64_t err = psci_power_down(PSCI_WAKEUP_IDLE);
if (err) {
Expand Down
2 changes: 1 addition & 1 deletion src/arch/armv8/armv8-a/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ static void psci_wake_from_powerdown(void)

static void psci_wake_from_idle(void)
{
cpu_idle_wakeup();
cpu_standby_wakeup();
}

void psci_wake_from_off(void);
Expand Down
7 changes: 6 additions & 1 deletion src/arch/armv8/armv8-r/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ void cpu_arch_profile_init(cpuid_t cpuid, paddr_t load_addr)
UNUSED_ARG(load_addr);
}

void cpu_arch_profile_idle()
void cpu_arch_profile_standby()
{
__asm__ volatile("wfi");
}

void cpu_arch_profile_powerdown()
{
__asm__ volatile("wfi");
}
25 changes: 20 additions & 5 deletions src/arch/armv8/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,32 @@ unsigned long cpu_id_to_mpidr(cpuid_t id)
return platform_arch_cpuid_to_mpidr(&platform, id);
}

void cpu_arch_idle()
void cpu_arch_standby()
{
cpu_arch_profile_idle();
cpu_arch_profile_standby();

/*
* In case the profile implementation does not jump to a predefined wake-up point and just
* returns from the profile, manually rewind stack and jump to idle wake up. Therefore, we
* returns from the profile, manually rewind stack and jump to standby wake up. Therefore, we
* should not return after this point.
*/
__asm__ volatile("mov sp, %0\n\r"
"b cpu_idle_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE]));
"b cpu_standby_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE]));

ERROR("returned from idle wake up");
ERROR("returned from standby wake up");
}

void cpu_arch_powerdown()
{
cpu_arch_profile_powerdown();

/*
* In case the profile implementation does not jump to a predefined wake-up point and just
* returns from the profile, manually rewind stack and jump to powerdown wake up. Therefore, we
* should not return after this point.
*/
__asm__ volatile("mov sp, %0\n\r"
"b cpu_powerdown_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE]));

ERROR("returned from powerdown wake up");
}
3 changes: 2 additions & 1 deletion src/arch/armv8/inc/arch/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ struct cpu_arch {

unsigned long cpu_id_to_mpidr(cpuid_t id);
void cpu_arch_profile_init(cpuid_t cpuid, paddr_t load_addr);
void cpu_arch_profile_idle(void);
void cpu_arch_profile_standby(void);
void cpu_arch_profile_powerdown(void);

extern cpuid_t CPU_MASTER;

Expand Down
2 changes: 1 addition & 1 deletion src/arch/armv8/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ static int32_t psci_cpu_off_handler(void)
cpu()->vcpu->arch.psci_ctx.state = OFF;
spin_unlock(&cpu()->vcpu->arch.psci_ctx.lock);

cpu_idle();
cpu_powerdown();

spin_lock(&cpu()->vcpu->arch.psci_ctx.lock);
cpu()->vcpu->arch.psci_ctx.state = ON;
Expand Down
14 changes: 11 additions & 3 deletions src/arch/riscv/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,18 @@ void cpu_arch_init(cpuid_t cpuid, paddr_t load_addr)
}
}

void cpu_arch_idle(void)
void cpu_arch_standby(void)
{
__asm__ volatile("wfi\n\t" ::: "memory");
__asm__ volatile("mv sp, %0\n\r"
"j cpu_idle_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE]));
ERROR("returned from idle wake up");
"j cpu_standby_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE]));
ERROR("returned from standby wake up");
}

void cpu_arch_powerdown(void)
{
__asm__ volatile("wfi\n\t" ::: "memory");
__asm__ volatile("mv sp, %0\n\r"
"j cpu_powerdown_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE]));
ERROR("returned from powerdown wake up");
}
34 changes: 27 additions & 7 deletions src/core/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,29 @@ void cpu_msg_handler(void)
cpu()->handling_msgs = false;
}

void cpu_idle(void)
void cpu_standby(void)
{
cpu_arch_idle();
cpu_arch_standby();

/**
* Should not return here. cpu should "wake up" from idle in cpu_idle_wakeup with a rewinded
* stack.
* Should not return here. cpu should "wake up" from standby in cpu_standby_wakeup with a
* rewinded stack.
*/
ERROR("Spurious idle wake up");
ERROR("Spurious standby wake up");
}

void cpu_idle_wakeup(void)
void cpu_powerdown(void)
{
cpu_arch_powerdown();

/**
* Should not return here. cpu should "wake up" from powerdown in cpu_powerdown_wakeup with a
* rewinded stack.
*/
ERROR("Spurious powerdown wake up");
}

void cpu_standby_wakeup(void)
{
if (interrupts_check(interrupts_ipi_id)) {
interrupts_clear(interrupts_ipi_id);
Expand All @@ -110,6 +121,15 @@ void cpu_idle_wakeup(void)
if (cpu()->vcpu != NULL) {
vcpu_run(cpu()->vcpu);
} else {
cpu_idle();
cpu_standby();
}
}

void cpu_powerdown_wakeup(void)
{
if (cpu()->vcpu != NULL) {
vcpu_run(cpu()->vcpu);
} else {
cpu_powerdown();
}
}
9 changes: 6 additions & 3 deletions src/core/inc/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,14 @@ void cpu_send_msg(cpuid_t cpu, struct cpu_msg* msg);
bool cpu_get_msg(struct cpu_msg* msg);
void cpu_msg_handler(void);
void cpu_msg_set_handler(cpuid_t id, cpu_msg_handler_t handler);
void cpu_idle(void);
void cpu_idle_wakeup(void);
void cpu_standby(void);
void cpu_powerdown(void);
void cpu_standby_wakeup(void);
void cpu_powerdown_wakeup(void);

void cpu_arch_init(cpuid_t cpu_id, paddr_t load_addr);
void cpu_arch_idle(void);
void cpu_arch_standby(void);
void cpu_arch_powerdown(void);

extern struct cpuif cpu_interfaces[];
static inline struct cpuif* cpu_if(cpuid_t cpu_id)
Expand Down
2 changes: 1 addition & 1 deletion src/core/vmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,6 @@ void vmm_init()
cpu_sync_barrier(&vm->sync);
vcpu_run(cpu()->vcpu);
} else {
cpu_idle();
cpu_powerdown();
}
}

0 comments on commit 12b93d3

Please sign in to comment.