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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'riscv-for-linus-6.4-mw2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux

Pull more RISC-V updates from Palmer Dabbelt:

- Support for hibernation

- The .rela.dyn section has been moved to the init area

- A fix for the SBI probing to allow for implementation-defined
behavior

- Various other fixes and cleanups throughout the tree

* tag 'riscv-for-linus-6.4-mw2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
RISC-V: include cpufeature.h in cpufeature.c
riscv: Move .rela.dyn to the init sections
dt-bindings: riscv: explicitly mention assumption of Zicsr & Zifencei support
riscv: compat_syscall_table: Fixup compile warning
RISC-V: fixup in-flight collision with ARCH_WANT_OPTIMIZE_VMEMMAP rename
RISC-V: fix sifive and thead section mismatches in errata
RISC-V: Align SBI probe implementation with spec
riscv: mm: remove redundant parameter of create_fdt_early_page_table
riscv: Adjust dependencies of HAVE_DYNAMIC_FTRACE selection
RISC-V: Add arch functions to support hibernation/suspend-to-disk
RISC-V: mm: Enable huge page support to kernel_page_present() function
RISC-V: Factor out common code of __cpu_resume_enter()
RISC-V: Change suspend_save_csrs and suspend_restore_csrs to public function

+682 -68
+6
Documentation/devicetree/bindings/riscv/cpus.yaml
··· 86 86 User-Level ISA document, available from 87 87 https://riscv.org/specifications/ 88 88 89 + Due to revisions of the ISA specification, some deviations 90 + have arisen over time. 91 + Notably, riscv,isa was defined prior to the creation of the 92 + Zicsr and Zifencei extensions and thus "i" implies 93 + "zicsr_zifencei". 94 + 89 95 While the isa strings in ISA specification are case 90 96 insensitive, letters in the riscv,isa string must be all 91 97 lowercase to simplify parsing.
+20 -3
arch/riscv/Kconfig
··· 47 47 select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU 48 48 select ARCH_WANT_FRAME_POINTERS 49 49 select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT 50 - select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP 51 50 select ARCH_WANT_HUGE_PMD_SHARE if 64BIT 52 51 select ARCH_WANT_LD_ORPHAN_WARN if !XIP_KERNEL 52 + select ARCH_WANT_OPTIMIZE_VMEMMAP 53 53 select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE 54 54 select BINFMT_FLAT_NO_DATA_START_OFFSET if !MMU 55 55 select BUILDTIME_TABLE_SORT if MMU 56 56 select CLINT_TIMER if !MMU 57 57 select CLONE_BACKWARDS 58 58 select COMMON_CLK 59 - select CPU_PM if CPU_IDLE 59 + select CPU_PM if CPU_IDLE || HIBERNATION 60 60 select EDAC_SUPPORT 61 61 select GENERIC_ARCH_TOPOLOGY 62 62 select GENERIC_ATOMIC64 if !64BIT ··· 142 142 select TRACE_IRQFLAGS_SUPPORT 143 143 select UACCESS_MEMCPY if !MMU 144 144 select ZONE_DMA32 if 64BIT 145 - select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && $(cc-option,-fpatchable-function-entry=8) 145 + select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) 146 146 select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE 147 147 select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL 148 148 select HAVE_FUNCTION_GRAPH_TRACER 149 149 select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION 150 + 151 + config CLANG_SUPPORTS_DYNAMIC_FTRACE 152 + def_bool CC_IS_CLANG 153 + # https://github.com/llvm/llvm-project/commit/6ab8927931851bb42b2c93a00801dc499d7d9b1e 154 + depends on CLANG_VERSION >= 130000 155 + # https://github.com/ClangBuiltLinux/linux/issues/1817 156 + depends on AS_IS_GNU || (AS_IS_LLVM && (LD_IS_LLD || LD_VERSION >= 23600)) 157 + 158 + config GCC_SUPPORTS_DYNAMIC_FTRACE 159 + def_bool CC_IS_GCC 160 + depends on $(cc-option,-fpatchable-function-entry=8) 150 161 151 162 config ARCH_MMAP_RND_BITS_MIN 152 163 default 18 if 64BIT ··· 798 787 menu "Power management options" 799 788 800 789 source "kernel/power/Kconfig" 790 + 791 + config ARCH_HIBERNATION_POSSIBLE 792 + def_bool y 793 + 794 + config ARCH_HIBERNATION_HEADER 795 + def_bool HIBERNATION 801 796 802 797 endmenu # "Power management options" 803 798
+3 -5
arch/riscv/errata/sifive/errata.c
··· 82 82 pr_warn("----------------------------------------------------------------\n"); 83 83 } 84 84 85 - void __init_or_module sifive_errata_patch_func(struct alt_entry *begin, 86 - struct alt_entry *end, 87 - unsigned long archid, 88 - unsigned long impid, 89 - unsigned int stage) 85 + void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, 86 + unsigned long archid, unsigned long impid, 87 + unsigned int stage) 90 88 { 91 89 struct alt_entry *alt; 92 90 u32 cpu_req_errata;
+3 -3
arch/riscv/errata/thead/errata.c
··· 83 83 return cpu_req_errata; 84 84 } 85 85 86 - void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, 87 - unsigned long archid, unsigned long impid, 88 - unsigned int stage) 86 + void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, 87 + unsigned long archid, unsigned long impid, 88 + unsigned int stage) 89 89 { 90 90 struct alt_entry *alt; 91 91 u32 cpu_req_errata = thead_errata_probe(stage, archid, impid);
+82
arch/riscv/include/asm/assembler.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2023 StarFive Technology Co., Ltd. 4 + * 5 + * Author: Jee Heng Sia <jeeheng.sia@starfivetech.com> 6 + */ 7 + 8 + #ifndef __ASSEMBLY__ 9 + #error "Only include this from assembly code" 10 + #endif 11 + 12 + #ifndef __ASM_ASSEMBLER_H 13 + #define __ASM_ASSEMBLER_H 14 + 15 + #include <asm/asm.h> 16 + #include <asm/asm-offsets.h> 17 + #include <asm/csr.h> 18 + 19 + /* 20 + * suspend_restore_csrs - restore CSRs 21 + */ 22 + .macro suspend_restore_csrs 23 + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0) 24 + csrw CSR_EPC, t0 25 + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0) 26 + csrw CSR_STATUS, t0 27 + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0) 28 + csrw CSR_TVAL, t0 29 + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0) 30 + csrw CSR_CAUSE, t0 31 + .endm 32 + 33 + /* 34 + * suspend_restore_regs - Restore registers (except A0 and T0-T6) 35 + */ 36 + .macro suspend_restore_regs 37 + REG_L ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0) 38 + REG_L sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0) 39 + REG_L gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0) 40 + REG_L tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0) 41 + REG_L s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0) 42 + REG_L s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0) 43 + REG_L a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0) 44 + REG_L a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0) 45 + REG_L a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0) 46 + REG_L a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0) 47 + REG_L a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0) 48 + REG_L a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0) 49 + REG_L a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0) 50 + REG_L s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0) 51 + REG_L s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0) 52 + REG_L s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0) 53 + REG_L s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0) 54 + REG_L s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0) 55 + REG_L s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0) 56 + REG_L s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0) 57 + REG_L s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0) 58 + REG_L s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0) 59 + REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0) 60 + .endm 61 + 62 + /* 63 + * copy_page - copy 1 page (4KB) of data from source to destination 64 + * @a0 - destination 65 + * @a1 - source 66 + */ 67 + .macro copy_page a0, a1 68 + lui a2, 0x1 69 + add a2, a2, a0 70 + 1 : 71 + REG_L t0, 0(a1) 72 + REG_L t1, SZREG(a1) 73 + 74 + REG_S t0, 0(a0) 75 + REG_S t1, SZREG(a0) 76 + 77 + addi a0, a0, 2 * SZREG 78 + addi a1, a1, 2 * SZREG 79 + bne a2, a0, 1b 80 + .endm 81 + 82 + #endif /* __ASM_ASSEMBLER_H */
+1 -1
arch/riscv/include/asm/sbi.h
··· 295 295 unsigned long start, 296 296 unsigned long size, 297 297 unsigned long asid); 298 - int sbi_probe_extension(int ext); 298 + long sbi_probe_extension(int ext); 299 299 300 300 /* Check if current SBI specification version is 0.1 or not */ 301 301 static inline int sbi_spec_is_0_1(void)
+22
arch/riscv/include/asm/suspend.h
··· 21 21 #endif 22 22 }; 23 23 24 + /* 25 + * Used by hibernation core and cleared during resume sequence 26 + */ 27 + extern int in_suspend; 28 + 24 29 /* Low-level CPU suspend entry function */ 25 30 int __cpu_suspend_enter(struct suspend_context *context); 26 31 ··· 38 33 /* Low-level CPU resume entry function */ 39 34 int __cpu_resume_enter(unsigned long hartid, unsigned long context); 40 35 36 + /* Used to save and restore the CSRs */ 37 + void suspend_save_csrs(struct suspend_context *context); 38 + void suspend_restore_csrs(struct suspend_context *context); 39 + 40 + /* Low-level API to support hibernation */ 41 + int swsusp_arch_suspend(void); 42 + int swsusp_arch_resume(void); 43 + int arch_hibernation_header_save(void *addr, unsigned int max_size); 44 + int arch_hibernation_header_restore(void *addr); 45 + int __hibernate_cpu_resume(void); 46 + 47 + /* Used to resume on the CPU we hibernated on */ 48 + int hibernate_resume_nonboot_cpu_disable(void); 49 + 50 + asmlinkage void hibernate_restore_image(unsigned long resume_satp, unsigned long satp_temp, 51 + unsigned long cpu_resume); 52 + asmlinkage int hibernate_core_restore_code(void); 41 53 #endif
+2
arch/riscv/kernel/Makefile
··· 9 9 CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE) 10 10 endif 11 11 CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,) 12 + CFLAGS_compat_syscall_table.o += $(call cc-option,-Wno-override-init,) 12 13 13 14 ifdef CONFIG_KEXEC 14 15 AFLAGS_kexec_relocate.o := -mcmodel=medany $(call cc-option,-mno-relax) ··· 65 64 obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o 66 65 67 66 obj-$(CONFIG_CPU_PM) += suspend_entry.o suspend.o 67 + obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o 68 68 69 69 obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o 70 70 obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o
+5
arch/riscv/kernel/asm-offsets.c
··· 9 9 #include <linux/kbuild.h> 10 10 #include <linux/mm.h> 11 11 #include <linux/sched.h> 12 + #include <linux/suspend.h> 12 13 #include <asm/kvm_host.h> 13 14 #include <asm/thread_info.h> 14 15 #include <asm/ptrace.h> ··· 116 115 OFFSET(PT_CAUSE, pt_regs, cause); 117 116 118 117 OFFSET(SUSPEND_CONTEXT_REGS, suspend_context, regs); 118 + 119 + OFFSET(HIBERN_PBE_ADDR, pbe, address); 120 + OFFSET(HIBERN_PBE_ORIG, pbe, orig_address); 121 + OFFSET(HIBERN_PBE_NEXT, pbe, next); 119 122 120 123 OFFSET(KVM_ARCH_GUEST_ZERO, kvm_vcpu_arch, guest_context.zero); 121 124 OFFSET(KVM_ARCH_GUEST_RA, kvm_vcpu_arch, guest_context.ra);
+1 -1
arch/riscv/kernel/cpu_ops.c
··· 27 27 void __init cpu_set_ops(int cpuid) 28 28 { 29 29 #if IS_ENABLED(CONFIG_RISCV_SBI) 30 - if (sbi_probe_extension(SBI_EXT_HSM) > 0) { 30 + if (sbi_probe_extension(SBI_EXT_HSM)) { 31 31 if (!cpuid) 32 32 pr_info("SBI HSM extension detected\n"); 33 33 cpu_ops[cpuid] = &cpu_ops_sbi;
+1
arch/riscv/kernel/cpufeature.c
··· 14 14 #include <linux/of.h> 15 15 #include <asm/alternative.h> 16 16 #include <asm/cacheflush.h> 17 + #include <asm/cpufeature.h> 17 18 #include <asm/hwcap.h> 18 19 #include <asm/patch.h> 19 20 #include <asm/processor.h>
+77
arch/riscv/kernel/hibernate-asm.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Hibernation low level support for RISCV. 4 + * 5 + * Copyright (C) 2023 StarFive Technology Co., Ltd. 6 + * 7 + * Author: Jee Heng Sia <jeeheng.sia@starfivetech.com> 8 + */ 9 + 10 + #include <asm/asm.h> 11 + #include <asm/asm-offsets.h> 12 + #include <asm/assembler.h> 13 + #include <asm/csr.h> 14 + 15 + #include <linux/linkage.h> 16 + 17 + /* 18 + * int __hibernate_cpu_resume(void) 19 + * Switch back to the hibernated image's page table prior to restoring the CPU 20 + * context. 21 + * 22 + * Always returns 0 23 + */ 24 + ENTRY(__hibernate_cpu_resume) 25 + /* switch to hibernated image's page table. */ 26 + csrw CSR_SATP, s0 27 + sfence.vma 28 + 29 + REG_L a0, hibernate_cpu_context 30 + 31 + suspend_restore_csrs 32 + suspend_restore_regs 33 + 34 + /* Return zero value. */ 35 + mv a0, zero 36 + 37 + ret 38 + END(__hibernate_cpu_resume) 39 + 40 + /* 41 + * Prepare to restore the image. 42 + * a0: satp of saved page tables. 43 + * a1: satp of temporary page tables. 44 + * a2: cpu_resume. 45 + */ 46 + ENTRY(hibernate_restore_image) 47 + mv s0, a0 48 + mv s1, a1 49 + mv s2, a2 50 + REG_L s4, restore_pblist 51 + REG_L a1, relocated_restore_code 52 + 53 + jalr a1 54 + END(hibernate_restore_image) 55 + 56 + /* 57 + * The below code will be executed from a 'safe' page. 58 + * It first switches to the temporary page table, then starts to copy the pages 59 + * back to the original memory location. Finally, it jumps to __hibernate_cpu_resume() 60 + * to restore the CPU context. 61 + */ 62 + ENTRY(hibernate_core_restore_code) 63 + /* switch to temp page table. */ 64 + csrw satp, s1 65 + sfence.vma 66 + .Lcopy: 67 + /* The below code will restore the hibernated image. */ 68 + REG_L a1, HIBERN_PBE_ADDR(s4) 69 + REG_L a0, HIBERN_PBE_ORIG(s4) 70 + 71 + copy_page a0, a1 72 + 73 + REG_L s4, HIBERN_PBE_NEXT(s4) 74 + bnez s4, .Lcopy 75 + 76 + jalr s2 77 + END(hibernate_core_restore_code)
+427
arch/riscv/kernel/hibernate.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Hibernation support for RISCV 4 + * 5 + * Copyright (C) 2023 StarFive Technology Co., Ltd. 6 + * 7 + * Author: Jee Heng Sia <jeeheng.sia@starfivetech.com> 8 + */ 9 + 10 + #include <asm/barrier.h> 11 + #include <asm/cacheflush.h> 12 + #include <asm/mmu_context.h> 13 + #include <asm/page.h> 14 + #include <asm/pgalloc.h> 15 + #include <asm/pgtable.h> 16 + #include <asm/sections.h> 17 + #include <asm/set_memory.h> 18 + #include <asm/smp.h> 19 + #include <asm/suspend.h> 20 + 21 + #include <linux/cpu.h> 22 + #include <linux/memblock.h> 23 + #include <linux/pm.h> 24 + #include <linux/sched.h> 25 + #include <linux/suspend.h> 26 + #include <linux/utsname.h> 27 + 28 + /* The logical cpu number we should resume on, initialised to a non-cpu number. */ 29 + static int sleep_cpu = -EINVAL; 30 + 31 + /* Pointer to the temporary resume page table. */ 32 + static pgd_t *resume_pg_dir; 33 + 34 + /* CPU context to be saved. */ 35 + struct suspend_context *hibernate_cpu_context; 36 + EXPORT_SYMBOL_GPL(hibernate_cpu_context); 37 + 38 + unsigned long relocated_restore_code; 39 + EXPORT_SYMBOL_GPL(relocated_restore_code); 40 + 41 + /** 42 + * struct arch_hibernate_hdr_invariants - container to store kernel build version. 43 + * @uts_version: to save the build number and date so that we do not resume with 44 + * a different kernel. 45 + */ 46 + struct arch_hibernate_hdr_invariants { 47 + char uts_version[__NEW_UTS_LEN + 1]; 48 + }; 49 + 50 + /** 51 + * struct arch_hibernate_hdr - helper parameters that help us to restore the image. 52 + * @invariants: container to store kernel build version. 53 + * @hartid: to make sure same boot_cpu executes the hibernate/restore code. 54 + * @saved_satp: original page table used by the hibernated image. 55 + * @restore_cpu_addr: the kernel's image address to restore the CPU context. 56 + */ 57 + static struct arch_hibernate_hdr { 58 + struct arch_hibernate_hdr_invariants invariants; 59 + unsigned long hartid; 60 + unsigned long saved_satp; 61 + unsigned long restore_cpu_addr; 62 + } resume_hdr; 63 + 64 + static void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i) 65 + { 66 + memset(i, 0, sizeof(*i)); 67 + memcpy(i->uts_version, init_utsname()->version, sizeof(i->uts_version)); 68 + } 69 + 70 + /* 71 + * Check if the given pfn is in the 'nosave' section. 72 + */ 73 + int pfn_is_nosave(unsigned long pfn) 74 + { 75 + unsigned long nosave_begin_pfn = sym_to_pfn(&__nosave_begin); 76 + unsigned long nosave_end_pfn = sym_to_pfn(&__nosave_end - 1); 77 + 78 + return ((pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn)); 79 + } 80 + 81 + void notrace save_processor_state(void) 82 + { 83 + WARN_ON(num_online_cpus() != 1); 84 + } 85 + 86 + void notrace restore_processor_state(void) 87 + { 88 + } 89 + 90 + /* 91 + * Helper parameters need to be saved to the hibernation image header. 92 + */ 93 + int arch_hibernation_header_save(void *addr, unsigned int max_size) 94 + { 95 + struct arch_hibernate_hdr *hdr = addr; 96 + 97 + if (max_size < sizeof(*hdr)) 98 + return -EOVERFLOW; 99 + 100 + arch_hdr_invariants(&hdr->invariants); 101 + 102 + hdr->hartid = cpuid_to_hartid_map(sleep_cpu); 103 + hdr->saved_satp = csr_read(CSR_SATP); 104 + hdr->restore_cpu_addr = (unsigned long)__hibernate_cpu_resume; 105 + 106 + return 0; 107 + } 108 + EXPORT_SYMBOL_GPL(arch_hibernation_header_save); 109 + 110 + /* 111 + * Retrieve the helper parameters from the hibernation image header. 112 + */ 113 + int arch_hibernation_header_restore(void *addr) 114 + { 115 + struct arch_hibernate_hdr_invariants invariants; 116 + struct arch_hibernate_hdr *hdr = addr; 117 + int ret = 0; 118 + 119 + arch_hdr_invariants(&invariants); 120 + 121 + if (memcmp(&hdr->invariants, &invariants, sizeof(invariants))) { 122 + pr_crit("Hibernate image not generated by this kernel!\n"); 123 + return -EINVAL; 124 + } 125 + 126 + sleep_cpu = riscv_hartid_to_cpuid(hdr->hartid); 127 + if (sleep_cpu < 0) { 128 + pr_crit("Hibernated on a CPU not known to this kernel!\n"); 129 + sleep_cpu = -EINVAL; 130 + return -EINVAL; 131 + } 132 + 133 + #ifdef CONFIG_SMP 134 + ret = bringup_hibernate_cpu(sleep_cpu); 135 + if (ret) { 136 + sleep_cpu = -EINVAL; 137 + return ret; 138 + } 139 + #endif 140 + resume_hdr = *hdr; 141 + 142 + return ret; 143 + } 144 + EXPORT_SYMBOL_GPL(arch_hibernation_header_restore); 145 + 146 + int swsusp_arch_suspend(void) 147 + { 148 + int ret = 0; 149 + 150 + if (__cpu_suspend_enter(hibernate_cpu_context)) { 151 + sleep_cpu = smp_processor_id(); 152 + suspend_save_csrs(hibernate_cpu_context); 153 + ret = swsusp_save(); 154 + } else { 155 + suspend_restore_csrs(hibernate_cpu_context); 156 + flush_tlb_all(); 157 + flush_icache_all(); 158 + 159 + /* 160 + * Tell the hibernation core that we've just restored the memory. 161 + */ 162 + in_suspend = 0; 163 + sleep_cpu = -EINVAL; 164 + } 165 + 166 + return ret; 167 + } 168 + 169 + static int temp_pgtable_map_pte(pmd_t *dst_pmdp, pmd_t *src_pmdp, unsigned long start, 170 + unsigned long end, pgprot_t prot) 171 + { 172 + pte_t *src_ptep; 173 + pte_t *dst_ptep; 174 + 175 + if (pmd_none(READ_ONCE(*dst_pmdp))) { 176 + dst_ptep = (pte_t *)get_safe_page(GFP_ATOMIC); 177 + if (!dst_ptep) 178 + return -ENOMEM; 179 + 180 + pmd_populate_kernel(NULL, dst_pmdp, dst_ptep); 181 + } 182 + 183 + dst_ptep = pte_offset_kernel(dst_pmdp, start); 184 + src_ptep = pte_offset_kernel(src_pmdp, start); 185 + 186 + do { 187 + pte_t pte = READ_ONCE(*src_ptep); 188 + 189 + if (pte_present(pte)) 190 + set_pte(dst_ptep, __pte(pte_val(pte) | pgprot_val(prot))); 191 + } while (dst_ptep++, src_ptep++, start += PAGE_SIZE, start < end); 192 + 193 + return 0; 194 + } 195 + 196 + static int temp_pgtable_map_pmd(pud_t *dst_pudp, pud_t *src_pudp, unsigned long start, 197 + unsigned long end, pgprot_t prot) 198 + { 199 + unsigned long next; 200 + unsigned long ret; 201 + pmd_t *src_pmdp; 202 + pmd_t *dst_pmdp; 203 + 204 + if (pud_none(READ_ONCE(*dst_pudp))) { 205 + dst_pmdp = (pmd_t *)get_safe_page(GFP_ATOMIC); 206 + if (!dst_pmdp) 207 + return -ENOMEM; 208 + 209 + pud_populate(NULL, dst_pudp, dst_pmdp); 210 + } 211 + 212 + dst_pmdp = pmd_offset(dst_pudp, start); 213 + src_pmdp = pmd_offset(src_pudp, start); 214 + 215 + do { 216 + pmd_t pmd = READ_ONCE(*src_pmdp); 217 + 218 + next = pmd_addr_end(start, end); 219 + 220 + if (pmd_none(pmd)) 221 + continue; 222 + 223 + if (pmd_leaf(pmd)) { 224 + set_pmd(dst_pmdp, __pmd(pmd_val(pmd) | pgprot_val(prot))); 225 + } else { 226 + ret = temp_pgtable_map_pte(dst_pmdp, src_pmdp, start, next, prot); 227 + if (ret) 228 + return -ENOMEM; 229 + } 230 + } while (dst_pmdp++, src_pmdp++, start = next, start != end); 231 + 232 + return 0; 233 + } 234 + 235 + static int temp_pgtable_map_pud(p4d_t *dst_p4dp, p4d_t *src_p4dp, unsigned long start, 236 + unsigned long end, pgprot_t prot) 237 + { 238 + unsigned long next; 239 + unsigned long ret; 240 + pud_t *dst_pudp; 241 + pud_t *src_pudp; 242 + 243 + if (p4d_none(READ_ONCE(*dst_p4dp))) { 244 + dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC); 245 + if (!dst_pudp) 246 + return -ENOMEM; 247 + 248 + p4d_populate(NULL, dst_p4dp, dst_pudp); 249 + } 250 + 251 + dst_pudp = pud_offset(dst_p4dp, start); 252 + src_pudp = pud_offset(src_p4dp, start); 253 + 254 + do { 255 + pud_t pud = READ_ONCE(*src_pudp); 256 + 257 + next = pud_addr_end(start, end); 258 + 259 + if (pud_none(pud)) 260 + continue; 261 + 262 + if (pud_leaf(pud)) { 263 + set_pud(dst_pudp, __pud(pud_val(pud) | pgprot_val(prot))); 264 + } else { 265 + ret = temp_pgtable_map_pmd(dst_pudp, src_pudp, start, next, prot); 266 + if (ret) 267 + return -ENOMEM; 268 + } 269 + } while (dst_pudp++, src_pudp++, start = next, start != end); 270 + 271 + return 0; 272 + } 273 + 274 + static int temp_pgtable_map_p4d(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, 275 + unsigned long end, pgprot_t prot) 276 + { 277 + unsigned long next; 278 + unsigned long ret; 279 + p4d_t *dst_p4dp; 280 + p4d_t *src_p4dp; 281 + 282 + if (pgd_none(READ_ONCE(*dst_pgdp))) { 283 + dst_p4dp = (p4d_t *)get_safe_page(GFP_ATOMIC); 284 + if (!dst_p4dp) 285 + return -ENOMEM; 286 + 287 + pgd_populate(NULL, dst_pgdp, dst_p4dp); 288 + } 289 + 290 + dst_p4dp = p4d_offset(dst_pgdp, start); 291 + src_p4dp = p4d_offset(src_pgdp, start); 292 + 293 + do { 294 + p4d_t p4d = READ_ONCE(*src_p4dp); 295 + 296 + next = p4d_addr_end(start, end); 297 + 298 + if (p4d_none(p4d)) 299 + continue; 300 + 301 + if (p4d_leaf(p4d)) { 302 + set_p4d(dst_p4dp, __p4d(p4d_val(p4d) | pgprot_val(prot))); 303 + } else { 304 + ret = temp_pgtable_map_pud(dst_p4dp, src_p4dp, start, next, prot); 305 + if (ret) 306 + return -ENOMEM; 307 + } 308 + } while (dst_p4dp++, src_p4dp++, start = next, start != end); 309 + 310 + return 0; 311 + } 312 + 313 + static int temp_pgtable_mapping(pgd_t *pgdp, unsigned long start, unsigned long end, pgprot_t prot) 314 + { 315 + pgd_t *dst_pgdp = pgd_offset_pgd(pgdp, start); 316 + pgd_t *src_pgdp = pgd_offset_k(start); 317 + unsigned long next; 318 + unsigned long ret; 319 + 320 + do { 321 + pgd_t pgd = READ_ONCE(*src_pgdp); 322 + 323 + next = pgd_addr_end(start, end); 324 + 325 + if (pgd_none(pgd)) 326 + continue; 327 + 328 + if (pgd_leaf(pgd)) { 329 + set_pgd(dst_pgdp, __pgd(pgd_val(pgd) | pgprot_val(prot))); 330 + } else { 331 + ret = temp_pgtable_map_p4d(dst_pgdp, src_pgdp, start, next, prot); 332 + if (ret) 333 + return -ENOMEM; 334 + } 335 + } while (dst_pgdp++, src_pgdp++, start = next, start != end); 336 + 337 + return 0; 338 + } 339 + 340 + static unsigned long relocate_restore_code(void) 341 + { 342 + void *page = (void *)get_safe_page(GFP_ATOMIC); 343 + 344 + if (!page) 345 + return -ENOMEM; 346 + 347 + copy_page(page, hibernate_core_restore_code); 348 + 349 + /* Make the page containing the relocated code executable. */ 350 + set_memory_x((unsigned long)page, 1); 351 + 352 + return (unsigned long)page; 353 + } 354 + 355 + int swsusp_arch_resume(void) 356 + { 357 + unsigned long end = (unsigned long)pfn_to_virt(max_low_pfn); 358 + unsigned long start = PAGE_OFFSET; 359 + int ret; 360 + 361 + /* 362 + * Memory allocated by get_safe_page() will be dealt with by the hibernation core, 363 + * we don't need to free it here. 364 + */ 365 + resume_pg_dir = (pgd_t *)get_safe_page(GFP_ATOMIC); 366 + if (!resume_pg_dir) 367 + return -ENOMEM; 368 + 369 + /* 370 + * Create a temporary page table and map the whole linear region as executable and 371 + * writable. 372 + */ 373 + ret = temp_pgtable_mapping(resume_pg_dir, start, end, __pgprot(_PAGE_WRITE | _PAGE_EXEC)); 374 + if (ret) 375 + return ret; 376 + 377 + /* Move the restore code to a new page so that it doesn't get overwritten by itself. */ 378 + relocated_restore_code = relocate_restore_code(); 379 + if (relocated_restore_code == -ENOMEM) 380 + return -ENOMEM; 381 + 382 + /* 383 + * Map the __hibernate_cpu_resume() address to the temporary page table so that the 384 + * restore code can jumps to it after finished restore the image. The next execution 385 + * code doesn't find itself in a different address space after switching over to the 386 + * original page table used by the hibernated image. 387 + * The __hibernate_cpu_resume() mapping is unnecessary for RV32 since the kernel and 388 + * linear addresses are identical, but different for RV64. To ensure consistency, we 389 + * map it for both RV32 and RV64 kernels. 390 + * Additionally, we should ensure that the page is writable before restoring the image. 391 + */ 392 + start = (unsigned long)resume_hdr.restore_cpu_addr; 393 + end = start + PAGE_SIZE; 394 + 395 + ret = temp_pgtable_mapping(resume_pg_dir, start, end, __pgprot(_PAGE_WRITE)); 396 + if (ret) 397 + return ret; 398 + 399 + hibernate_restore_image(resume_hdr.saved_satp, (PFN_DOWN(__pa(resume_pg_dir)) | satp_mode), 400 + resume_hdr.restore_cpu_addr); 401 + 402 + return 0; 403 + } 404 + 405 + #ifdef CONFIG_PM_SLEEP_SMP 406 + int hibernate_resume_nonboot_cpu_disable(void) 407 + { 408 + if (sleep_cpu < 0) { 409 + pr_err("Failing to resume from hibernate on an unknown CPU\n"); 410 + return -ENODEV; 411 + } 412 + 413 + return freeze_secondary_cpus(sleep_cpu); 414 + } 415 + #endif 416 + 417 + static int __init riscv_hibernate_init(void) 418 + { 419 + hibernate_cpu_context = kzalloc(sizeof(*hibernate_cpu_context), GFP_KERNEL); 420 + 421 + if (WARN_ON(!hibernate_cpu_context)) 422 + return -ENOMEM; 423 + 424 + return 0; 425 + } 426 + 427 + early_initcall(riscv_hibernate_init);
+8 -9
arch/riscv/kernel/sbi.c
··· 524 524 * sbi_probe_extension() - Check if an SBI extension ID is supported or not. 525 525 * @extid: The extension ID to be probed. 526 526 * 527 - * Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise. 527 + * Return: 1 or an extension specific nonzero value if yes, 0 otherwise. 528 528 */ 529 - int sbi_probe_extension(int extid) 529 + long sbi_probe_extension(int extid) 530 530 { 531 531 struct sbiret ret; 532 532 533 533 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid, 534 534 0, 0, 0, 0, 0); 535 535 if (!ret.error) 536 - if (ret.value) 537 - return ret.value; 536 + return ret.value; 538 537 539 - return -ENOTSUPP; 538 + return 0; 540 539 } 541 540 EXPORT_SYMBOL(sbi_probe_extension); 542 541 ··· 598 599 if (!sbi_spec_is_0_1()) { 599 600 pr_info("SBI implementation ID=0x%lx Version=0x%lx\n", 600 601 sbi_get_firmware_id(), sbi_get_firmware_version()); 601 - if (sbi_probe_extension(SBI_EXT_TIME) > 0) { 602 + if (sbi_probe_extension(SBI_EXT_TIME)) { 602 603 __sbi_set_timer = __sbi_set_timer_v02; 603 604 pr_info("SBI TIME extension detected\n"); 604 605 } else { 605 606 __sbi_set_timer = __sbi_set_timer_v01; 606 607 } 607 - if (sbi_probe_extension(SBI_EXT_IPI) > 0) { 608 + if (sbi_probe_extension(SBI_EXT_IPI)) { 608 609 __sbi_send_ipi = __sbi_send_ipi_v02; 609 610 pr_info("SBI IPI extension detected\n"); 610 611 } else { 611 612 __sbi_send_ipi = __sbi_send_ipi_v01; 612 613 } 613 - if (sbi_probe_extension(SBI_EXT_RFENCE) > 0) { 614 + if (sbi_probe_extension(SBI_EXT_RFENCE)) { 614 615 __sbi_rfence = __sbi_rfence_v02; 615 616 pr_info("SBI RFENCE extension detected\n"); 616 617 } else { 617 618 __sbi_rfence = __sbi_rfence_v01; 618 619 } 619 620 if ((sbi_spec_version >= sbi_mk_version(0, 3)) && 620 - (sbi_probe_extension(SBI_EXT_SRST) > 0)) { 621 + sbi_probe_extension(SBI_EXT_SRST)) { 621 622 pr_info("SBI SRST extension detected\n"); 622 623 pm_power_off = sbi_srst_power_off; 623 624 sbi_srst_reboot_nb.notifier_call = sbi_srst_reboot;
+2 -2
arch/riscv/kernel/suspend.c
··· 8 8 #include <asm/csr.h> 9 9 #include <asm/suspend.h> 10 10 11 - static void suspend_save_csrs(struct suspend_context *context) 11 + void suspend_save_csrs(struct suspend_context *context) 12 12 { 13 13 context->scratch = csr_read(CSR_SCRATCH); 14 14 context->tvec = csr_read(CSR_TVEC); ··· 29 29 #endif 30 30 } 31 31 32 - static void suspend_restore_csrs(struct suspend_context *context) 32 + void suspend_restore_csrs(struct suspend_context *context) 33 33 { 34 34 csr_write(CSR_SCRATCH, context->scratch); 35 35 csr_write(CSR_TVEC, context->tvec);
+3 -31
arch/riscv/kernel/suspend_entry.S
··· 7 7 #include <linux/linkage.h> 8 8 #include <asm/asm.h> 9 9 #include <asm/asm-offsets.h> 10 + #include <asm/assembler.h> 10 11 #include <asm/csr.h> 11 12 #include <asm/xip_fixup.h> 12 13 ··· 84 83 add a0, a1, zero 85 84 86 85 /* Restore CSRs */ 87 - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0) 88 - csrw CSR_EPC, t0 89 - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0) 90 - csrw CSR_STATUS, t0 91 - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0) 92 - csrw CSR_TVAL, t0 93 - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0) 94 - csrw CSR_CAUSE, t0 86 + suspend_restore_csrs 95 87 96 88 /* Restore registers (except A0 and T0-T6) */ 97 - REG_L ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0) 98 - REG_L sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0) 99 - REG_L gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0) 100 - REG_L tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0) 101 - REG_L s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0) 102 - REG_L s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0) 103 - REG_L a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0) 104 - REG_L a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0) 105 - REG_L a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0) 106 - REG_L a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0) 107 - REG_L a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0) 108 - REG_L a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0) 109 - REG_L a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0) 110 - REG_L s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0) 111 - REG_L s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0) 112 - REG_L s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0) 113 - REG_L s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0) 114 - REG_L s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0) 115 - REG_L s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0) 116 - REG_L s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0) 117 - REG_L s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0) 118 - REG_L s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0) 119 - REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0) 89 + suspend_restore_regs 120 90 121 91 /* Return zero value */ 122 92 add a0, zero, zero
+6 -6
arch/riscv/kernel/vmlinux.lds.S
··· 104 104 *(.rel.dyn*) 105 105 } 106 106 107 + .rela.dyn : ALIGN(8) { 108 + __rela_dyn_start = .; 109 + *(.rela .rela*) 110 + __rela_dyn_end = .; 111 + } 112 + 107 113 __init_data_end = .; 108 114 109 115 . = ALIGN(8); ··· 134 128 .sdata : { 135 129 __global_pointer$ = . + 0x800; 136 130 *(.sdata*) 137 - } 138 - 139 - .rela.dyn : ALIGN(8) { 140 - __rela_dyn_start = .; 141 - *(.rela .rela*) 142 - __rela_dyn_end = .; 143 131 } 144 132 145 133 .got : { *(.got*) }
+1 -1
arch/riscv/kvm/main.c
··· 80 80 return -ENODEV; 81 81 } 82 82 83 - if (sbi_probe_extension(SBI_EXT_RFENCE) <= 0) { 83 + if (!sbi_probe_extension(SBI_EXT_RFENCE)) { 84 84 kvm_info("require SBI RFENCE extension\n"); 85 85 return -ENODEV; 86 86 }
+2 -4
arch/riscv/mm/init.c
··· 919 919 * this means 2 PMD entries whereas for 32-bit kernel, this is only 1 PGDIR 920 920 * entry. 921 921 */ 922 - static void __init create_fdt_early_page_table(pgd_t *pgdir, 923 - uintptr_t fix_fdt_va, 922 + static void __init create_fdt_early_page_table(uintptr_t fix_fdt_va, 924 923 uintptr_t dtb_pa) 925 924 { 926 925 uintptr_t pa = dtb_pa & ~(PMD_SIZE - 1); ··· 1131 1132 create_kernel_page_table(early_pg_dir, true); 1132 1133 1133 1134 /* Setup early mapping for FDT early scan */ 1134 - create_fdt_early_page_table(early_pg_dir, 1135 - __fix_to_virt(FIX_FDT), dtb_pa); 1135 + create_fdt_early_page_table(__fix_to_virt(FIX_FDT), dtb_pa); 1136 1136 1137 1137 /* 1138 1138 * Bootime fixmap only can handle PMD_SIZE mapping. Thus, boot-ioremap
+8
arch/riscv/mm/pageattr.c
··· 217 217 pgd = pgd_offset_k(addr); 218 218 if (!pgd_present(*pgd)) 219 219 return false; 220 + if (pgd_leaf(*pgd)) 221 + return true; 220 222 221 223 p4d = p4d_offset(pgd, addr); 222 224 if (!p4d_present(*p4d)) 223 225 return false; 226 + if (p4d_leaf(*p4d)) 227 + return true; 224 228 225 229 pud = pud_offset(p4d, addr); 226 230 if (!pud_present(*pud)) 227 231 return false; 232 + if (pud_leaf(*pud)) 233 + return true; 228 234 229 235 pmd = pmd_offset(pud, addr); 230 236 if (!pmd_present(*pmd)) 231 237 return false; 238 + if (pmd_leaf(*pmd)) 239 + return true; 232 240 233 241 pte = pte_offset_kernel(pmd, addr); 234 242 return pte_present(*pte);
+1 -1
drivers/cpuidle/cpuidle-riscv-sbi.c
··· 613 613 * 2) SBI HSM extension is available 614 614 */ 615 615 if ((sbi_spec_version < sbi_mk_version(0, 3)) || 616 - sbi_probe_extension(SBI_EXT_HSM) <= 0) { 616 + !sbi_probe_extension(SBI_EXT_HSM)) { 617 617 pr_info("HSM suspend not available\n"); 618 618 return 0; 619 619 }
+1 -1
drivers/perf/riscv_pmu_sbi.c
··· 924 924 struct platform_device *pdev; 925 925 926 926 if (sbi_spec_version < sbi_mk_version(0, 3) || 927 - sbi_probe_extension(SBI_EXT_PMU) <= 0) { 927 + !sbi_probe_extension(SBI_EXT_PMU)) { 928 928 return 0; 929 929 } 930 930