[PATCH 1/2] lib: sbi: restore platform CSR when suspend

Samuel Holland samuel.holland at sifive.com
Sun Dec 7 02:58:30 PST 2025


Hi Xiang,

On 2025-12-04 8:58 AM, Xiang W wrote:
> When HART enters suspend mode, some platforms require specific CSRs
> to be saved for recovery. This patch add interface for this.
> 
> Signed-off-by: Xiang W <wangxiang at iscas.ac.cn>
> ---
>  include/sbi/sbi_platform.h | 60 ++++++++++++++++++++++++++++++++++++++
>  lib/sbi/sbi_hsm.c          | 12 +++++++-
>  2 files changed, 71 insertions(+), 1 deletion(-)
> 
> diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
> index d75c12de..175ec1e2 100644
> --- a/include/sbi/sbi_platform.h
> +++ b/include/sbi/sbi_platform.h
> @@ -41,6 +41,9 @@
>  #define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2))
>  /** Offset of cbom_block_size in struct sbi_platform */
>  #define SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET (0x60 + (__SIZEOF_POINTER__ * 3))
> +/** Offset of suspend_backup_csr_count in struct sbi_platform */
> +#define SBI_PLATFORM_SUSPEND_BACKUP_CSR_COUNT_OFFSET \
> +					    (0x60 + (__SIZEOF_POINTER__ * 4))
>  
>  #define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT		(1UL << 12)
>  
> @@ -146,6 +149,12 @@ struct sbi_platform_operations {
>  			unsigned long log2len);
>  	/** platform specific pmp disable on current HART */
>  	void (*pmp_disable)(unsigned int n);
> +
> +	/** Save platform specific CSR before suspend */
> +	void (*suspend_non_ret_save)(unsigned long *data);
> +
> +	/** Restore platform specific CSR after suspend */
> +	void (*suspend_non_ret_restore)(unsigned long *data);
>  };
>  
>  /** Platform default per-HART stack size for exception/interrupt handling */
> @@ -198,6 +207,13 @@ struct sbi_platform {
>  	const u32 *hart_index2id;
>  	/** Allocation alignment for Scratch */
>  	unsigned long cbom_block_size;
> +
> +	/**
> +	 * When HART enters suspend mode, some platforms require specific CSRs
> +	 * to be saved for recovery. This variable tracks how many CSRs need to
> +	 *  be backed up for this platform.

There's an extra space before "be".

> +	 */
> +	unsigned long suspend_backup_csr_count;
>  };
>  
>  /**
> @@ -216,6 +232,8 @@ assert_member_offset(struct sbi_platform, platform_ops_addr, SBI_PLATFORM_OPS_OF
>  assert_member_offset(struct sbi_platform, firmware_context, SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET);
>  assert_member_offset(struct sbi_platform, hart_index2id, SBI_PLATFORM_HART_INDEX2ID_OFFSET);
>  assert_member_offset(struct sbi_platform, cbom_block_size, SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET);
> +assert_member_offset(struct sbi_platform, suspend_backup_csr_count, SBI_PLATFORM_SUSPEND_BACKUP_CSR_COUNT_OFFSET);
> +
>  
>  /** Get pointer to sbi_platform for sbi_scratch pointer */
>  #define sbi_platform_ptr(__s) \
> @@ -666,6 +684,48 @@ static inline void sbi_platform_pmp_disable(const struct sbi_platform *plat,
>  		sbi_platform_ops(plat)->pmp_disable(n);
>  }
>  
> +/**
> + * Platform specific CSR count to backup during suspend.
> + *
> + * @param plat pointer to struct sbi_platform
> + *
> + * @return csr count need backup
> + */
> +static inline unsigned long sbi_platform_suspend_backup_csr_count(
> +					    const struct sbi_platform *plat)
> +{
> +	if (plat)
> +		return plat->suspend_backup_csr_count;
> +	return 0;
> +}
> +
> +/**
> + * Save platform specific CSR before suspend
> + *
> + * @param plat pointer to struct sbi_platform
> + * @param data buffer used to save CSR
> + */
> +static inline void sbi_platform_suspend_non_ret_save(
> +					    const struct sbi_platform *plat,
> +					    unsigned long *data)
> +{
> +	if (plat && sbi_platform_ops(plat)->suspend_non_ret_save)
> +		sbi_platform_ops(plat)->suspend_non_ret_save(data);
> +}
> +
> +/**
> + * Restore platform specific CSR after suspend
> + * @param plat pointer to struct sbi_platform
> + * @param data buffer used to restore CSR
> + */
> +static inline void sbi_platform_suspend_non_ret_restore(
> +					    const struct sbi_platform *plat,
> +					    unsigned long *data)
> +{
> +	if (plat && sbi_platform_ops(plat)->suspend_non_ret_restore)
> +		sbi_platform_ops(plat)->suspend_non_ret_restore(data);
> +}
> +
>  #endif
>  
>  #endif
> diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
> index 0a355f9c..949f7aaf 100644
> --- a/lib/sbi/sbi_hsm.c
> +++ b/lib/sbi/sbi_hsm.c
> @@ -21,6 +21,7 @@
>  #include <sbi/sbi_hsm.h>
>  #include <sbi/sbi_init.h>
>  #include <sbi/sbi_ipi.h>
> +#include <sbi/sbi_platform.h>
>  #include <sbi/sbi_scratch.h>
>  #include <sbi/sbi_system.h>
>  #include <sbi/sbi_timer.h>
> @@ -50,6 +51,7 @@ struct sbi_hsm_data {
>  	unsigned long saved_mideleg;
>  	u64 saved_menvcfg;
>  	atomic_t start_ticket;
> +	unsigned long platform_saved[0];

Please use the standard flexible array member syntax (no zero) instead of the
GNU extension.

>  };
>  
>  bool sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
> @@ -249,9 +251,13 @@ int sbi_hsm_init(struct sbi_scratch *scratch, bool cold_boot)
>  {
>  	struct sbi_scratch *rscratch;
>  	struct sbi_hsm_data *hdata;
> +	unsigned long n;
>  
>  	if (cold_boot) {
> -		hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata));
> +		n = sbi_platform_suspend_backup_csr_count(
> +			sbi_platform_ptr(scratch));
> +		hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata) +
> +							    n * sizeof(long));
>  		if (!hart_data_offset)
>  			return SBI_ENOMEM;
>  
> @@ -430,6 +436,8 @@ void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
>  	hdata->saved_mideleg = csr_read(CSR_MIDELEG);
>  	if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
>  		hdata->saved_menvcfg = csr_read64(CSR_MENVCFG);
> +
> +	sbi_platform_suspend_non_ret_save(sbi_platform_ptr(scratch), hdata->platform_saved);
>  }
>  
>  static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
> @@ -443,6 +451,8 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
>  	csr_write(CSR_MEDELEG, hdata->saved_medeleg);
>  	csr_write(CSR_MIE, hdata->saved_mie);
>  	csr_set(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
> +
> +	sbi_platform_suspend_non_ret_restore(sbi_platform_ptr(scratch), hdata->platform_saved);

The suspend/restore functions operate in reverse/LIFO order. I would suggest to
maintain this property.

Regards,
Samuel

>  }
>  
>  void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)




More information about the opensbi mailing list