diff options
author | Samuel Holland <samuel@sholland.org> | 2022-06-13 04:03:48 +0300 |
---|---|---|
committer | Anup Patel <anup@brainfault.org> | 2022-06-13 09:24:06 +0300 |
commit | 79e42eb2d646097198aed935042e289e53ff9876 (patch) | |
tree | 1a8e0cc332bbd68c7acc98c82737c4fab9b362f5 /lib | |
parent | b20ed9febe0b78228055ce69d8e3fbb13f64f1cc (diff) | |
download | opensbi-79e42eb2d646097198aed935042e289e53ff9876.tar.xz |
lib: sbi_hsm: Assume a consistent resume address
The suspend code needs to know the resume address for two reasons:
1) Programming some hardware register or management firmware. Here we
assume the hardware/firmware maintains its state between suspends,
so it only needs to be programmed once at startup.
2) When a non-retentive suspend request ends up being retentive, due
to lack of hardware support, pending interrupt, or for some other
reason. However, the behavior here is not platform-dependent, and
this can be handled in the generic hart suspend function.
Since neither situation requires the platform-level suspend function to
know the resume address, stop passing it to that function. Instead,
handle the non-retentive to retentive situation generically.
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sbi/sbi_hsm.c | 46 |
1 files changed, 20 insertions, 26 deletions
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index a7b6a80..1165acc 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -171,10 +171,10 @@ static int hsm_device_hart_stop(void) return SBI_ENOTSUPP; } -static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr) +static int hsm_device_hart_suspend(u32 suspend_type) { if (hsm_dev && hsm_dev->hart_suspend) - return hsm_dev->hart_suspend(suspend_type, raddr); + return hsm_dev->hart_suspend(suspend_type); return SBI_ENOTSUPP; } @@ -319,7 +319,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow) return 0; } -static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch) +static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch) { /* Wait for interrupt */ wfi(); @@ -359,23 +359,6 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch) csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP))); } -static int __sbi_hsm_suspend_non_ret_default(struct sbi_scratch *scratch, - ulong raddr) -{ - void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr; - - /* Wait for interrupt */ - wfi(); - - /* - * Directly jump to warm reboot to simulate resume from a - * non-retentive suspend. - */ - jump_warmboot(); - - return 0; -} - void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch) { int oldstate; @@ -473,17 +456,28 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, __sbi_hsm_suspend_non_ret_save(scratch); /* Try platform specific suspend */ - ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr); + ret = hsm_device_hart_suspend(suspend_type); if (ret == SBI_ENOTSUPP) { /* Try generic implementation of default suspend types */ - if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) { - ret = __sbi_hsm_suspend_ret_default(scratch); - } else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) { - ret = __sbi_hsm_suspend_non_ret_default(scratch, - scratch->warmboot_addr); + if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT || + suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) { + ret = __sbi_hsm_suspend_default(scratch); } } + /* + * The platform may have coordinated a retentive suspend, or it may + * have exited early from a non-retentive suspend. Either way, the + * caller is not expecting a successful return, so jump to the warm + * boot entry point to simulate resume from a non-retentive suspend. + */ + if (ret == 0 && (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)) { + void (*jump_warmboot)(void) = + (void (*)(void))scratch->warmboot_addr; + + jump_warmboot(); + } + fail_restore_state: /* * We might have successfully resumed from retentive suspend |