From 170912648fb06cf85cf9853b409920926d3b3987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Peixoto?= Date: Tue, 22 Oct 2024 11:57:34 +0100 Subject: [PATCH] feat(arch/riscv): add SBI hart suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds support for the SBI hart suspend. As specified in the SBI documentation, the suspend call is supported only from firmware version 0.3 onward. Signed-off-by: João Peixoto --- src/arch/riscv/cpu.c | 5 ++++- src/arch/riscv/inc/arch/sbi.h | 18 +++++++++++------- src/arch/riscv/sbi.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/arch/riscv/cpu.c b/src/arch/riscv/cpu.c index c159df77..75e8dd60 100644 --- a/src/arch/riscv/cpu.c +++ b/src/arch/riscv/cpu.c @@ -29,7 +29,10 @@ void cpu_arch_init(cpuid_t cpuid, paddr_t load_addr) void cpu_arch_idle(void) { - __asm__ volatile("wfi\n\t" ::: "memory"); + struct sbiret ret = sbi_hart_suspend(SBI_HSM_SUSPEND_RET_DEFAULT, 0, 0); + if (ret.error < 0) { + ERROR("failed to suspend hart %d", cpu()->id); + } __asm__ volatile("mv sp, %0\n\r" "j cpu_idle_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE])); ERROR("returned from idle wake up"); diff --git a/src/arch/riscv/inc/arch/sbi.h b/src/arch/riscv/inc/arch/sbi.h index dbc2fd82..886a5b43 100644 --- a/src/arch/riscv/inc/arch/sbi.h +++ b/src/arch/riscv/inc/arch/sbi.h @@ -13,13 +13,16 @@ * From https://github.com/riscv/riscv-sbi-doc */ -#define SBI_SUCCESS (0) -#define SBI_ERR_FAILURE (-1) -#define SBI_ERR_NOT_SUPPORTED (-2) -#define SBI_ERR_INVALID_PARAM (-3) -#define SBI_ERR_DENIED (-4) -#define SBI_ERR_INVALID_ADDRESS (-5) -#define SBI_ERR_ALREADY_AVAILABLE (-6) +#define SBI_SUCCESS (0) +#define SBI_ERR_FAILURE (-1) +#define SBI_ERR_NOT_SUPPORTED (-2) +#define SBI_ERR_INVALID_PARAM (-3) +#define SBI_ERR_DENIED (-4) +#define SBI_ERR_INVALID_ADDRESS (-5) +#define SBI_ERR_ALREADY_AVAILABLE (-6) + +#define SBI_HSM_SUSPEND_RET_DEFAULT (0x00000000) +#define SBI_HSM_SUSP_NON_RET_BIT (0x80000000) struct sbiret { long error; @@ -73,5 +76,6 @@ struct sbiret sbi_remote_hfence_vvma(const unsigned long hart_mask, unsigned lon struct sbiret sbi_hart_start(unsigned long hartid, unsigned long start_addr, unsigned long priv); struct sbiret sbi_hart_stop(void); struct sbiret sbi_hart_status(unsigned long hartid); +struct sbiret sbi_hart_suspend(uint32_t suspend_type, unsigned long resume_addr, unsigned long priv); #endif /* __SBI_H__ */ diff --git a/src/arch/riscv/sbi.c b/src/arch/riscv/sbi.c index 668717c8..40157d34 100644 --- a/src/arch/riscv/sbi.c +++ b/src/arch/riscv/sbi.c @@ -30,6 +30,7 @@ #define SBI_HART_START_FID (0) #define SBI_HART_STOP_FID (1) #define SBI_HART_STATUS_FID (2) +#define SBI_HART_SUSPEND_FID (3) #define SBI_EXTID_RFNC (0x52464E43) #define SBI_REMOTE_FENCE_I_FID (0) @@ -170,6 +171,12 @@ struct sbiret sbi_hart_status(unsigned long hartid) return sbi_ecall(SBI_EXTID_HSM, SBI_HART_STATUS_FID, hartid, 0, 0, 0, 0, 0); } +struct sbiret sbi_hart_suspend(uint32_t suspend_type, unsigned long resume_addr, unsigned long priv) +{ + return sbi_ecall(SBI_EXTID_HSM, SBI_HART_SUSPEND_FID, (unsigned long)suspend_type, resume_addr, + priv, 0, 0, 0); +} + static unsigned long ext_table[] = { SBI_EXTID_BASE, SBI_EXTID_TIME, SBI_EXTID_IPI, SBI_EXTID_RFNC, SBI_EXTID_HSM }; @@ -382,6 +389,30 @@ static struct sbiret sbi_hsm_status_handler(void) return ret; } +static struct sbiret sbi_hsm_suspend_handler(void) +{ + struct sbiret ret; + uint32_t suspend_type = (uint32_t)vcpu_readreg(cpu()->vcpu, REG_A0); + + spin_lock(&cpu()->vcpu->arch.sbi_ctx.lock); + if (cpu()->vcpu->arch.sbi_ctx.state != STARTED) { + ret.error = SBI_ERR_FAILURE; + } else { + if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) { + /* + * TODO: We only need to implement this when we get a real physical platform + * with real non-retentive suspend implementation. + * To support this we will need to save and restore the hart registers and CSRs. + */ + ret.error = SBI_ERR_NOT_SUPPORTED; + } else { + ret = sbi_hart_suspend(suspend_type, 0, 0); + } + } + + return ret; +} + static struct sbiret sbi_hsm_handler(unsigned long fid) { struct sbiret ret; @@ -393,6 +424,9 @@ static struct sbiret sbi_hsm_handler(unsigned long fid) case SBI_HART_STATUS_FID: ret = sbi_hsm_status_handler(); break; + case SBI_HART_SUSPEND_FID: + ret = sbi_hsm_suspend_handler(); + break; default: ret.error = SBI_ERR_NOT_SUPPORTED; }