Message ID | 20231129113414.41661-4-ajones@ventanamicro.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | riscv: Introduce system suspend support | expand |
Hi Andrew, On 2023-11-29 5:34 AM, Andrew Jones wrote: > When the SUSP SBI extension is present it implies that the standard > "suspend to RAM" type is available. Wire it up to the generic > platform suspend support, also applying the already present support > for non-retentive CPU suspend. When the kernel is built with > CONFIG_SUSPEND, one can do 'echo mem > /sys/power/state' to suspend. > Resumption will occur when a platform-specific wake-up event arrives. > > Signed-off-by: Andrew Jones <ajones@ventanamicro.com> > Tested-by: Samuel Holland <samuel.holland@sifive.com> > --- > arch/riscv/Kconfig | 6 ++++- > arch/riscv/include/asm/sbi.h | 9 ++++++++ > arch/riscv/kernel/suspend.c | 44 ++++++++++++++++++++++++++++++++++++ > 3 files changed, 58 insertions(+), 1 deletion(-) > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > index 95a2a06acc6a..385fcad45c47 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -65,7 +65,7 @@ config RISCV > select CLINT_TIMER if !MMU > select CLONE_BACKWARDS > select COMMON_CLK > - select CPU_PM if CPU_IDLE || HIBERNATION > + select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND > select EDAC_SUPPORT > select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE) > select GENERIC_ARCH_TOPOLOGY > @@ -918,9 +918,13 @@ config PORTABLE > select MMU > select OF > > + > config ARCH_PROC_KCORE_TEXT > def_bool y > > +config ARCH_SUSPEND_POSSIBLE > + def_bool RISCV_SBI > + This option was already added by commit c1f048a6bd7d ("riscv: Enable ARCH_SUSPEND_POSSIBLE for s2idle"), so this hunk is a duplicate. Regards, Samuel > menu "Power management options" > > source "kernel/power/Kconfig" > diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h > index 0892f4421bc4..f09356e187df 100644 > --- a/arch/riscv/include/asm/sbi.h > +++ b/arch/riscv/include/asm/sbi.h > @@ -29,6 +29,7 @@ enum sbi_ext_id { > SBI_EXT_RFENCE = 0x52464E43, > SBI_EXT_HSM = 0x48534D, > SBI_EXT_SRST = 0x53525354, > + SBI_EXT_SUSP = 0x53555350, > SBI_EXT_PMU = 0x504D55, > SBI_EXT_DBCN = 0x4442434E, > > @@ -114,6 +115,14 @@ enum sbi_srst_reset_reason { > SBI_SRST_RESET_REASON_SYS_FAILURE, > }; > > +enum sbi_ext_susp_fid { > + SBI_EXT_SUSP_SYSTEM_SUSPEND = 0, > +}; > + > +enum sbi_ext_susp_sleep_type { > + SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM = 0, > +}; > + > enum sbi_ext_pmu_fid { > SBI_EXT_PMU_NUM_COUNTERS = 0, > SBI_EXT_PMU_COUNTER_GET_INFO, > diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c > index 3c89b8ec69c4..239509367e42 100644 > --- a/arch/riscv/kernel/suspend.c > +++ b/arch/riscv/kernel/suspend.c > @@ -4,8 +4,12 @@ > * Copyright (c) 2022 Ventana Micro Systems Inc. > */ > > +#define pr_fmt(fmt) "suspend: " fmt > + > #include <linux/ftrace.h> > +#include <linux/suspend.h> > #include <asm/csr.h> > +#include <asm/sbi.h> > #include <asm/suspend.h> > > void suspend_save_csrs(struct suspend_context *context) > @@ -85,3 +89,43 @@ int cpu_suspend(unsigned long arg, > > return rc; > } > + > +#ifdef CONFIG_RISCV_SBI > +static int sbi_system_suspend(unsigned long sleep_type, > + unsigned long resume_addr, > + unsigned long opaque) > +{ > + struct sbiret ret; > + > + ret = sbi_ecall(SBI_EXT_SUSP, SBI_EXT_SUSP_SYSTEM_SUSPEND, > + sleep_type, resume_addr, opaque, 0, 0, 0); > + if (ret.error) > + return sbi_err_map_linux_errno(ret.error); > + > + return ret.value; > +} > + > +static int sbi_system_suspend_enter(suspend_state_t state) > +{ > + return cpu_suspend(SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM, sbi_system_suspend); > +} > + > +static const struct platform_suspend_ops sbi_system_suspend_ops = { > + .valid = suspend_valid_only_mem, > + .enter = sbi_system_suspend_enter, > +}; > + > +static int __init sbi_system_suspend_init(void) > +{ > + if (sbi_spec_version >= sbi_mk_version(2, 0) && > + sbi_probe_extension(SBI_EXT_SUSP) > 0) { > + pr_info("SBI SUSP extension detected\n"); > + if (IS_ENABLED(CONFIG_SUSPEND)) > + suspend_set_ops(&sbi_system_suspend_ops); > + } > + > + return 0; > +} > + > +arch_initcall(sbi_system_suspend_init); > +#endif /* CONFIG_RISCV_SBI */
On Tue, Dec 05, 2023 at 12:23:07PM -0600, Samuel Holland wrote: > Hi Andrew, > > On 2023-11-29 5:34 AM, Andrew Jones wrote: > > When the SUSP SBI extension is present it implies that the standard > > "suspend to RAM" type is available. Wire it up to the generic > > platform suspend support, also applying the already present support > > for non-retentive CPU suspend. When the kernel is built with > > CONFIG_SUSPEND, one can do 'echo mem > /sys/power/state' to suspend. > > Resumption will occur when a platform-specific wake-up event arrives. > > > > Signed-off-by: Andrew Jones <ajones@ventanamicro.com> > > Tested-by: Samuel Holland <samuel.holland@sifive.com> > > --- > > arch/riscv/Kconfig | 6 ++++- > > arch/riscv/include/asm/sbi.h | 9 ++++++++ > > arch/riscv/kernel/suspend.c | 44 ++++++++++++++++++++++++++++++++++++ > > 3 files changed, 58 insertions(+), 1 deletion(-) > > > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > > index 95a2a06acc6a..385fcad45c47 100644 > > --- a/arch/riscv/Kconfig > > +++ b/arch/riscv/Kconfig > > @@ -65,7 +65,7 @@ config RISCV > > select CLINT_TIMER if !MMU > > select CLONE_BACKWARDS > > select COMMON_CLK > > - select CPU_PM if CPU_IDLE || HIBERNATION > > + select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND > > select EDAC_SUPPORT > > select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE) > > select GENERIC_ARCH_TOPOLOGY > > @@ -918,9 +918,13 @@ config PORTABLE > > select MMU > > select OF > > > > + > > config ARCH_PROC_KCORE_TEXT > > def_bool y > > > > +config ARCH_SUSPEND_POSSIBLE > > + def_bool RISCV_SBI > > + > > This option was already added by commit c1f048a6bd7d ("riscv: Enable > ARCH_SUSPEND_POSSIBLE for s2idle"), so this hunk is a duplicate. Thanks, Samuel. I'll send a v3. drew
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 95a2a06acc6a..385fcad45c47 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -65,7 +65,7 @@ config RISCV select CLINT_TIMER if !MMU select CLONE_BACKWARDS select COMMON_CLK - select CPU_PM if CPU_IDLE || HIBERNATION + select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND select EDAC_SUPPORT select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE) select GENERIC_ARCH_TOPOLOGY @@ -918,9 +918,13 @@ config PORTABLE select MMU select OF + config ARCH_PROC_KCORE_TEXT def_bool y +config ARCH_SUSPEND_POSSIBLE + def_bool RISCV_SBI + menu "Power management options" source "kernel/power/Kconfig" diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 0892f4421bc4..f09356e187df 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -29,6 +29,7 @@ enum sbi_ext_id { SBI_EXT_RFENCE = 0x52464E43, SBI_EXT_HSM = 0x48534D, SBI_EXT_SRST = 0x53525354, + SBI_EXT_SUSP = 0x53555350, SBI_EXT_PMU = 0x504D55, SBI_EXT_DBCN = 0x4442434E, @@ -114,6 +115,14 @@ enum sbi_srst_reset_reason { SBI_SRST_RESET_REASON_SYS_FAILURE, }; +enum sbi_ext_susp_fid { + SBI_EXT_SUSP_SYSTEM_SUSPEND = 0, +}; + +enum sbi_ext_susp_sleep_type { + SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM = 0, +}; + enum sbi_ext_pmu_fid { SBI_EXT_PMU_NUM_COUNTERS = 0, SBI_EXT_PMU_COUNTER_GET_INFO, diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c index 3c89b8ec69c4..239509367e42 100644 --- a/arch/riscv/kernel/suspend.c +++ b/arch/riscv/kernel/suspend.c @@ -4,8 +4,12 @@ * Copyright (c) 2022 Ventana Micro Systems Inc. */ +#define pr_fmt(fmt) "suspend: " fmt + #include <linux/ftrace.h> +#include <linux/suspend.h> #include <asm/csr.h> +#include <asm/sbi.h> #include <asm/suspend.h> void suspend_save_csrs(struct suspend_context *context) @@ -85,3 +89,43 @@ int cpu_suspend(unsigned long arg, return rc; } + +#ifdef CONFIG_RISCV_SBI +static int sbi_system_suspend(unsigned long sleep_type, + unsigned long resume_addr, + unsigned long opaque) +{ + struct sbiret ret; + + ret = sbi_ecall(SBI_EXT_SUSP, SBI_EXT_SUSP_SYSTEM_SUSPEND, + sleep_type, resume_addr, opaque, 0, 0, 0); + if (ret.error) + return sbi_err_map_linux_errno(ret.error); + + return ret.value; +} + +static int sbi_system_suspend_enter(suspend_state_t state) +{ + return cpu_suspend(SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM, sbi_system_suspend); +} + +static const struct platform_suspend_ops sbi_system_suspend_ops = { + .valid = suspend_valid_only_mem, + .enter = sbi_system_suspend_enter, +}; + +static int __init sbi_system_suspend_init(void) +{ + if (sbi_spec_version >= sbi_mk_version(2, 0) && + sbi_probe_extension(SBI_EXT_SUSP) > 0) { + pr_info("SBI SUSP extension detected\n"); + if (IS_ENABLED(CONFIG_SUSPEND)) + suspend_set_ops(&sbi_system_suspend_ops); + } + + return 0; +} + +arch_initcall(sbi_system_suspend_init); +#endif /* CONFIG_RISCV_SBI */