Message ID | 20221028023829.4030984-2-chenhuacai@loongson.cn (mailing list archive) |
---|---|
State | Handled Elsewhere, archived |
Headers | show |
Series | [1/2] LoongArch: Add suspend (ACPI S3) support | expand |
Hi, Huacai, On 2022/10/28 上午10:38, Huacai Chen wrote: > Add hibernation (Suspend to Disk, aka ACPI S4) support for LoongArch. > > Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> > --- > arch/loongarch/Kconfig | 3 ++ > arch/loongarch/kernel/asm-offsets.c | 12 +++++ > arch/loongarch/kernel/reset.c | 2 + > arch/loongarch/kernel/setup.c | 5 ++ > arch/loongarch/power/Makefile | 1 + > arch/loongarch/power/hibernate.c | 58 ++++++++++++++++++++++++ > arch/loongarch/power/hibernate_asm.S | 68 ++++++++++++++++++++++++++++ > 7 files changed, 149 insertions(+) > create mode 100644 arch/loongarch/power/hibernate.c > create mode 100644 arch/loongarch/power/hibernate_asm.S > > diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig > index 0df102401d1d..1943f840e494 100644 > --- a/arch/loongarch/Kconfig > +++ b/arch/loongarch/Kconfig > @@ -521,6 +521,9 @@ menu "Power management options" > config ARCH_SUSPEND_POSSIBLE > def_bool y > > +config ARCH_HIBERNATION_POSSIBLE > + def_bool y > + > source "kernel/power/Kconfig" > source "drivers/acpi/Kconfig" > > diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c > index bdd88eda9513..4ef494577813 100644 > --- a/arch/loongarch/kernel/asm-offsets.c > +++ b/arch/loongarch/kernel/asm-offsets.c > @@ -257,3 +257,15 @@ void output_smpboot_defines(void) > BLANK(); > } > #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 > diff --git a/arch/loongarch/kernel/reset.c b/arch/loongarch/kernel/reset.c > index 8c82021eb2f4..cdf021ff6214 100644 > --- a/arch/loongarch/kernel/reset.c > +++ b/arch/loongarch/kernel/reset.c > @@ -15,6 +15,7 @@ > #include <acpi/reboot.h> > #include <asm/idle.h> > #include <asm/loongarch.h> > +#include <asm/loongson.h> > > void (*pm_power_off)(void); > EXPORT_SYMBOL(pm_power_off); > @@ -42,6 +43,7 @@ void machine_power_off(void) > preempt_disable(); > smp_send_stop(); > #endif > + enable_pci_wakeup(); > do_kernel_power_off(); > #ifdef CONFIG_EFI > efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); > diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c > index 96b6cb5db004..3c8bc250f4e2 100644 > --- a/arch/loongarch/kernel/setup.c > +++ b/arch/loongarch/kernel/setup.c > @@ -28,6 +28,7 @@ > #include <linux/sizes.h> > #include <linux/device.h> > #include <linux/dma-map-ops.h> > +#include <linux/suspend.h> > #include <linux/swiotlb.h> > > #include <asm/addrspace.h> > @@ -312,6 +313,10 @@ static void __init arch_mem_init(char **cmdline_p) > > 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(); > > early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn)); > diff --git a/arch/loongarch/power/Makefile b/arch/loongarch/power/Makefile > index 6740117decaa..58151d003e40 100644 > --- a/arch/loongarch/power/Makefile > +++ b/arch/loongarch/power/Makefile > @@ -1,3 +1,4 @@ > obj-y += platform.o > > obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o > +obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o > diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c > new file mode 100644 > index 000000000000..32dae9ef311a > --- /dev/null > +++ b/arch/loongarch/power/hibernate.c > @@ -0,0 +1,58 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include <asm/fpu.h> > +#include <asm/loongson.h> > +#include <asm/sections.h> > +#include <asm/tlbflush.h> > + > +static u64 saved_crmd; > +static u64 saved_prmd; > +static u64 saved_euen; > +static u64 saved_ecfg; > +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); > + > + 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); > + > + if (is_fpu_owner()) > + restore_fp(current); > +} > + > +int pfn_is_nosave(unsigned long pfn) > +{ I'm surprised that every arch has its own version of pfn_is_nosave(). We can improve it. But it's beyond these patches, just ignore here. > + 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(); > +} > diff --git a/arch/loongarch/power/hibernate_asm.S b/arch/loongarch/power/hibernate_asm.S > new file mode 100644 > index 000000000000..7894fbd56c85 > --- /dev/null > +++ b/arch/loongarch/power/hibernate_asm.S > @@ -0,0 +1,64 @@ > +/* 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 sp, t0, PT_R3 > + PTR_S fp, t0, PT_R22 > + PTR_S tp, t0, PT_R2 > + 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 Is needed save and restore PERCPU_BASE_KS, u0 or other KSave registers? Thanks, Jinyang > +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 sp, t0, PT_R3 > + PTR_L fp, t0, PT_R22 > + PTR_L tp, t0, PT_R2 > + 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)
Hi, Jinyang, On Fri, Oct 28, 2022 at 3:26 PM Jinyang He <hejinyang@loongson.cn> wrote: > > Hi, Huacai, > > > On 2022/10/28 上午10:38, Huacai Chen wrote: > > Add hibernation (Suspend to Disk, aka ACPI S4) support for LoongArch. > > > > Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> > > --- > > arch/loongarch/Kconfig | 3 ++ > > arch/loongarch/kernel/asm-offsets.c | 12 +++++ > > arch/loongarch/kernel/reset.c | 2 + > > arch/loongarch/kernel/setup.c | 5 ++ > > arch/loongarch/power/Makefile | 1 + > > arch/loongarch/power/hibernate.c | 58 ++++++++++++++++++++++++ > > arch/loongarch/power/hibernate_asm.S | 68 ++++++++++++++++++++++++++++ > > 7 files changed, 149 insertions(+) > > create mode 100644 arch/loongarch/power/hibernate.c > > create mode 100644 arch/loongarch/power/hibernate_asm.S > > > > diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig > > index 0df102401d1d..1943f840e494 100644 > > --- a/arch/loongarch/Kconfig > > +++ b/arch/loongarch/Kconfig > > @@ -521,6 +521,9 @@ menu "Power management options" > > config ARCH_SUSPEND_POSSIBLE > > def_bool y > > > > +config ARCH_HIBERNATION_POSSIBLE > > + def_bool y > > + > > source "kernel/power/Kconfig" > > source "drivers/acpi/Kconfig" > > > > diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c > > index bdd88eda9513..4ef494577813 100644 > > --- a/arch/loongarch/kernel/asm-offsets.c > > +++ b/arch/loongarch/kernel/asm-offsets.c > > @@ -257,3 +257,15 @@ void output_smpboot_defines(void) > > BLANK(); > > } > > #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 > > diff --git a/arch/loongarch/kernel/reset.c b/arch/loongarch/kernel/reset.c > > index 8c82021eb2f4..cdf021ff6214 100644 > > --- a/arch/loongarch/kernel/reset.c > > +++ b/arch/loongarch/kernel/reset.c > > @@ -15,6 +15,7 @@ > > #include <acpi/reboot.h> > > #include <asm/idle.h> > > #include <asm/loongarch.h> > > +#include <asm/loongson.h> > > > > void (*pm_power_off)(void); > > EXPORT_SYMBOL(pm_power_off); > > @@ -42,6 +43,7 @@ void machine_power_off(void) > > preempt_disable(); > > smp_send_stop(); > > #endif > > + enable_pci_wakeup(); > > do_kernel_power_off(); > > #ifdef CONFIG_EFI > > efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); > > diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c > > index 96b6cb5db004..3c8bc250f4e2 100644 > > --- a/arch/loongarch/kernel/setup.c > > +++ b/arch/loongarch/kernel/setup.c > > @@ -28,6 +28,7 @@ > > #include <linux/sizes.h> > > #include <linux/device.h> > > #include <linux/dma-map-ops.h> > > +#include <linux/suspend.h> > > #include <linux/swiotlb.h> > > > > #include <asm/addrspace.h> > > @@ -312,6 +313,10 @@ static void __init arch_mem_init(char **cmdline_p) > > > > 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(); > > > > early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn)); > > diff --git a/arch/loongarch/power/Makefile b/arch/loongarch/power/Makefile > > index 6740117decaa..58151d003e40 100644 > > --- a/arch/loongarch/power/Makefile > > +++ b/arch/loongarch/power/Makefile > > @@ -1,3 +1,4 @@ > > obj-y += platform.o > > > > obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o > > +obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o > > diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c > > new file mode 100644 > > index 000000000000..32dae9ef311a > > --- /dev/null > > +++ b/arch/loongarch/power/hibernate.c > > @@ -0,0 +1,58 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +#include <asm/fpu.h> > > +#include <asm/loongson.h> > > +#include <asm/sections.h> > > +#include <asm/tlbflush.h> > > + > > +static u64 saved_crmd; > > +static u64 saved_prmd; > > +static u64 saved_euen; > > +static u64 saved_ecfg; > > +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); > > + > > + 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); > > + > > + if (is_fpu_owner()) > > + restore_fp(current); > > +} > > + > > +int pfn_is_nosave(unsigned long pfn) > > +{ > I'm surprised that every arch has its own version of pfn_is_nosave(). > > We can improve it. But it's beyond these patches, just ignore here. > > > > + 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(); > > +} > > diff --git a/arch/loongarch/power/hibernate_asm.S b/arch/loongarch/power/hibernate_asm.S > > new file mode 100644 > > index 000000000000..7894fbd56c85 > > --- /dev/null > > +++ b/arch/loongarch/power/hibernate_asm.S > > @@ -0,0 +1,64 @@ > > +/* 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 sp, t0, PT_R3 > > + PTR_S fp, t0, PT_R22 > > + PTR_S tp, t0, PT_R2 > > + 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 > > Is needed save and restore PERCPU_BASE_KS, u0 or other KSave registers? Saving/restoring PERCPU_BASE_KS and u0 seems needed, but I don't know why it works well without them. :) Huacai > > > Thanks, > > Jinyang > > > > +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 sp, t0, PT_R3 > > + PTR_L fp, t0, PT_R22 > > + PTR_L tp, t0, PT_R2 > > + 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) >
Hi Huacai,
I love your patch! Yet something to improve:
[auto build test ERROR on pavel-leds/for-next]
[also build test ERROR on linus/master v6.1-rc2 next-20221028]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Huacai-Chen/LoongArch-Add-suspend-ACPI-S3-support/20221028-104234
base: git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git for-next
patch link: https://lore.kernel.org/r/20221028023829.4030984-2-chenhuacai%40loongson.cn
patch subject: [PATCH 2/2] LoongArch: Add hibernation (ACPI S4) support
config: loongarch-allnoconfig
compiler: loongarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/49ada2ab12c9a56d08865ddfc91413242369c1b8
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Huacai-Chen/LoongArch-Add-suspend-ACPI-S3-support/20221028-104234
git checkout 49ada2ab12c9a56d08865ddfc91413242369c1b8
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch SHELL=/bin/bash
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
loongarch64-linux-ld: arch/loongarch/kernel/reset.o: in function `machine_power_off':
>> reset.c:(.text+0x54): undefined reference to `enable_pci_wakeup'
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 0df102401d1d..1943f840e494 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -521,6 +521,9 @@ menu "Power management options" config ARCH_SUSPEND_POSSIBLE def_bool y +config ARCH_HIBERNATION_POSSIBLE + def_bool y + source "kernel/power/Kconfig" source "drivers/acpi/Kconfig" diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c index bdd88eda9513..4ef494577813 100644 --- a/arch/loongarch/kernel/asm-offsets.c +++ b/arch/loongarch/kernel/asm-offsets.c @@ -257,3 +257,15 @@ void output_smpboot_defines(void) BLANK(); } #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 diff --git a/arch/loongarch/kernel/reset.c b/arch/loongarch/kernel/reset.c index 8c82021eb2f4..cdf021ff6214 100644 --- a/arch/loongarch/kernel/reset.c +++ b/arch/loongarch/kernel/reset.c @@ -15,6 +15,7 @@ #include <acpi/reboot.h> #include <asm/idle.h> #include <asm/loongarch.h> +#include <asm/loongson.h> void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); @@ -42,6 +43,7 @@ void machine_power_off(void) preempt_disable(); smp_send_stop(); #endif + enable_pci_wakeup(); do_kernel_power_off(); #ifdef CONFIG_EFI efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c index 96b6cb5db004..3c8bc250f4e2 100644 --- a/arch/loongarch/kernel/setup.c +++ b/arch/loongarch/kernel/setup.c @@ -28,6 +28,7 @@ #include <linux/sizes.h> #include <linux/device.h> #include <linux/dma-map-ops.h> +#include <linux/suspend.h> #include <linux/swiotlb.h> #include <asm/addrspace.h> @@ -312,6 +313,10 @@ static void __init arch_mem_init(char **cmdline_p) 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(); early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn)); diff --git a/arch/loongarch/power/Makefile b/arch/loongarch/power/Makefile index 6740117decaa..58151d003e40 100644 --- a/arch/loongarch/power/Makefile +++ b/arch/loongarch/power/Makefile @@ -1,3 +1,4 @@ obj-y += platform.o obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o +obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c new file mode 100644 index 000000000000..32dae9ef311a --- /dev/null +++ b/arch/loongarch/power/hibernate.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <asm/fpu.h> +#include <asm/loongson.h> +#include <asm/sections.h> +#include <asm/tlbflush.h> + +static u64 saved_crmd; +static u64 saved_prmd; +static u64 saved_euen; +static u64 saved_ecfg; +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); + + 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); + + 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(); +} diff --git a/arch/loongarch/power/hibernate_asm.S b/arch/loongarch/power/hibernate_asm.S new file mode 100644 index 000000000000..7894fbd56c85 --- /dev/null +++ b/arch/loongarch/power/hibernate_asm.S @@ -0,0 +1,64 @@ +/* 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 sp, t0, PT_R3 + PTR_S fp, t0, PT_R22 + PTR_S tp, t0, PT_R2 + 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 sp, t0, PT_R3 + PTR_L fp, t0, PT_R22 + PTR_L tp, t0, PT_R2 + 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)
Add hibernation (Suspend to Disk, aka ACPI S4) support for LoongArch. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> --- arch/loongarch/Kconfig | 3 ++ arch/loongarch/kernel/asm-offsets.c | 12 +++++ arch/loongarch/kernel/reset.c | 2 + arch/loongarch/kernel/setup.c | 5 ++ arch/loongarch/power/Makefile | 1 + arch/loongarch/power/hibernate.c | 58 ++++++++++++++++++++++++ arch/loongarch/power/hibernate_asm.S | 68 ++++++++++++++++++++++++++++ 7 files changed, 149 insertions(+) create mode 100644 arch/loongarch/power/hibernate.c create mode 100644 arch/loongarch/power/hibernate_asm.S