forked from Mirrors/opensbi
		
	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:
		
				
					committed by
					
						
						Anup Patel
					
				
			
			
				
	
			
			
			
						parent
						
							b20ed9febe
						
					
				
				
					commit
					79e42eb2d6
				
			@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user