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>
This commit is contained in:
Samuel Holland
2022-06-12 20:03:48 -05:00
committed by Anup Patel
parent b20ed9febe
commit 79e42eb2d6
2 changed files with 22 additions and 28 deletions

View File

@@ -34,9 +34,9 @@ struct sbi_hsm_device {
* the hart resumes normal execution. * the hart resumes normal execution.
* *
* For successful non-retentive suspend, the hart will resume from * For successful non-retentive suspend, the hart will resume from
* specified resume address * the warm boot entry point.
*/ */
int (*hart_suspend)(u32 suspend_type, ulong raddr); int (*hart_suspend)(u32 suspend_type);
/** /**
* Perform platform-specific actions to resume from a suspended state. * Perform platform-specific actions to resume from a suspended state.

View File

@@ -171,10 +171,10 @@ static int hsm_device_hart_stop(void)
return SBI_ENOTSUPP; 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) 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; return SBI_ENOTSUPP;
} }
@@ -319,7 +319,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
return 0; 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 */ /* Wait for interrupt */
wfi(); 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))); 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) void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
{ {
int oldstate; 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); __sbi_hsm_suspend_non_ret_save(scratch);
/* Try platform specific suspend */ /* 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) { if (ret == SBI_ENOTSUPP) {
/* Try generic implementation of default suspend types */ /* Try generic implementation of default suspend types */
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) { if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT ||
ret = __sbi_hsm_suspend_ret_default(scratch); suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) { ret = __sbi_hsm_suspend_default(scratch);
ret = __sbi_hsm_suspend_non_ret_default(scratch,
scratch->warmboot_addr);
} }
} }
/*
* 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: fail_restore_state:
/* /*
* We might have successfully resumed from retentive suspend * We might have successfully resumed from retentive suspend