Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+154
+3
arch/loongarch/Kconfig
··· 521 521 config ARCH_SUSPEND_POSSIBLE 522 522 def_bool y 523 523 524 + config ARCH_HIBERNATION_POSSIBLE 525 + def_bool y 526 + 524 527 source "kernel/power/Kconfig" 525 528 source "drivers/acpi/Kconfig" 526 529
+12
arch/loongarch/kernel/asm-offsets.c
··· 257 257 BLANK(); 258 258 } 259 259 #endif 260 + 261 + #ifdef CONFIG_HIBERNATION 262 + void output_pbe_defines(void) 263 + { 264 + COMMENT(" Linux struct pbe offsets. "); 265 + OFFSET(PBE_ADDRESS, pbe, address); 266 + OFFSET(PBE_ORIG_ADDRESS, pbe, orig_address); 267 + OFFSET(PBE_NEXT, pbe, next); 268 + DEFINE(PBE_SIZE, sizeof(struct pbe)); 269 + BLANK(); 270 + } 271 + #endif
+5
arch/loongarch/kernel/reset.c
··· 15 15 #include <acpi/reboot.h> 16 16 #include <asm/idle.h> 17 17 #include <asm/loongarch.h> 18 + #include <asm/loongson.h> 18 19 19 20 void (*pm_power_off)(void); 20 21 EXPORT_SYMBOL(pm_power_off); ··· 42 41 #ifdef CONFIG_SMP 43 42 preempt_disable(); 44 43 smp_send_stop(); 44 + #endif 45 + #ifdef CONFIG_PM 46 + if (!acpi_disabled) 47 + enable_pci_wakeup(); 45 48 #endif 46 49 do_kernel_power_off(); 47 50 #ifdef CONFIG_EFI
+5
arch/loongarch/kernel/setup.c
··· 31 31 #include <linux/libfdt.h> 32 32 #include <linux/of_fdt.h> 33 33 #include <linux/of_address.h> 34 + #include <linux/suspend.h> 34 35 #include <linux/swiotlb.h> 35 36 36 37 #include <asm/addrspace.h> ··· 370 369 swiotlb_init(true, SWIOTLB_VERBOSE); 371 370 372 371 dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); 372 + 373 + /* Reserve for hibernation. */ 374 + register_nosave_region(PFN_DOWN(__pa_symbol(&__nosave_begin)), 375 + PFN_UP(__pa_symbol(&__nosave_end))); 373 376 374 377 memblock_dump_all(); 375 378
+1
arch/loongarch/power/Makefile
··· 1 1 obj-y += platform.o 2 2 3 3 obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o 4 + obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o
+62
arch/loongarch/power/hibernate.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <asm/fpu.h> 3 + #include <asm/loongson.h> 4 + #include <asm/sections.h> 5 + #include <asm/tlbflush.h> 6 + #include <linux/suspend.h> 7 + 8 + static u32 saved_crmd; 9 + static u32 saved_prmd; 10 + static u32 saved_euen; 11 + static u32 saved_ecfg; 12 + static u64 saved_pcpu_base; 13 + struct pt_regs saved_regs; 14 + 15 + void save_processor_state(void) 16 + { 17 + saved_crmd = csr_read32(LOONGARCH_CSR_CRMD); 18 + saved_prmd = csr_read32(LOONGARCH_CSR_PRMD); 19 + saved_euen = csr_read32(LOONGARCH_CSR_EUEN); 20 + saved_ecfg = csr_read32(LOONGARCH_CSR_ECFG); 21 + saved_pcpu_base = csr_read64(PERCPU_BASE_KS); 22 + 23 + if (is_fpu_owner()) 24 + save_fp(current); 25 + } 26 + 27 + void restore_processor_state(void) 28 + { 29 + csr_write32(saved_crmd, LOONGARCH_CSR_CRMD); 30 + csr_write32(saved_prmd, LOONGARCH_CSR_PRMD); 31 + csr_write32(saved_euen, LOONGARCH_CSR_EUEN); 32 + csr_write32(saved_ecfg, LOONGARCH_CSR_ECFG); 33 + csr_write64(saved_pcpu_base, PERCPU_BASE_KS); 34 + 35 + if (is_fpu_owner()) 36 + restore_fp(current); 37 + } 38 + 39 + int pfn_is_nosave(unsigned long pfn) 40 + { 41 + unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); 42 + unsigned long nosave_end_pfn = PFN_UP(__pa(&__nosave_end)); 43 + 44 + return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); 45 + } 46 + 47 + extern int swsusp_asm_suspend(void); 48 + 49 + int swsusp_arch_suspend(void) 50 + { 51 + enable_pci_wakeup(); 52 + return swsusp_asm_suspend(); 53 + } 54 + 55 + extern int swsusp_asm_resume(void); 56 + 57 + int swsusp_arch_resume(void) 58 + { 59 + /* Avoid TLB mismatch during and after kernel resume */ 60 + local_flush_tlb_all(); 61 + return swsusp_asm_resume(); 62 + }
+66
arch/loongarch/power/hibernate_asm.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Hibernation support specific for LoongArch 4 + * 5 + * Author: Huacai Chen <chenhuacai@loongson.cn> 6 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 7 + */ 8 + #include <linux/linkage.h> 9 + #include <asm/asm.h> 10 + #include <asm/asm-offsets.h> 11 + #include <asm/regdef.h> 12 + 13 + .text 14 + SYM_FUNC_START(swsusp_asm_suspend) 15 + la.pcrel t0, saved_regs 16 + PTR_S ra, t0, PT_R1 17 + PTR_S tp, t0, PT_R2 18 + PTR_S sp, t0, PT_R3 19 + PTR_S u0, t0, PT_R21 20 + PTR_S fp, t0, PT_R22 21 + PTR_S s0, t0, PT_R23 22 + PTR_S s1, t0, PT_R24 23 + PTR_S s2, t0, PT_R25 24 + PTR_S s3, t0, PT_R26 25 + PTR_S s4, t0, PT_R27 26 + PTR_S s5, t0, PT_R28 27 + PTR_S s6, t0, PT_R29 28 + PTR_S s7, t0, PT_R30 29 + PTR_S s8, t0, PT_R31 30 + b swsusp_save 31 + SYM_FUNC_END(swsusp_asm_suspend) 32 + 33 + SYM_FUNC_START(swsusp_asm_resume) 34 + la.pcrel t0, restore_pblist 35 + PTR_L t0, t0, 0 36 + 0: 37 + PTR_L t1, t0, PBE_ADDRESS /* source */ 38 + PTR_L t2, t0, PBE_ORIG_ADDRESS /* destination */ 39 + PTR_LI t3, _PAGE_SIZE 40 + PTR_ADD t3, t3, t1 41 + 1: 42 + REG_L t8, t1, 0 43 + REG_S t8, t2, 0 44 + PTR_ADDI t1, t1, SZREG 45 + PTR_ADDI t2, t2, SZREG 46 + bne t1, t3, 1b 47 + PTR_L t0, t0, PBE_NEXT 48 + bnez t0, 0b 49 + la.pcrel t0, saved_regs 50 + PTR_L ra, t0, PT_R1 51 + PTR_L tp, t0, PT_R2 52 + PTR_L sp, t0, PT_R3 53 + PTR_L u0, t0, PT_R21 54 + PTR_L fp, t0, PT_R22 55 + PTR_L s0, t0, PT_R23 56 + PTR_L s1, t0, PT_R24 57 + PTR_L s2, t0, PT_R25 58 + PTR_L s3, t0, PT_R26 59 + PTR_L s4, t0, PT_R27 60 + PTR_L s5, t0, PT_R28 61 + PTR_L s6, t0, PT_R29 62 + PTR_L s7, t0, PT_R30 63 + PTR_L s8, t0, PT_R31 64 + PTR_LI a0, 0x0 65 + jirl zero, ra, 0 66 + SYM_FUNC_END(swsusp_asm_resume)