lib: sbi: Implement system suspend

Fill the implementation of the system suspend ecall. A platform
implementation of the suspend callbacks is still required for this
to do anything.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
Andrew Jones 2023-02-27 11:31:04 +01:00 committed by Anup Patel
parent c9917b6108
commit 7c964e279c

View file

@ -116,5 +116,60 @@ bool sbi_system_suspend_supported(u32 sleep_type)
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
{
return 0;
int ret = SBI_ENOTSUPP;
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
unsigned int hartid = current_hartid();
unsigned long prev_mode;
unsigned long i;
if (!dom || !dom->system_suspend_allowed)
return SBI_EFAIL;
if (!suspend_dev || !suspend_dev->system_suspend)
return SBI_EFAIL;
if (!sbi_system_suspend_supported(sleep_type))
return SBI_ENOTSUPP;
prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_EFAIL;
sbi_hartmask_for_each_hart(i, &dom->assigned_harts) {
if (i == hartid)
continue;
if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED)
return SBI_EFAIL;
}
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVALID_ADDR;
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_STARTED,
SBI_HSM_STATE_SUSPENDED))
return SBI_EFAIL;
/* Prepare for resume */
scratch->next_mode = prev_mode;
scratch->next_addr = resume_addr;
scratch->next_arg1 = opaque;
__sbi_hsm_suspend_non_ret_save(scratch);
/* Suspend */
ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
if (ret != SBI_OK) {
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
SBI_HSM_STATE_STARTED))
sbi_hart_hang();
return ret;
}
/* Resume */
jump_warmboot();
__builtin_unreachable();
}