]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xtensa: add hibernation support
authorMax Filippov <jcmvbkbc@gmail.com>
Wed, 20 Apr 2022 13:07:20 +0000 (06:07 -0700)
committerMax Filippov <jcmvbkbc@gmail.com>
Mon, 2 May 2022 02:51:24 +0000 (19:51 -0700)
Define ARCH_HIBERNATION_POSSIBLE in Kconfig and implement hibernation
callbacks.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
arch/xtensa/Kconfig
arch/xtensa/kernel/Makefile
arch/xtensa/kernel/asm-offsets.c
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/hibernate.c [new file with mode: 0644]

index 036854e7335183bace83564da6a8c92be4d37317..3088a432740f9dcaca6060f271f75c34aca3d8c7 100644 (file)
@@ -787,6 +787,9 @@ endmenu
 
 menu "Power management options"
 
+config ARCH_HIBERNATION_POSSIBLE
+       def_bool y
+
 source "kernel/power/Kconfig"
 
 endmenu
index 5fd6cd15e0fb191c212b9027f4bd2d9cc16ed371..897c1c7410589826be38626288be77afa3dc41e9 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_S32C1I_SELFTEST) += s32c1i_selftest.o
 obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+obj-$(CONFIG_HIBERNATION) += hibernate.o
 
 # In the Xtensa architecture, assembly generates literals which must always
 # precede the L32R instruction with a relative offset less than 256 kB.
index e3b9cf4c22899ea31f93682298574a74912ec5f7..9a1db6ffcbf4937b165124e177ef0623230d4cf0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ptrace.h>
 #include <linux/mm.h>
 #include <linux/kbuild.h>
+#include <linux/suspend.h>
 
 #include <asm/ptrace.h>
 #include <asm/traps.h>
@@ -149,5 +150,12 @@ int main(void)
               offsetof(struct exc_table, fast_kernel_handler));
        DEFINE(EXC_TABLE_DEFAULT, offsetof(struct exc_table, default_handler));
 
+#ifdef CONFIG_HIBERNATION
+       DEFINE(PBE_ADDRESS, offsetof(struct pbe, address));
+       DEFINE(PBE_ORIG_ADDRESS, offsetof(struct pbe, orig_address));
+       DEFINE(PBE_NEXT, offsetof(struct pbe, next));
+       DEFINE(PBE_SIZE, sizeof(struct pbe));
+#endif
+
        return 0;
 }
index 3255d4f6184415300e441780c4da4ff18a376e20..d703ed31254abf3051b68583821861a062a918d3 100644 (file)
@@ -2155,3 +2155,95 @@ ENTRY(ret_from_kernel_thread)
        j               common_exception_return
 
 ENDPROC(ret_from_kernel_thread)
+
+#ifdef CONFIG_HIBERNATION
+
+       .bss
+       .align  4
+.Lsaved_regs:
+#if defined(__XTENSA_WINDOWED_ABI__)
+       .fill   2, 4
+#elif defined(__XTENSA_CALL0_ABI__)
+       .fill   6, 4
+#else
+#error Unsupported Xtensa ABI
+#endif
+       .align  XCHAL_NCP_SA_ALIGN
+.Lsaved_user_regs:
+       .fill   XTREGS_USER_SIZE, 1
+
+       .previous
+
+ENTRY(swsusp_arch_suspend)
+
+       abi_entry_default
+
+       movi            a2, .Lsaved_regs
+       movi            a3, .Lsaved_user_regs
+       s32i            a0, a2, 0
+       s32i            a1, a2, 4
+       save_xtregs_user a3 a4 a5 a6 a7 a8 0
+#if defined(__XTENSA_WINDOWED_ABI__)
+       spill_registers_kernel
+#elif defined(__XTENSA_CALL0_ABI__)
+       s32i            a12, a2, 8
+       s32i            a13, a2, 12
+       s32i            a14, a2, 16
+       s32i            a15, a2, 20
+#else
+#error Unsupported Xtensa ABI
+#endif
+       abi_call        swsusp_save
+       mov             a2, abi_rv
+       abi_ret_default
+
+ENDPROC(swsusp_arch_suspend)
+
+ENTRY(swsusp_arch_resume)
+
+       abi_entry_default
+
+#if defined(__XTENSA_WINDOWED_ABI__)
+       spill_registers_kernel
+#endif
+
+       movi            a2, restore_pblist
+       l32i            a2, a2, 0
+
+.Lcopy_pbe:
+       l32i            a3, a2, PBE_ADDRESS
+       l32i            a4, a2, PBE_ORIG_ADDRESS
+
+       __loopi         a3, a9, PAGE_SIZE, 16
+       l32i            a5, a3, 0
+       l32i            a6, a3, 4
+       l32i            a7, a3, 8
+       l32i            a8, a3, 12
+       addi            a3, a3, 16
+       s32i            a5, a4, 0
+       s32i            a6, a4, 4
+       s32i            a7, a4, 8
+       s32i            a8, a4, 12
+       addi            a4, a4, 16
+       __endl          a3, a9
+
+       l32i            a2, a2, PBE_NEXT
+       bnez            a2, .Lcopy_pbe
+
+       movi            a2, .Lsaved_regs
+       movi            a3, .Lsaved_user_regs
+       l32i            a0, a2, 0
+       l32i            a1, a2, 4
+       load_xtregs_user a3 a4 a5 a6 a7 a8 0
+#if defined(__XTENSA_CALL0_ABI__)
+       l32i            a12, a2, 8
+       l32i            a13, a2, 12
+       l32i            a14, a2, 16
+       l32i            a15, a2, 20
+#endif
+       movi            a2, 0
+       abi_ret_default
+
+ENDPROC(swsusp_arch_resume)
+
+#endif
diff --git a/arch/xtensa/kernel/hibernate.c b/arch/xtensa/kernel/hibernate.c
new file mode 100644 (file)
index 0000000..0698432
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <asm/coprocessor.h>
+
+int pfn_is_nosave(unsigned long pfn)
+{
+       unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
+       unsigned long nosave_end_pfn = PFN_UP(__pa(&__nosave_end));
+
+       return  (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
+
+void notrace save_processor_state(void)
+{
+       WARN_ON(num_online_cpus() != 1);
+#if XTENSA_HAVE_COPROCESSORS
+       local_coprocessors_flush_release_all();
+#endif
+}
+
+void notrace restore_processor_state(void)
+{
+}