summaryrefslogtreecommitdiff
path: root/arch/loongarch/power/hibernate.c
diff options
context:
space:
mode:
authorHuacai Chen <chenhuacai@loongson.cn>2022-12-10 22:40:15 +0800
committerHuacai Chen <chenhuacai@loongson.cn>2022-12-14 08:41:53 +0800
commit7db54bfe44a662c8f2c10277bccfa02c2f4c719c (patch)
tree0718e06127149f29a103fee7fcccf6a458067f61 /arch/loongarch/power/hibernate.c
parent366bb35a8e48198cefcd3484ac6b2374d1347873 (diff)
downloadlinux-7db54bfe44a662c8f2c10277bccfa02c2f4c719c.tar.gz
linux-7db54bfe44a662c8f2c10277bccfa02c2f4c719c.tar.bz2
linux-7db54bfe44a662c8f2c10277bccfa02c2f4c719c.zip
LoongArch: Add hibernation (ACPI S4) support
Add hibernation (Suspend to Disk, aka ACPI S4) support for LoongArch. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Diffstat (limited to 'arch/loongarch/power/hibernate.c')
-rw-r--r--arch/loongarch/power/hibernate.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c
new file mode 100644
index 000000000000..1e0590542f98
--- /dev/null
+++ b/arch/loongarch/power/hibernate.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <asm/fpu.h>
+#include <asm/loongson.h>
+#include <asm/sections.h>
+#include <asm/tlbflush.h>
+#include <linux/suspend.h>
+
+static u32 saved_crmd;
+static u32 saved_prmd;
+static u32 saved_euen;
+static u32 saved_ecfg;
+static u64 saved_pcpu_base;
+struct pt_regs saved_regs;
+
+void save_processor_state(void)
+{
+ saved_crmd = csr_read32(LOONGARCH_CSR_CRMD);
+ saved_prmd = csr_read32(LOONGARCH_CSR_PRMD);
+ saved_euen = csr_read32(LOONGARCH_CSR_EUEN);
+ saved_ecfg = csr_read32(LOONGARCH_CSR_ECFG);
+ saved_pcpu_base = csr_read64(PERCPU_BASE_KS);
+
+ if (is_fpu_owner())
+ save_fp(current);
+}
+
+void restore_processor_state(void)
+{
+ csr_write32(saved_crmd, LOONGARCH_CSR_CRMD);
+ csr_write32(saved_prmd, LOONGARCH_CSR_PRMD);
+ csr_write32(saved_euen, LOONGARCH_CSR_EUEN);
+ csr_write32(saved_ecfg, LOONGARCH_CSR_ECFG);
+ csr_write64(saved_pcpu_base, PERCPU_BASE_KS);
+
+ if (is_fpu_owner())
+ restore_fp(current);
+}
+
+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);
+}
+
+extern int swsusp_asm_suspend(void);
+
+int swsusp_arch_suspend(void)
+{
+ enable_pci_wakeup();
+ return swsusp_asm_suspend();
+}
+
+extern int swsusp_asm_resume(void);
+
+int swsusp_arch_resume(void)
+{
+ /* Avoid TLB mismatch during and after kernel resume */
+ local_flush_tlb_all();
+ return swsusp_asm_resume();
+}