mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
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>
This commit is contained in:
parent
366bb35a8e
commit
7db54bfe44
@ -521,6 +521,9 @@ menu "Power management options"
|
|||||||
config ARCH_SUSPEND_POSSIBLE
|
config ARCH_SUSPEND_POSSIBLE
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
|
config ARCH_HIBERNATION_POSSIBLE
|
||||||
|
def_bool y
|
||||||
|
|
||||||
source "kernel/power/Kconfig"
|
source "kernel/power/Kconfig"
|
||||||
source "drivers/acpi/Kconfig"
|
source "drivers/acpi/Kconfig"
|
||||||
|
|
||||||
|
@ -257,3 +257,15 @@ void output_smpboot_defines(void)
|
|||||||
BLANK();
|
BLANK();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_HIBERNATION
|
||||||
|
void output_pbe_defines(void)
|
||||||
|
{
|
||||||
|
COMMENT(" Linux struct pbe offsets. ");
|
||||||
|
OFFSET(PBE_ADDRESS, pbe, address);
|
||||||
|
OFFSET(PBE_ORIG_ADDRESS, pbe, orig_address);
|
||||||
|
OFFSET(PBE_NEXT, pbe, next);
|
||||||
|
DEFINE(PBE_SIZE, sizeof(struct pbe));
|
||||||
|
BLANK();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <acpi/reboot.h>
|
#include <acpi/reboot.h>
|
||||||
#include <asm/idle.h>
|
#include <asm/idle.h>
|
||||||
#include <asm/loongarch.h>
|
#include <asm/loongarch.h>
|
||||||
|
#include <asm/loongson.h>
|
||||||
|
|
||||||
void (*pm_power_off)(void);
|
void (*pm_power_off)(void);
|
||||||
EXPORT_SYMBOL(pm_power_off);
|
EXPORT_SYMBOL(pm_power_off);
|
||||||
@ -41,6 +42,10 @@ void machine_power_off(void)
|
|||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
smp_send_stop();
|
smp_send_stop();
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
if (!acpi_disabled)
|
||||||
|
enable_pci_wakeup();
|
||||||
#endif
|
#endif
|
||||||
do_kernel_power_off();
|
do_kernel_power_off();
|
||||||
#ifdef CONFIG_EFI
|
#ifdef CONFIG_EFI
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <linux/libfdt.h>
|
#include <linux/libfdt.h>
|
||||||
#include <linux/of_fdt.h>
|
#include <linux/of_fdt.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
#include <linux/swiotlb.h>
|
#include <linux/swiotlb.h>
|
||||||
|
|
||||||
#include <asm/addrspace.h>
|
#include <asm/addrspace.h>
|
||||||
@ -370,6 +371,10 @@ static void __init arch_mem_init(char **cmdline_p)
|
|||||||
|
|
||||||
dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
|
dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
|
||||||
|
|
||||||
|
/* Reserve for hibernation. */
|
||||||
|
register_nosave_region(PFN_DOWN(__pa_symbol(&__nosave_begin)),
|
||||||
|
PFN_UP(__pa_symbol(&__nosave_end)));
|
||||||
|
|
||||||
memblock_dump_all();
|
memblock_dump_all();
|
||||||
|
|
||||||
early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
|
early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
obj-y += platform.o
|
obj-y += platform.o
|
||||||
|
|
||||||
obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o
|
obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o
|
||||||
|
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o
|
||||||
|
62
arch/loongarch/power/hibernate.c
Normal file
62
arch/loongarch/power/hibernate.c
Normal file
@ -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();
|
||||||
|
}
|
66
arch/loongarch/power/hibernate_asm.S
Normal file
66
arch/loongarch/power/hibernate_asm.S
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Hibernation support specific for LoongArch
|
||||||
|
*
|
||||||
|
* Author: Huacai Chen <chenhuacai@loongson.cn>
|
||||||
|
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited
|
||||||
|
*/
|
||||||
|
#include <linux/linkage.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
|
#include <asm/asm-offsets.h>
|
||||||
|
#include <asm/regdef.h>
|
||||||
|
|
||||||
|
.text
|
||||||
|
SYM_FUNC_START(swsusp_asm_suspend)
|
||||||
|
la.pcrel t0, saved_regs
|
||||||
|
PTR_S ra, t0, PT_R1
|
||||||
|
PTR_S tp, t0, PT_R2
|
||||||
|
PTR_S sp, t0, PT_R3
|
||||||
|
PTR_S u0, t0, PT_R21
|
||||||
|
PTR_S fp, t0, PT_R22
|
||||||
|
PTR_S s0, t0, PT_R23
|
||||||
|
PTR_S s1, t0, PT_R24
|
||||||
|
PTR_S s2, t0, PT_R25
|
||||||
|
PTR_S s3, t0, PT_R26
|
||||||
|
PTR_S s4, t0, PT_R27
|
||||||
|
PTR_S s5, t0, PT_R28
|
||||||
|
PTR_S s6, t0, PT_R29
|
||||||
|
PTR_S s7, t0, PT_R30
|
||||||
|
PTR_S s8, t0, PT_R31
|
||||||
|
b swsusp_save
|
||||||
|
SYM_FUNC_END(swsusp_asm_suspend)
|
||||||
|
|
||||||
|
SYM_FUNC_START(swsusp_asm_resume)
|
||||||
|
la.pcrel t0, restore_pblist
|
||||||
|
PTR_L t0, t0, 0
|
||||||
|
0:
|
||||||
|
PTR_L t1, t0, PBE_ADDRESS /* source */
|
||||||
|
PTR_L t2, t0, PBE_ORIG_ADDRESS /* destination */
|
||||||
|
PTR_LI t3, _PAGE_SIZE
|
||||||
|
PTR_ADD t3, t3, t1
|
||||||
|
1:
|
||||||
|
REG_L t8, t1, 0
|
||||||
|
REG_S t8, t2, 0
|
||||||
|
PTR_ADDI t1, t1, SZREG
|
||||||
|
PTR_ADDI t2, t2, SZREG
|
||||||
|
bne t1, t3, 1b
|
||||||
|
PTR_L t0, t0, PBE_NEXT
|
||||||
|
bnez t0, 0b
|
||||||
|
la.pcrel t0, saved_regs
|
||||||
|
PTR_L ra, t0, PT_R1
|
||||||
|
PTR_L tp, t0, PT_R2
|
||||||
|
PTR_L sp, t0, PT_R3
|
||||||
|
PTR_L u0, t0, PT_R21
|
||||||
|
PTR_L fp, t0, PT_R22
|
||||||
|
PTR_L s0, t0, PT_R23
|
||||||
|
PTR_L s1, t0, PT_R24
|
||||||
|
PTR_L s2, t0, PT_R25
|
||||||
|
PTR_L s3, t0, PT_R26
|
||||||
|
PTR_L s4, t0, PT_R27
|
||||||
|
PTR_L s5, t0, PT_R28
|
||||||
|
PTR_L s6, t0, PT_R29
|
||||||
|
PTR_L s7, t0, PT_R30
|
||||||
|
PTR_L s8, t0, PT_R31
|
||||||
|
PTR_LI a0, 0x0
|
||||||
|
jirl zero, ra, 0
|
||||||
|
SYM_FUNC_END(swsusp_asm_resume)
|
Loading…
Reference in New Issue
Block a user