Skip to content

Commit 7db54bf

Browse files
committed
LoongArch: Add hibernation (ACPI S4) support
Add hibernation (Suspend to Disk, aka ACPI S4) support for LoongArch. Signed-off-by: Huacai Chen <[email protected]>
1 parent 366bb35 commit 7db54bf

File tree

7 files changed

+154
-0
lines changed

7 files changed

+154
-0
lines changed

arch/loongarch/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,9 @@ menu "Power management options"
521521
config ARCH_SUSPEND_POSSIBLE
522522
def_bool y
523523

524+
config ARCH_HIBERNATION_POSSIBLE
525+
def_bool y
526+
524527
source "kernel/power/Kconfig"
525528
source "drivers/acpi/Kconfig"
526529

arch/loongarch/kernel/asm-offsets.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,15 @@ void output_smpboot_defines(void)
257257
BLANK();
258258
}
259259
#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

arch/loongarch/kernel/reset.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <acpi/reboot.h>
1616
#include <asm/idle.h>
1717
#include <asm/loongarch.h>
18+
#include <asm/loongson.h>
1819

1920
void (*pm_power_off)(void);
2021
EXPORT_SYMBOL(pm_power_off);
@@ -41,6 +42,10 @@ void machine_power_off(void)
4142
#ifdef CONFIG_SMP
4243
preempt_disable();
4344
smp_send_stop();
45+
#endif
46+
#ifdef CONFIG_PM
47+
if (!acpi_disabled)
48+
enable_pci_wakeup();
4449
#endif
4550
do_kernel_power_off();
4651
#ifdef CONFIG_EFI

arch/loongarch/kernel/setup.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/libfdt.h>
3232
#include <linux/of_fdt.h>
3333
#include <linux/of_address.h>
34+
#include <linux/suspend.h>
3435
#include <linux/swiotlb.h>
3536

3637
#include <asm/addrspace.h>
@@ -370,6 +371,10 @@ static void __init arch_mem_init(char **cmdline_p)
370371

371372
dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
372373

374+
/* Reserve for hibernation. */
375+
register_nosave_region(PFN_DOWN(__pa_symbol(&__nosave_begin)),
376+
PFN_UP(__pa_symbol(&__nosave_end)));
377+
373378
memblock_dump_all();
374379

375380
early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));

arch/loongarch/power/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
obj-y += platform.o
22

33
obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o
4+
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o

arch/loongarch/power/hibernate.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
}

arch/loongarch/power/hibernate_asm.S

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Hibernation support specific for LoongArch
4+
*
5+
* Author: Huacai Chen <[email protected]>
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)

0 commit comments

Comments
 (0)