diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-30 09:44:29 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-30 09:44:29 -1000 |
| commit | 780cb2a5fd64901444878cf5a40c0f2ec54837ce (patch) | |
| tree | 6e73864dd8b389f706607440fe2ae20629fff686 | |
| parent | 8fe8e62f432f0a7a0292a328a73c6912b9a2b73b (diff) | |
| parent | 6f8d12bb1a1231dbba579932772701880745a21d (diff) | |
| download | linux-780cb2a5fd64901444878cf5a40c0f2ec54837ce.tar.gz linux-780cb2a5fd64901444878cf5a40c0f2ec54837ce.zip | |
Merge tag 'loongarch-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
Pull LoongArch updates from Huacai Chen:
- Add LoongArch-specific ACPI initialization
- Set NX compat flag in PE/COFF efi header
- Use pa_to_nid()/nid_to_addrbase() rather than hard-code
- Detect and expose LAMCAS/DIV32 feature existence
- Fix and improve perf hardware breakpoints
- Fix and improve BPF JIT (trampoline and 32-bit operations)
- Add arch_crash_save_vmcoreinfo() support
- Some bug fixes and other small changes
* tag 'loongarch-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson: (24 commits)
soc: loongson: loongson2_guts: Use of_root instead of own reference
soc: loongson: loongson2_pm: Fix build warnings for 32BIT
LoongArch: dts: loongson-2k0500: Drop unsupported bus_id in DWMAC
LoongArch: BPF: Optimize 32-bit operations using native instructions
LoongArch: BPF: Clean up and decouple is32 parameter from move_imm()
LoongArch: BPF: Fix stack arguments for indirect trampolines
LoongArch: Add arch_crash_save_vmcoreinfo() support
LoongArch: Fix one-shot limitation for perf hardware breakpoints
LoongArch: Fix perf hardware breakpoint failure via installation
LoongArch: Only send SIGTRAP signal if necessary in do_watch()
LoongArch: Fix architectural naming typo for CSR_FWPS_SKIP
LoongArch: Fix bitmask corruption in update_bp_registers()
LoongArch: Remove redundant call in update_bp_registers()
LoongArch: Remove arch-specific __smp_mb__{before,after}_atomic()
LoongArch: Detect and expose DIV32 feature existence
LoongArch: Detect and expose LAMCAS feature existence
LoongArch: Use pa_to_nid()/nid_to_addrbase() rather than hard-code
LoongArch: Don't init & online empty nodes
LoongArch: Call cpu_final_simd() with pure_initcall()
LoongArch: Use assign_bit() API where applicable
...
40 files changed, 753 insertions, 272 deletions
diff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst index 5f1df6d08050..0fc4294b90a4 100644 --- a/Documentation/admin-guide/kdump/vmcoreinfo.rst +++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst @@ -594,3 +594,39 @@ va_kernel_pa_offset Indicates the offset between the kernel virtual and physical mappings. Used to translate virtual to physical addresses. + +LOONGARCH64 +=========== + +VA_BITS +------- + +The maximum number of bits for virtual addresses. Used to compute the +virtual memory ranges. + +PHYS_OFFSET +----------- + +Indicates the physical address of the start of memory. Used to translate +virtual to physical addresses. + +PAGE_OFFSET +----------- + +Indicates the virtual kernel start address of the direct-mapped RAM region. +Used together with PHYS_OFFSET to translate between virtual and physical +addresses. + +KERNELOFFSET +------------ + +The kernel randomization offset. Used to locate the kernel text in virtual +memory. If KASLR is disabled, this value is zero. + +MODULES_VADDR|MODULES_END|VMALLOC_START|VMALLOC_END|VMEMMAP_START|VMEMMAP_END +----------------------------------------------------------------------------- + +Used to get the correct ranges: + MODULES_VADDR ~ MODULES_END-1 : Kernel module space. + VMALLOC_START ~ VMALLOC_END-1 : vmalloc() / ioremap() space. + VMEMMAP_START ~ VMEMMAP_END-1 : vmemmap region, used for struct page array. diff --git a/MAINTAINERS b/MAINTAINERS index 37f6d8aaa556..3f7bbb9c2915 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -350,6 +350,15 @@ S: Maintained F: drivers/acpi/arm64 F: include/linux/acpi_iort.h +ACPI FOR LOONGARCH (ACPI/LoongArch) +M: Bibo Mao <maobibo@loongson.cn> +M: Huacai Chen <chenhuacai@kernel.org> +L: linux-acpi@vger.kernel.org +L: loongarch@lists.linux.dev +S: Maintained +F: drivers/acpi/loongarch/ +F: include/linux/acpi_iovt.h + ACPI FOR RISC-V (ACPI/riscv) M: Sunil V L <sunilvl@ventanamicro.com> L: linux-acpi@vger.kernel.org diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 0aad0004b010..b5ed4881d3c0 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -6,6 +6,7 @@ config LOONGARCH select ACPI_GENERIC_GSI if ACPI select ACPI_MCFG if ACPI select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU + select ACPI_IOVT if ACPI select ACPI_PPTT if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_BINFMT_ELF_STATE diff --git a/arch/loongarch/boot/dts/loongson-2k0500-ref.dts b/arch/loongarch/boot/dts/loongson-2k0500-ref.dts index 7ace54c84244..d2a3ed9fa578 100644 --- a/arch/loongarch/boot/dts/loongson-2k0500-ref.dts +++ b/arch/loongarch/boot/dts/loongson-2k0500-ref.dts @@ -73,14 +73,12 @@ status = "okay"; phy-mode = "rgmii-id"; - bus_id = <0x0>; }; &gmac1 { status = "okay"; phy-mode = "rgmii-id"; - bus_id = <0x1>; }; &i2c0 { diff --git a/arch/loongarch/include/asm/barrier.h b/arch/loongarch/include/asm/barrier.h index 4b663f197706..84c6d739119d 100644 --- a/arch/loongarch/include/asm/barrier.h +++ b/arch/loongarch/include/asm/barrier.h @@ -57,9 +57,6 @@ #define __WEAK_LLSC_MB " \n" #endif -#define __smp_mb__before_atomic() barrier() -#define __smp_mb__after_atomic() barrier() - /** * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise * @index: array element index diff --git a/arch/loongarch/include/asm/cpu-features.h b/arch/loongarch/include/asm/cpu-features.h index 62059c5551b9..f587cdd1acab 100644 --- a/arch/loongarch/include/asm/cpu-features.h +++ b/arch/loongarch/include/asm/cpu-features.h @@ -36,6 +36,7 @@ #define cpu_has_cpucfg cpu_opt(LOONGARCH_CPU_CPUCFG) #define cpu_has_lam cpu_opt(LOONGARCH_CPU_LAM) #define cpu_has_lam_bh cpu_opt(LOONGARCH_CPU_LAM_BH) +#define cpu_has_lamcas cpu_opt(LOONGARCH_CPU_LAMCAS) #define cpu_has_scq cpu_opt(LOONGARCH_CPU_SCQ) #define cpu_has_ual cpu_opt(LOONGARCH_CPU_UAL) #define cpu_has_fpu cpu_opt(LOONGARCH_CPU_FPU) @@ -44,6 +45,7 @@ #define cpu_has_crc32 cpu_opt(LOONGARCH_CPU_CRC32) #define cpu_has_complex cpu_opt(LOONGARCH_CPU_COMPLEX) #define cpu_has_crypto cpu_opt(LOONGARCH_CPU_CRYPTO) +#define cpu_has_div32 cpu_opt(LOONGARCH_CPU_DIV32) #define cpu_has_lvz cpu_opt(LOONGARCH_CPU_LVZ) #define cpu_has_lbt_x86 cpu_opt(LOONGARCH_CPU_LBT_X86) #define cpu_has_lbt_arm cpu_opt(LOONGARCH_CPU_LBT_ARM) diff --git a/arch/loongarch/include/asm/cpu.h b/arch/loongarch/include/asm/cpu.h index 91b96938861e..8d389bb49421 100644 --- a/arch/loongarch/include/asm/cpu.h +++ b/arch/loongarch/include/asm/cpu.h @@ -96,41 +96,44 @@ static inline char *id_to_core_name(unsigned int id) #define CPU_FEATURE_CPUCFG 0 /* CPU has CPUCFG */ #define CPU_FEATURE_LAM 1 /* CPU has Atomic instructions */ #define CPU_FEATURE_LAM_BH 2 /* CPU has AM{SWAP/ADD}[_DB].{B/H} instructions */ -#define CPU_FEATURE_SCQ 3 /* CPU has SC.Q instruction */ -#define CPU_FEATURE_UAL 4 /* CPU supports unaligned access */ -#define CPU_FEATURE_FPU 5 /* CPU has FPU */ -#define CPU_FEATURE_LSX 6 /* CPU has LSX (128-bit SIMD) */ -#define CPU_FEATURE_LASX 7 /* CPU has LASX (256-bit SIMD) */ -#define CPU_FEATURE_CRC32 8 /* CPU has CRC32 instructions */ -#define CPU_FEATURE_COMPLEX 9 /* CPU has Complex instructions */ -#define CPU_FEATURE_CRYPTO 10 /* CPU has Crypto instructions */ -#define CPU_FEATURE_LVZ 11 /* CPU has Virtualization extension */ -#define CPU_FEATURE_LBT_X86 12 /* CPU has X86 Binary Translation */ -#define CPU_FEATURE_LBT_ARM 13 /* CPU has ARM Binary Translation */ -#define CPU_FEATURE_LBT_MIPS 14 /* CPU has MIPS Binary Translation */ -#define CPU_FEATURE_TLB 15 /* CPU has TLB */ -#define CPU_FEATURE_CSR 16 /* CPU has CSR */ -#define CPU_FEATURE_IOCSR 17 /* CPU has IOCSR */ -#define CPU_FEATURE_WATCH 18 /* CPU has watchpoint registers */ -#define CPU_FEATURE_VINT 19 /* CPU has vectored interrupts */ -#define CPU_FEATURE_CSRIPI 20 /* CPU has CSR-IPI */ -#define CPU_FEATURE_EXTIOI 21 /* CPU has EXT-IOI */ -#define CPU_FEATURE_PREFETCH 22 /* CPU has prefetch instructions */ -#define CPU_FEATURE_PMP 23 /* CPU has perfermance counter */ -#define CPU_FEATURE_SCALEFREQ 24 /* CPU supports cpufreq scaling */ -#define CPU_FEATURE_FLATMODE 25 /* CPU has flat mode */ -#define CPU_FEATURE_EIODECODE 26 /* CPU has EXTIOI interrupt pin decode mode */ -#define CPU_FEATURE_GUESTID 27 /* CPU has GuestID feature */ -#define CPU_FEATURE_HYPERVISOR 28 /* CPU has hypervisor (running in VM) */ -#define CPU_FEATURE_PTW 29 /* CPU has hardware page table walker */ -#define CPU_FEATURE_LSPW 30 /* CPU has LSPW (lddir/ldpte instructions) */ -#define CPU_FEATURE_MSGINT 31 /* CPU has MSG interrupt */ -#define CPU_FEATURE_AVECINT 32 /* CPU has AVEC interrupt */ -#define CPU_FEATURE_REDIRECTINT 33 /* CPU has interrupt remapping */ +#define CPU_FEATURE_LAMCAS 3 /* CPU has AMCAS[_DB].{B/H/W/D} instructions */ +#define CPU_FEATURE_SCQ 4 /* CPU has SC.Q instruction */ +#define CPU_FEATURE_UAL 5 /* CPU supports unaligned access */ +#define CPU_FEATURE_FPU 6 /* CPU has FPU */ +#define CPU_FEATURE_LSX 7 /* CPU has LSX (128-bit SIMD) */ +#define CPU_FEATURE_LASX 8 /* CPU has LASX (256-bit SIMD) */ +#define CPU_FEATURE_CRC32 9 /* CPU has CRC32 instructions */ +#define CPU_FEATURE_COMPLEX 10 /* CPU has Complex instructions */ +#define CPU_FEATURE_CRYPTO 11 /* CPU has Crypto instructions */ +#define CPU_FEATURE_DIV32 12 /* CPU has DIV32 feature */ +#define CPU_FEATURE_LVZ 13 /* CPU has Virtualization extension */ +#define CPU_FEATURE_LBT_X86 14 /* CPU has X86 Binary Translation */ +#define CPU_FEATURE_LBT_ARM 15 /* CPU has ARM Binary Translation */ +#define CPU_FEATURE_LBT_MIPS 16 /* CPU has MIPS Binary Translation */ +#define CPU_FEATURE_TLB 17 /* CPU has TLB */ +#define CPU_FEATURE_CSR 18 /* CPU has CSR */ +#define CPU_FEATURE_IOCSR 19 /* CPU has IOCSR */ +#define CPU_FEATURE_WATCH 20 /* CPU has watchpoint registers */ +#define CPU_FEATURE_VINT 21 /* CPU has vectored interrupts */ +#define CPU_FEATURE_CSRIPI 22 /* CPU has CSR-IPI */ +#define CPU_FEATURE_EXTIOI 23 /* CPU has EXT-IOI */ +#define CPU_FEATURE_PREFETCH 24 /* CPU has prefetch instructions */ +#define CPU_FEATURE_PMP 25 /* CPU has perfermance counter */ +#define CPU_FEATURE_SCALEFREQ 26 /* CPU supports cpufreq scaling */ +#define CPU_FEATURE_FLATMODE 27 /* CPU has flat mode */ +#define CPU_FEATURE_EIODECODE 28 /* CPU has EXTIOI interrupt pin decode mode */ +#define CPU_FEATURE_GUESTID 29 /* CPU has GuestID feature */ +#define CPU_FEATURE_HYPERVISOR 30 /* CPU has hypervisor (running in VM) */ +#define CPU_FEATURE_PTW 31 /* CPU has hardware page table walker */ +#define CPU_FEATURE_LSPW 32 /* CPU has LSPW (lddir/ldpte instructions) */ +#define CPU_FEATURE_MSGINT 33 /* CPU has MSG interrupt */ +#define CPU_FEATURE_AVECINT 34 /* CPU has AVEC interrupt */ +#define CPU_FEATURE_REDIRECTINT 35 /* CPU has interrupt remapping */ #define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG) #define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM) #define LOONGARCH_CPU_LAM_BH BIT_ULL(CPU_FEATURE_LAM_BH) +#define LOONGARCH_CPU_LAMCAS BIT_ULL(CPU_FEATURE_LAMCAS) #define LOONGARCH_CPU_SCQ BIT_ULL(CPU_FEATURE_SCQ) #define LOONGARCH_CPU_UAL BIT_ULL(CPU_FEATURE_UAL) #define LOONGARCH_CPU_FPU BIT_ULL(CPU_FEATURE_FPU) @@ -139,6 +142,7 @@ static inline char *id_to_core_name(unsigned int id) #define LOONGARCH_CPU_CRC32 BIT_ULL(CPU_FEATURE_CRC32) #define LOONGARCH_CPU_COMPLEX BIT_ULL(CPU_FEATURE_COMPLEX) #define LOONGARCH_CPU_CRYPTO BIT_ULL(CPU_FEATURE_CRYPTO) +#define LOONGARCH_CPU_DIV32 BIT_ULL(CPU_FEATURE_DIV32) #define LOONGARCH_CPU_LVZ BIT_ULL(CPU_FEATURE_LVZ) #define LOONGARCH_CPU_LBT_X86 BIT_ULL(CPU_FEATURE_LBT_X86) #define LOONGARCH_CPU_LBT_ARM BIT_ULL(CPU_FEATURE_LBT_ARM) diff --git a/arch/loongarch/include/asm/hw_breakpoint.h b/arch/loongarch/include/asm/hw_breakpoint.h index 5faa97a87a9e..f4478936787d 100644 --- a/arch/loongarch/include/asm/hw_breakpoint.h +++ b/arch/loongarch/include/asm/hw_breakpoint.h @@ -116,17 +116,17 @@ extern void arch_uninstall_hw_breakpoint(struct perf_event *bp); extern int hw_breakpoint_slots(int type); extern void hw_breakpoint_pmu_read(struct perf_event *bp); -void breakpoint_handler(struct pt_regs *regs); -void watchpoint_handler(struct pt_regs *regs); +bool breakpoint_handler(struct pt_regs *regs); +bool watchpoint_handler(struct pt_regs *regs); #ifdef CONFIG_HAVE_HW_BREAKPOINT extern void ptrace_hw_copy_thread(struct task_struct *task); -extern void hw_breakpoint_thread_switch(struct task_struct *next); +extern void hw_breakpoint_thread_switch(struct task_struct *prev, struct task_struct *next); #else static inline void ptrace_hw_copy_thread(struct task_struct *task) { } -static inline void hw_breakpoint_thread_switch(struct task_struct *next) +static inline void hw_breakpoint_thread_switch(struct task_struct *prev, struct task_struct *next) { } #endif diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h index 585667e361c2..b55aae325300 100644 --- a/arch/loongarch/include/asm/inst.h +++ b/arch/loongarch/include/asm/inst.h @@ -752,11 +752,17 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \ DEF_EMIT_REG3_FORMAT(addw, addw_op) DEF_EMIT_REG3_FORMAT(addd, addd_op) +DEF_EMIT_REG3_FORMAT(subw, subw_op) DEF_EMIT_REG3_FORMAT(subd, subd_op) +DEF_EMIT_REG3_FORMAT(mulw, mulw_op) DEF_EMIT_REG3_FORMAT(muld, muld_op) +DEF_EMIT_REG3_FORMAT(divw, divw_op) DEF_EMIT_REG3_FORMAT(divd, divd_op) +DEF_EMIT_REG3_FORMAT(modw, modw_op) DEF_EMIT_REG3_FORMAT(modd, modd_op) +DEF_EMIT_REG3_FORMAT(divwu, divwu_op) DEF_EMIT_REG3_FORMAT(divdu, divdu_op) +DEF_EMIT_REG3_FORMAT(modwu, modwu_op) DEF_EMIT_REG3_FORMAT(moddu, moddu_op) DEF_EMIT_REG3_FORMAT(maskeqz, maskeqz_op) DEF_EMIT_REG3_FORMAT(masknez, masknez_op) diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h index 88e3bdfd4971..b26d0e1b2634 100644 --- a/arch/loongarch/include/asm/loongarch.h +++ b/arch/loongarch/include/asm/loongarch.h @@ -1135,8 +1135,11 @@ #define LOONGARCH_CSR_DERA 0x501 /* debug era */ #define LOONGARCH_CSR_DESAVE 0x502 /* debug save */ -#define CSR_FWPC_SKIP_SHIFT 16 -#define CSR_FWPC_SKIP (_ULCAST_(1) << CSR_FWPC_SKIP_SHIFT) +#define CSR_FWPS_SKIP_SHIFT 16 +#define CSR_FWPS_SKIP (_ULCAST_(1) << CSR_FWPS_SKIP_SHIFT) + +#define CSR_MWPS_SKIP_SHIFT 16 +#define CSR_MWPS_SKIP (_ULCAST_(1) << CSR_MWPS_SKIP_SHIFT) /* * CSR_ECFG IM diff --git a/arch/loongarch/include/asm/numa.h b/arch/loongarch/include/asm/numa.h index bbf9f70bd25f..c9654ff900a3 100644 --- a/arch/loongarch/include/asm/numa.h +++ b/arch/loongarch/include/asm/numa.h @@ -14,7 +14,7 @@ #define NODE_ADDRSPACE_SHIFT 44 #define pa_to_nid(addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT) -#define nid_to_addrbase(nid) (_ULCAST_(nid) << NODE_ADDRSPACE_SHIFT) +#define nid_to_addrbase(nid) (_U64CAST_(nid) << NODE_ADDRSPACE_SHIFT) #ifdef CONFIG_NUMA diff --git a/arch/loongarch/include/asm/processor.h b/arch/loongarch/include/asm/processor.h index ce8b953f8c79..a884f964ec98 100644 --- a/arch/loongarch/include/asm/processor.h +++ b/arch/loongarch/include/asm/processor.h @@ -138,6 +138,7 @@ struct thread_struct { struct loongarch_lbt lbt; /* Also conditionally copied */ /* Hardware breakpoints pinned to this task. */ + bool hbp_break_skip, hbp_watch_skip; struct perf_event *hbp_break[LOONGARCH_MAX_BRP]; struct perf_event *hbp_watch[LOONGARCH_MAX_WRP]; }; diff --git a/arch/loongarch/include/asm/switch_to.h b/arch/loongarch/include/asm/switch_to.h index 27acbf913774..ab9e0292c7f3 100644 --- a/arch/loongarch/include/asm/switch_to.h +++ b/arch/loongarch/include/asm/switch_to.h @@ -34,7 +34,7 @@ extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev, do { \ lose_fpu_inatomic(1, prev); \ lose_lbt_inatomic(1, prev); \ - hw_breakpoint_thread_switch(next); \ + hw_breakpoint_thread_switch(prev, next); \ set_current(next); \ (last) = __switch_to(prev, next, \ __builtin_return_address(0), __builtin_frame_address(0)); \ diff --git a/arch/loongarch/include/uapi/asm/hwcap.h b/arch/loongarch/include/uapi/asm/hwcap.h index 90e96113ba51..cc609e3486bc 100644 --- a/arch/loongarch/include/uapi/asm/hwcap.h +++ b/arch/loongarch/include/uapi/asm/hwcap.h @@ -20,5 +20,7 @@ #define HWCAP_LOONGARCH_LSPW (1 << 14) #define HWCAP_LOONGARCH_SCQ (1 << 15) #define HWCAP_LOONGARCH_LAM_BH (1 << 16) +#define HWCAP_LOONGARCH_LAMCAS (1 << 17) +#define HWCAP_LOONGARCH_DIV32 (1 << 18) #endif /* _UAPI_ASM_HWCAP_H */ diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index 001924877772..6260c15adaba 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_RELOCATABLE) += relocate.o obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_efi.o kexec_elf.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c index 7121e7483498..692bf7c85090 100644 --- a/arch/loongarch/kernel/cpu-probe.c +++ b/arch/loongarch/kernel/cpu-probe.c @@ -93,7 +93,7 @@ static int __init cpu_final_simd(void) return 0; } -arch_initcall(cpu_final_simd); +pure_initcall(cpu_final_simd); static inline void set_elf_platform(int cpu, const char *plat) { @@ -182,6 +182,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c) c->options |= LOONGARCH_CPU_LAM_BH; elf_hwcap |= HWCAP_LOONGARCH_LAM_BH; } + if (config & CPUCFG2_LAMCAS) { + c->options |= LOONGARCH_CPU_LAMCAS; + elf_hwcap |= HWCAP_LOONGARCH_LAMCAS; + } if (config & CPUCFG2_SCQ) { c->options |= LOONGARCH_CPU_SCQ; elf_hwcap |= HWCAP_LOONGARCH_SCQ; @@ -210,6 +214,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c) c->options |= LOONGARCH_CPU_CRYPTO; elf_hwcap |= HWCAP_LOONGARCH_CRYPTO; } + if (config & CPUCFG2_DIV32) { + c->options |= LOONGARCH_CPU_DIV32; + elf_hwcap |= HWCAP_LOONGARCH_DIV32; + } if (config & CPUCFG2_PTW) { c->options |= LOONGARCH_CPU_PTW; elf_hwcap |= HWCAP_LOONGARCH_PTW; diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S index 6df56241cb95..c041dad5bbb6 100644 --- a/arch/loongarch/kernel/efi-header.S +++ b/arch/loongarch/kernel/efi-header.S @@ -51,7 +51,7 @@ .long .Lefi_header_end - _head /* SizeOfHeaders */ .long 0 /* CheckSum */ .short IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */ - .short 0 /* DllCharacteristics */ + .short IMAGE_DLLCHARACTERISTICS_NX_COMPAT /* DllCharacteristics */ .quad 0 /* SizeOfStackReserve */ .quad 0 /* SizeOfStackCommit */ .quad 0 /* SizeOfHeapReserve */ diff --git a/arch/loongarch/kernel/env.c b/arch/loongarch/kernel/env.c index 652456768b55..c529a14deb18 100644 --- a/arch/loongarch/kernel/env.c +++ b/arch/loongarch/kernel/env.c @@ -25,10 +25,7 @@ void __init init_environ(void) int efi_boot = fw_arg0; char *cmdline = early_memremap_ro(fw_arg1, COMMAND_LINE_SIZE); - if (efi_boot) - set_bit(EFI_BOOT, &efi.flags); - else - clear_bit(EFI_BOOT, &efi.flags); + assign_bit(EFI_BOOT, &efi.flags, efi_boot); strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE); strscpy(init_command_line, cmdline, COMMAND_LINE_SIZE); diff --git a/arch/loongarch/kernel/hw_breakpoint.c b/arch/loongarch/kernel/hw_breakpoint.c index c35f9bf38033..df149ff06dd5 100644 --- a/arch/loongarch/kernel/hw_breakpoint.c +++ b/arch/loongarch/kernel/hw_breakpoint.c @@ -156,6 +156,9 @@ static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots, void ptrace_hw_copy_thread(struct task_struct *tsk) { + tsk->thread.hbp_break_skip = 0; + tsk->thread.hbp_watch_skip = 0; + memset(tsk->thread.hbp_break, 0, sizeof(tsk->thread.hbp_break)); memset(tsk->thread.hbp_watch, 0, sizeof(tsk->thread.hbp_watch)); } @@ -233,7 +236,7 @@ static int hw_breakpoint_control(struct perf_event *bp, } enable = csr_read64(LOONGARCH_CSR_CRMD); csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD); - if (bp->hw.target && test_tsk_thread_flag(bp->hw.target, TIF_LOAD_WATCH)) + if (bp->hw.target) regs->csr_prmd |= CSR_PRMD_PWE; break; case HW_BREAKPOINT_UNINSTALL: @@ -453,7 +456,6 @@ static void update_bp_registers(struct pt_regs *regs, int enable, int type) if (enable) { if ((info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) && (type == 0)) { write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE); - write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE); } else { ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1); if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD) @@ -469,9 +471,9 @@ static void update_bp_registers(struct pt_regs *regs, int enable, int type) } else { ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1); if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD) - ctrl &= ~0x1 << MWPnCFG3_LoadEn; + ctrl &= ~(0x1 << MWPnCFG3_LoadEn); if (info->ctrl.type == LOONGARCH_BREAKPOINT_STORE) - ctrl &= ~0x1 << MWPnCFG3_StoreEn; + ctrl &= ~(0x1 << MWPnCFG3_StoreEn); write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl); } regs->csr_prmd &= ~CSR_PRMD_PWE; @@ -483,9 +485,11 @@ NOKPROBE_SYMBOL(update_bp_registers); /* * Debug exception handlers. */ -void breakpoint_handler(struct pt_regs *regs) +bool breakpoint_handler(struct pt_regs *regs) { int i; + unsigned int clear_mask = 0; + bool need_sigtrap = false; struct perf_event *bp, **slots; slots = this_cpu_ptr(bp_on_reg); @@ -495,17 +499,27 @@ void breakpoint_handler(struct pt_regs *regs) bp = slots[i]; if (bp == NULL) continue; + perf_bp_event(bp, regs); - csr_write32(0x1 << i, LOONGARCH_CSR_FWPS); - update_bp_registers(regs, 0, 0); + if (bp->attr.sigtrap) + need_sigtrap = true; + + clear_mask |= (0x1 << i); } } + + if (clear_mask) + csr_write32(clear_mask | CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); + + return need_sigtrap; } NOKPROBE_SYMBOL(breakpoint_handler); -void watchpoint_handler(struct pt_regs *regs) +bool watchpoint_handler(struct pt_regs *regs) { int i; + unsigned int clear_mask = 0; + bool need_sigtrap = false; struct perf_event *wp, **slots; slots = this_cpu_ptr(wp_on_reg); @@ -515,11 +529,19 @@ void watchpoint_handler(struct pt_regs *regs) wp = slots[i]; if (wp == NULL) continue; + perf_bp_event(wp, regs); - csr_write32(0x1 << i, LOONGARCH_CSR_MWPS); - update_bp_registers(regs, 0, 1); + if (wp->attr.sigtrap) + need_sigtrap = true; + + clear_mask |= (0x1 << i); } } + + if (clear_mask) + csr_write32(clear_mask | CSR_MWPS_SKIP, LOONGARCH_CSR_MWPS); + + return need_sigtrap; } NOKPROBE_SYMBOL(watchpoint_handler); @@ -542,7 +564,7 @@ static int __init arch_hw_breakpoint_init(void) } arch_initcall(arch_hw_breakpoint_init); -void hw_breakpoint_thread_switch(struct task_struct *next) +void hw_breakpoint_thread_switch(struct task_struct *prev, struct task_struct *next) { u64 addr, mask; struct pt_regs *regs = task_pt_regs(next); @@ -551,9 +573,29 @@ void hw_breakpoint_thread_switch(struct task_struct *next) addr = read_wb_reg(CSR_CFG_ADDR, 0, 0); mask = read_wb_reg(CSR_CFG_MASK, 0, 0); if (!((regs->csr_era ^ addr) & ~mask)) - csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS); + csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); regs->csr_prmd |= CSR_PRMD_PWE; } else { + unsigned int fwps = csr_read32(LOONGARCH_CSR_FWPS); + unsigned int mwps = csr_read32(LOONGARCH_CSR_MWPS); + + prev->thread.hbp_break_skip = !!(fwps & CSR_FWPS_SKIP); + prev->thread.hbp_watch_skip = !!(mwps & CSR_MWPS_SKIP); + + if (!next->thread.hbp_break_skip) + csr_write32(0, LOONGARCH_CSR_FWPS); + else { + csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); + next->thread.hbp_break_skip = 0; + } + + if (!next->thread.hbp_watch_skip) + csr_write32(0, LOONGARCH_CSR_MWPS); + else { + csr_write32(CSR_MWPS_SKIP, LOONGARCH_CSR_MWPS); + next->thread.hbp_watch_skip = 0; + } + /* Update breakpoints */ update_bp_registers(regs, 1, 0); /* Update watchpoints */ diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c index 7bf68a7a5f4b..29e0f2baaa8c 100644 --- a/arch/loongarch/kernel/irq.c +++ b/arch/loongarch/kernel/irq.c @@ -20,6 +20,7 @@ #include <asm/irq.h> #include <asm/loongson.h> +#include <asm/numa.h> #include <asm/setup.h> DEFINE_PER_CPU(unsigned long, irq_stack); @@ -69,7 +70,7 @@ static int __init early_pci_mcfg_parse(struct acpi_table_header *header) for (i = 0; i < n; i++, mptr++) { msi_group[i].pci_segment = mptr->pci_segment; - pch_group[i].node = msi_group[i].node = (mptr->address >> 44) & 0xf; + pch_group[i].node = msi_group[i].node = pa_to_nid(mptr->address); } return 0; diff --git a/arch/loongarch/kernel/numa.c b/arch/loongarch/kernel/numa.c index c96c53623715..7dedc134ddfe 100644 --- a/arch/loongarch/kernel/numa.c +++ b/arch/loongarch/kernel/numa.c @@ -216,6 +216,8 @@ static int __init fake_numa_init(void) phys_addr_t start = memblock_start_of_DRAM(); phys_addr_t end = memblock_end_of_DRAM() - 1; + set_cpuid_to_node(0, 0); + early_numa_add_cpu(0, 0); pr_info("Faking a node at [mem %pap-%pap]\n", &start, &end); return numa_add_memblk(0, start, end + 1); @@ -244,8 +246,10 @@ int __init init_numa_memory(void) return -EINVAL; for_each_node_mask(node, node_possible_map) { - node_mem_init(node); - node_set_online(node); + if (!cpumask_empty(&cpus_on_node[node])) { + node_mem_init(node); + node_set_online(node); + } } max_pfn = PFN_DOWN(memblock_end_of_DRAM()); max_low_pfn = min(PFN_DOWN(HIGHMEM_START), max_pfn); diff --git a/arch/loongarch/kernel/proc.c b/arch/loongarch/kernel/proc.c index d4ce5b585453..37e9b144ec09 100644 --- a/arch/loongarch/kernel/proc.c +++ b/arch/loongarch/kernel/proc.c @@ -66,6 +66,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_puts(m, " lam"); if (cpu_has_lam_bh) seq_puts(m, " lam_bh"); + if (cpu_has_lamcas) + seq_puts(m, " lamcas"); if (cpu_has_scq) seq_puts(m, " scq"); if (cpu_has_ual) @@ -82,6 +84,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_puts(m, " complex"); if (cpu_has_crypto) seq_puts(m, " crypto"); + if (cpu_has_div32) + seq_puts(m, " div32"); if (cpu_has_ptw) seq_puts(m, " ptw"); if (cpu_has_lspw) diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index 776523747ea3..20ce2c8d77a1 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -815,6 +815,8 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs) #ifndef CONFIG_HAVE_HW_BREAKPOINT pr_warn("Hardware watch point handler not implemented!\n"); #else + bool need_sigtrap = !!current->ptrace; + if (kgdb_breakpoint_handler(regs)) goto out; @@ -829,7 +831,7 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs) * instruction. So don't clear llbit and reset CSR.FWPS.Skip until * the llsc execution is completed. */ - csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS); + csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); csr_write32(CSR_LLBCTL_KLO, LOONGARCH_CSR_LLBCTL); goto out; } @@ -846,16 +848,17 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs) * current pc, If yes, then we should not set the CSR.FWPS.SKIP * bit to break the original instruction stream. */ - csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS); + csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); goto out; } } } else { - breakpoint_handler(regs); - watchpoint_handler(regs); + need_sigtrap |= breakpoint_handler(regs); + need_sigtrap |= watchpoint_handler(regs); } - force_sig(SIGTRAP); + if (need_sigtrap) + force_sig(SIGTRAP); out: #endif irqentry_exit(regs, state); diff --git a/arch/loongarch/kernel/vmcore_info.c b/arch/loongarch/kernel/vmcore_info.c new file mode 100644 index 000000000000..e4efc35165b1 --- /dev/null +++ b/arch/loongarch/kernel/vmcore_info.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/vmcore_info.h> +#include <asm/addrspace.h> +#include <asm/pgtable.h> +#include <asm/setup.h> + +void arch_crash_save_vmcoreinfo(void) +{ + VMCOREINFO_NUMBER(VA_BITS); + /* NUMBER(VMALLOC_START) is exported by the generic code */ + vmcoreinfo_append_str("NUMBER(VMALLOC_END)=0x%lx\n", VMALLOC_END); +#ifdef CONFIG_64BIT + vmcoreinfo_append_str("NUMBER(MODULES_VADDR)=0x%lx\n", MODULES_VADDR); + vmcoreinfo_append_str("NUMBER(MODULES_END)=0x%lx\n", MODULES_END); + vmcoreinfo_append_str("NUMBER(VMEMMAP_START)=0x%lx\n", (unsigned long)vmemmap); + vmcoreinfo_append_str("NUMBER(VMEMMAP_END)=0x%lx\n", VMEMMAP_END + 1); +#endif + vmcoreinfo_append_str("NUMBER(PHYS_OFFSET)=0x%lx\n", PHYS_OFFSET); + vmcoreinfo_append_str("NUMBER(PAGE_OFFSET)=0x%lx\n", PAGE_OFFSET); + vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset()); +} diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 9393e4b0db8e..3ab039d0afb6 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -194,7 +194,7 @@ static void build_prologue(struct jit_ctx *ctx) ctx->stack_size = stack_adjust; if (ctx->arena_vm_start) - move_imm(ctx, REG_ARENA, ctx->arena_vm_start, false); + move_imm(ctx, REG_ARENA, ctx->arena_vm_start); } static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call) @@ -288,7 +288,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) * if (index >= array->map.max_entries) * goto out; */ - emit_zext_32(ctx, a2, true); + emit_insn(ctx, bstrpickd, a2, a2, 31, 0); off = offsetof(struct bpf_array, map.max_entries); emit_insn(ctx, ldwu, t1, a1, off); @@ -339,7 +339,7 @@ toofar: static void emit_store_stack_imm64(struct jit_ctx *ctx, int reg, int stack_off, u64 imm64) { - move_imm(ctx, reg, imm64, false); + move_imm(ctx, reg, imm64); emit_insn(ctx, std, reg, LOONGARCH_GPR_FP, stack_off); } @@ -355,7 +355,7 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) const s32 imm = insn->imm; const bool isdw = BPF_SIZE(insn->code) == BPF_DW; - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, addd, t1, dst, t1); move_reg(ctx, t3, src); @@ -412,7 +412,6 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) return -EINVAL; } emit_insn(ctx, amadddbb, src, t1, t3); - emit_zext_32(ctx, src, true); break; case BPF_H: if (!cpu_has_lam_bh) { @@ -420,23 +419,23 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) return -EINVAL; } emit_insn(ctx, amadddbh, src, t1, t3); - emit_zext_32(ctx, src, true); break; case BPF_W: emit_insn(ctx, amadddbw, src, t1, t3); - emit_zext_32(ctx, src, true); break; case BPF_DW: emit_insn(ctx, amadddbd, src, t1, t3); break; } + if (!isdw) + emit_insn(ctx, bstrpickd, src, src, 31, 0); break; case BPF_AND | BPF_FETCH: if (isdw) { emit_insn(ctx, amanddbd, src, t1, t3); } else { emit_insn(ctx, amanddbw, src, t1, t3); - emit_zext_32(ctx, src, true); + emit_insn(ctx, bstrpickd, src, src, 31, 0); } break; case BPF_OR | BPF_FETCH: @@ -444,7 +443,7 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) emit_insn(ctx, amordbd, src, t1, t3); } else { emit_insn(ctx, amordbw, src, t1, t3); - emit_zext_32(ctx, src, true); + emit_insn(ctx, bstrpickd, src, src, 31, 0); } break; case BPF_XOR | BPF_FETCH: @@ -452,7 +451,7 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) emit_insn(ctx, amxordbd, src, t1, t3); } else { emit_insn(ctx, amxordbw, src, t1, t3); - emit_zext_32(ctx, src, true); + emit_insn(ctx, bstrpickd, src, src, 31, 0); } break; /* src = atomic_xchg(dst + off, src); */ @@ -464,7 +463,6 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) return -EINVAL; } emit_insn(ctx, amswapdbb, src, t1, t3); - emit_zext_32(ctx, src, true); break; case BPF_H: if (!cpu_has_lam_bh) { @@ -472,16 +470,16 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) return -EINVAL; } emit_insn(ctx, amswapdbh, src, t1, t3); - emit_zext_32(ctx, src, true); break; case BPF_W: emit_insn(ctx, amswapdbw, src, t1, t3); - emit_zext_32(ctx, src, true); break; case BPF_DW: emit_insn(ctx, amswapdbd, src, t1, t3); break; } + if (!isdw) + emit_insn(ctx, bstrpickd, src, src, 31, 0); break; /* r0 = atomic_cmpxchg(dst + off, r0, src); */ case BPF_CMPXCHG: @@ -494,13 +492,13 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) emit_insn(ctx, beq, t3, LOONGARCH_GPR_ZERO, -4); } else { emit_insn(ctx, llw, r0, t1, 0); - emit_zext_32(ctx, t2, true); - emit_zext_32(ctx, r0, true); + emit_insn(ctx, bstrpickd, t2, t2, 31, 0); + emit_insn(ctx, bstrpickd, r0, r0, 31, 0); emit_insn(ctx, bne, t2, r0, 4); move_reg(ctx, t3, src); emit_insn(ctx, scw, t3, t1, 0); emit_insn(ctx, beq, t3, LOONGARCH_GPR_ZERO, -6); - emit_zext_32(ctx, r0, true); + emit_insn(ctx, bstrpickd, r0, r0, 31, 0); } emit_insn(ctx, dbar, DBAR_LLSC_MB); break; @@ -528,7 +526,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, ldbu, dst, src, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, ldxbu, dst, src, t1); } break; @@ -536,7 +534,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, ldhu, dst, src, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, ldxhu, dst, src, t1); } break; @@ -544,7 +542,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, ldwu, dst, src, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, ldxwu, dst, src, t1); } break; @@ -552,7 +550,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, ldd, dst, src, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, ldxd, dst, src, t1); } break; @@ -567,7 +565,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, stb, src, dst, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, stxb, src, dst, t1); } break; @@ -575,7 +573,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, sth, src, dst, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, stxh, src, dst, t1); } break; @@ -583,7 +581,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, stw, src, dst, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, stxw, src, dst, t1); } break; @@ -591,7 +589,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) if (is_signed_imm12(off)) { emit_insn(ctx, std, src, dst, off); } else { - move_imm(ctx, t1, off, false); + move_imm(ctx, t1, off); emit_insn(ctx, stxd, src, dst, t1); } break; @@ -605,12 +603,6 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) return 0; } -static bool is_signed_bpf_cond(u8 cond) -{ - return cond == BPF_JSGT || cond == BPF_JSLT || - cond == BPF_JSGE || cond == BPF_JSLE; -} - #define BPF_FIXUP_REG_MASK GENMASK(31, 27) #define BPF_FIXUP_OFFSET_MASK GENMASK(26, 0) #define REG_DONT_CLEAR_MARKER 0 @@ -707,7 +699,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext u8 dst = regmap[insn->dst_reg]; const s16 off = insn->off; const s32 imm = insn->imm; - const bool is32 = BPF_CLASS(insn->code) == BPF_ALU || BPF_CLASS(insn->code) == BPF_JMP32; + const bool is32 = BPF_CLASS(insn->code) == BPF_ALU && BPF_OP(insn->code) != BPF_END; switch (code) { /* dst = src */ @@ -715,8 +707,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext case BPF_ALU64 | BPF_MOV | BPF_X: if (insn_is_cast_user(insn)) { move_reg(ctx, t1, src); - emit_zext_32(ctx, t1, true); - move_imm(ctx, dst, (ctx->user_vm_start >> 32) << 32, false); + emit_insn(ctx, bstrpickd, t1, t1, 31, 0); + move_imm(ctx, dst, (ctx->user_vm_start >> 32) << 32); emit_insn(ctx, beq, t1, LOONGARCH_GPR_ZERO, 2); emit_insn(ctx, or, t1, dst, t1); move_reg(ctx, dst, t1); @@ -734,15 +726,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext switch (off) { case 0: move_reg(ctx, dst, src); - emit_zext_32(ctx, dst, is32); break; case 8: emit_insn(ctx, extwb, dst, src); - emit_zext_32(ctx, dst, is32); break; case 16: emit_insn(ctx, extwh, dst, src); - emit_zext_32(ctx, dst, is32); break; case 32: emit_insn(ctx, addw, dst, src, LOONGARCH_GPR_ZERO); @@ -752,145 +741,188 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext /* dst = imm */ case BPF_ALU | BPF_MOV | BPF_K: + move_imm(ctx, dst, (u32)imm); + return 0; case BPF_ALU64 | BPF_MOV | BPF_K: - move_imm(ctx, dst, imm, is32); - break; + move_imm(ctx, dst, imm); + return 0; /* dst = dst + src */ case BPF_ALU | BPF_ADD | BPF_X: + emit_insn(ctx, addw, dst, dst, src); + break; case BPF_ALU64 | BPF_ADD | BPF_X: emit_insn(ctx, addd, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; /* dst = dst + imm */ case BPF_ALU | BPF_ADD | BPF_K: + if (is_signed_imm12(imm)) { + emit_insn(ctx, addiw, dst, dst, imm); + } else { + move_imm(ctx, t1, (u32)imm); + emit_insn(ctx, addw, dst, dst, t1); + } + break; case BPF_ALU64 | BPF_ADD | BPF_K: if (is_signed_imm12(imm)) { emit_insn(ctx, addid, dst, dst, imm); } else { - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); emit_insn(ctx, addd, dst, dst, t1); } - emit_zext_32(ctx, dst, is32); break; /* dst = dst - src */ case BPF_ALU | BPF_SUB | BPF_X: + emit_insn(ctx, subw, dst, dst, src); + break; case BPF_ALU64 | BPF_SUB | BPF_X: emit_insn(ctx, subd, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; /* dst = dst - imm */ case BPF_ALU | BPF_SUB | BPF_K: + if (is_signed_imm12(-imm)) { + emit_insn(ctx, addiw, dst, dst, -imm); + } else { + move_imm(ctx, t1, (u32)imm); + emit_insn(ctx, subw, dst, dst, t1); + } + break; case BPF_ALU64 | BPF_SUB | BPF_K: if (is_signed_imm12(-imm)) { emit_insn(ctx, addid, dst, dst, -imm); } else { - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); emit_insn(ctx, subd, dst, dst, t1); } - emit_zext_32(ctx, dst, is32); break; /* dst = dst * src */ case BPF_ALU | BPF_MUL | BPF_X: + emit_insn(ctx, mulw, dst, dst, src); + break; case BPF_ALU64 | BPF_MUL | BPF_X: emit_insn(ctx, muld, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; /* dst = dst * imm */ case BPF_ALU | BPF_MUL | BPF_K: + move_imm(ctx, t1, (u32)imm); + emit_insn(ctx, mulw, dst, dst, t1); + break; case BPF_ALU64 | BPF_MUL | BPF_K: - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); emit_insn(ctx, muld, dst, dst, t1); - emit_zext_32(ctx, dst, is32); break; /* dst = dst / src */ case BPF_ALU | BPF_DIV | BPF_X: - case BPF_ALU64 | BPF_DIV | BPF_X: - if (!off) { - emit_zext_32(ctx, dst, is32); - move_reg(ctx, t1, src); - emit_zext_32(ctx, t1, is32); - emit_insn(ctx, divdu, dst, dst, t1); - emit_zext_32(ctx, dst, is32); - } else { - emit_sext_32(ctx, dst, is32); - move_reg(ctx, t1, src); - emit_sext_32(ctx, t1, is32); - emit_insn(ctx, divd, dst, dst, t1); - emit_zext_32(ctx, dst, is32); + if (cpu_has_div32) { + if (!off) + emit_insn(ctx, divwu, dst, dst, src); + else + emit_insn(ctx, divw, dst, dst, src); + break; } + /* + * Legacy fallback for !div32: src must be extended into a + * temporary register to keep the original src register intact. + */ + emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO); + emit_insn(ctx, addw, t1, src, LOONGARCH_GPR_ZERO); + if (!off) + emit_insn(ctx, divwu, dst, dst, t1); + else + emit_insn(ctx, divw, dst, dst, t1); + break; + case BPF_ALU64 | BPF_DIV | BPF_X: + if (!off) + emit_insn(ctx, divdu, dst, dst, src); + else + emit_insn(ctx, divd, dst, dst, src); break; /* dst = dst / imm */ case BPF_ALU | BPF_DIV | BPF_K: + move_imm(ctx, t1, (u32)imm); + if (!cpu_has_div32) { + emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO); + emit_insn(ctx, addw, t1, t1, LOONGARCH_GPR_ZERO); + } + if (!off) + emit_insn(ctx, divwu, dst, dst, t1); + else + emit_insn(ctx, divw, dst, dst, t1); + break; case BPF_ALU64 | BPF_DIV | BPF_K: - if (!off) { - move_imm(ctx, t1, imm, is32); - emit_zext_32(ctx, dst, is32); + move_imm(ctx, t1, imm); + if (!off) emit_insn(ctx, divdu, dst, dst, t1); - emit_zext_32(ctx, dst, is32); - } else { - move_imm(ctx, t1, imm, false); - emit_sext_32(ctx, t1, is32); - emit_sext_32(ctx, dst, is32); + else emit_insn(ctx, divd, dst, dst, t1); - emit_zext_32(ctx, dst, is32); - } break; /* dst = dst % src */ case BPF_ALU | BPF_MOD | BPF_X: - case BPF_ALU64 | BPF_MOD | BPF_X: - if (!off) { - emit_zext_32(ctx, dst, is32); - move_reg(ctx, t1, src); - emit_zext_32(ctx, t1, is32); - emit_insn(ctx, moddu, dst, dst, t1); - emit_zext_32(ctx, dst, is32); - } else { - emit_sext_32(ctx, dst, is32); - move_reg(ctx, t1, src); - emit_sext_32(ctx, t1, is32); - emit_insn(ctx, modd, dst, dst, t1); - emit_zext_32(ctx, dst, is32); + if (cpu_has_div32) { + if (!off) + emit_insn(ctx, modwu, dst, dst, src); + else + emit_insn(ctx, modw, dst, dst, src); + break; } + /* + * Legacy fallback for !div32: src must be extended into a + * temporary register to keep the original src register intact. + */ + emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO); + emit_insn(ctx, addw, t1, src, LOONGARCH_GPR_ZERO); + if (!off) + emit_insn(ctx, modwu, dst, dst, t1); + else + emit_insn(ctx, modw, dst, dst, t1); + break; + case BPF_ALU64 | BPF_MOD | BPF_X: + if (!off) + emit_insn(ctx, moddu, dst, dst, src); + else + emit_insn(ctx, modd, dst, dst, src); break; /* dst = dst % imm */ case BPF_ALU | BPF_MOD | BPF_K: + move_imm(ctx, t1, (u32)imm); + if (!cpu_has_div32) { + emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO); + emit_insn(ctx, addw, t1, t1, LOONGARCH_GPR_ZERO); + } + if (!off) + emit_insn(ctx, modwu, dst, dst, t1); + else + emit_insn(ctx, modw, dst, dst, t1); + break; case BPF_ALU64 | BPF_MOD | BPF_K: - if (!off) { - move_imm(ctx, t1, imm, is32); - emit_zext_32(ctx, dst, is32); + move_imm(ctx, t1, imm); + if (!off) emit_insn(ctx, moddu, dst, dst, t1); - emit_zext_32(ctx, dst, is32); - } else { - move_imm(ctx, t1, imm, false); - emit_sext_32(ctx, t1, is32); - emit_sext_32(ctx, dst, is32); + else emit_insn(ctx, modd, dst, dst, t1); - emit_zext_32(ctx, dst, is32); - } break; /* dst = -dst */ case BPF_ALU | BPF_NEG: + emit_insn(ctx, subw, dst, LOONGARCH_GPR_ZERO, dst); + break; case BPF_ALU64 | BPF_NEG: emit_insn(ctx, subd, dst, LOONGARCH_GPR_ZERO, dst); - emit_zext_32(ctx, dst, is32); break; /* dst = dst & src */ case BPF_ALU | BPF_AND | BPF_X: case BPF_ALU64 | BPF_AND | BPF_X: emit_insn(ctx, and, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; /* dst = dst & imm */ @@ -899,17 +931,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext if (is_unsigned_imm12(imm)) { emit_insn(ctx, andi, dst, dst, imm); } else { - move_imm(ctx, t1, imm, is32); + if (is32) + move_imm(ctx, t1, (u32)imm); + else + move_imm(ctx, t1, imm); emit_insn(ctx, and, dst, dst, t1); } - emit_zext_32(ctx, dst, is32); break; /* dst = dst | src */ case BPF_ALU | BPF_OR | BPF_X: case BPF_ALU64 | BPF_OR | BPF_X: emit_insn(ctx, or, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; /* dst = dst | imm */ @@ -918,17 +951,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext if (is_unsigned_imm12(imm)) { emit_insn(ctx, ori, dst, dst, imm); } else { - move_imm(ctx, t1, imm, is32); + if (is32) + move_imm(ctx, t1, (u32)imm); + else + move_imm(ctx, t1, imm); emit_insn(ctx, or, dst, dst, t1); } - emit_zext_32(ctx, dst, is32); break; /* dst = dst ^ src */ case BPF_ALU | BPF_XOR | BPF_X: case BPF_ALU64 | BPF_XOR | BPF_X: emit_insn(ctx, xor, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; /* dst = dst ^ imm */ @@ -937,18 +971,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext if (is_unsigned_imm12(imm)) { emit_insn(ctx, xori, dst, dst, imm); } else { - move_imm(ctx, t1, imm, is32); + if (is32) + move_imm(ctx, t1, (u32)imm); + else + move_imm(ctx, t1, imm); emit_insn(ctx, xor, dst, dst, t1); } - emit_zext_32(ctx, dst, is32); break; /* dst = dst << src (logical) */ case BPF_ALU | BPF_LSH | BPF_X: emit_insn(ctx, sllw, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; - case BPF_ALU64 | BPF_LSH | BPF_X: emit_insn(ctx, slld, dst, dst, src); break; @@ -956,9 +990,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext /* dst = dst << imm (logical) */ case BPF_ALU | BPF_LSH | BPF_K: emit_insn(ctx, slliw, dst, dst, imm); - emit_zext_32(ctx, dst, is32); break; - case BPF_ALU64 | BPF_LSH | BPF_K: emit_insn(ctx, sllid, dst, dst, imm); break; @@ -966,9 +998,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext /* dst = dst >> src (logical) */ case BPF_ALU | BPF_RSH | BPF_X: emit_insn(ctx, srlw, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; - case BPF_ALU64 | BPF_RSH | BPF_X: emit_insn(ctx, srld, dst, dst, src); break; @@ -976,9 +1006,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext /* dst = dst >> imm (logical) */ case BPF_ALU | BPF_RSH | BPF_K: emit_insn(ctx, srliw, dst, dst, imm); - emit_zext_32(ctx, dst, is32); break; - case BPF_ALU64 | BPF_RSH | BPF_K: emit_insn(ctx, srlid, dst, dst, imm); break; @@ -986,9 +1014,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext /* dst = dst >> src (arithmetic) */ case BPF_ALU | BPF_ARSH | BPF_X: emit_insn(ctx, sraw, dst, dst, src); - emit_zext_32(ctx, dst, is32); break; - case BPF_ALU64 | BPF_ARSH | BPF_X: emit_insn(ctx, srad, dst, dst, src); break; @@ -996,9 +1022,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext /* dst = dst >> imm (arithmetic) */ case BPF_ALU | BPF_ARSH | BPF_K: emit_insn(ctx, sraiw, dst, dst, imm); - emit_zext_32(ctx, dst, is32); break; - case BPF_ALU64 | BPF_ARSH | BPF_K: emit_insn(ctx, sraid, dst, dst, imm); break; @@ -1007,12 +1031,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext case BPF_ALU | BPF_END | BPF_FROM_LE: switch (imm) { case 16: - /* zero-extend 16 bits into 64 bits */ emit_insn(ctx, bstrpickd, dst, dst, 15, 0); break; case 32: - /* zero-extend 32 bits into 64 bits */ - emit_zext_32(ctx, dst, is32); + emit_insn(ctx, bstrpickd, dst, dst, 31, 0); break; case 64: /* do nothing */ @@ -1025,13 +1047,11 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext switch (imm) { case 16: emit_insn(ctx, revb2h, dst, dst); - /* zero-extend 16 bits into 64 bits */ emit_insn(ctx, bstrpickd, dst, dst, 15, 0); break; case 32: emit_insn(ctx, revb2w, dst, dst); - /* clear the upper 32 bits */ - emit_zext_32(ctx, dst, true); + emit_insn(ctx, bstrpickd, dst, dst, 31, 0); break; case 64: emit_insn(ctx, revbd, dst, dst); @@ -1039,7 +1059,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext } break; - /* PC += off if dst cond src */ + /* PC += off if dst cond src (64-bit) */ case BPF_JMP | BPF_JEQ | BPF_X: case BPF_JMP | BPF_JNE | BPF_X: case BPF_JMP | BPF_JGT | BPF_X: @@ -1050,31 +1070,38 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext case BPF_JMP | BPF_JSGE | BPF_X: case BPF_JMP | BPF_JSLT | BPF_X: case BPF_JMP | BPF_JSLE | BPF_X: + jmp_offset = bpf2la_offset(i, off, ctx); + if (emit_cond_jmp(ctx, cond, dst, src, jmp_offset) < 0) + goto toofar; + break; + + /* PC += off if dst cond src (32-bit unsigned) */ case BPF_JMP32 | BPF_JEQ | BPF_X: case BPF_JMP32 | BPF_JNE | BPF_X: case BPF_JMP32 | BPF_JGT | BPF_X: case BPF_JMP32 | BPF_JGE | BPF_X: case BPF_JMP32 | BPF_JLT | BPF_X: case BPF_JMP32 | BPF_JLE | BPF_X: + jmp_offset = bpf2la_offset(i, off, ctx); + emit_insn(ctx, bstrpickd, t1, dst, 31, 0); + emit_insn(ctx, bstrpickd, t2, src, 31, 0); + if (emit_cond_jmp(ctx, cond, t1, t2, jmp_offset) < 0) + goto toofar; + break; + + /* PC += off if dst cond src (32-bit signed) */ case BPF_JMP32 | BPF_JSGT | BPF_X: case BPF_JMP32 | BPF_JSGE | BPF_X: case BPF_JMP32 | BPF_JSLT | BPF_X: case BPF_JMP32 | BPF_JSLE | BPF_X: jmp_offset = bpf2la_offset(i, off, ctx); - move_reg(ctx, t1, dst); - move_reg(ctx, t2, src); - if (is_signed_bpf_cond(BPF_OP(code))) { - emit_sext_32(ctx, t1, is32); - emit_sext_32(ctx, t2, is32); - } else { - emit_zext_32(ctx, t1, is32); - emit_zext_32(ctx, t2, is32); - } + emit_insn(ctx, addw, t1, dst, LOONGARCH_GPR_ZERO); + emit_insn(ctx, addw, t2, src, LOONGARCH_GPR_ZERO); if (emit_cond_jmp(ctx, cond, t1, t2, jmp_offset) < 0) goto toofar; break; - /* PC += off if dst cond imm */ + /* PC += off if dst cond imm (64-bit) */ case BPF_JMP | BPF_JEQ | BPF_K: case BPF_JMP | BPF_JNE | BPF_K: case BPF_JMP | BPF_JGT | BPF_K: @@ -1085,32 +1112,51 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext case BPF_JMP | BPF_JSGE | BPF_K: case BPF_JMP | BPF_JSLT | BPF_K: case BPF_JMP | BPF_JSLE | BPF_K: + jmp_offset = bpf2la_offset(i, off, ctx); + if (imm) { + move_imm(ctx, t1, imm); + tm = t1; + } else { + tm = LOONGARCH_GPR_ZERO; + } + if (emit_cond_jmp(ctx, cond, dst, tm, jmp_offset) < 0) + goto toofar; + break; + + /* PC += off if dst cond imm (32-bit unsigned) */ case BPF_JMP32 | BPF_JEQ | BPF_K: case BPF_JMP32 | BPF_JNE | BPF_K: case BPF_JMP32 | BPF_JGT | BPF_K: case BPF_JMP32 | BPF_JGE | BPF_K: case BPF_JMP32 | BPF_JLT | BPF_K: case BPF_JMP32 | BPF_JLE | BPF_K: + jmp_offset = bpf2la_offset(i, off, ctx); + if (imm) { + move_imm(ctx, t1, imm); + emit_insn(ctx, bstrpickd, t1, t1, 31, 0); + tm = t1; + } else { + tm = LOONGARCH_GPR_ZERO; + } + emit_insn(ctx, bstrpickd, t2, dst, 31, 0); + if (emit_cond_jmp(ctx, cond, t2, tm, jmp_offset) < 0) + goto toofar; + break; + + /* PC += off if dst cond imm (32-bit signed) */ case BPF_JMP32 | BPF_JSGT | BPF_K: case BPF_JMP32 | BPF_JSGE | BPF_K: case BPF_JMP32 | BPF_JSLT | BPF_K: case BPF_JMP32 | BPF_JSLE | BPF_K: jmp_offset = bpf2la_offset(i, off, ctx); if (imm) { - move_imm(ctx, t1, imm, false); + move_imm(ctx, t1, imm); + emit_insn(ctx, addw, t1, t1, LOONGARCH_GPR_ZERO); tm = t1; } else { - /* If imm is 0, simply use zero register. */ tm = LOONGARCH_GPR_ZERO; } - move_reg(ctx, t2, dst); - if (is_signed_bpf_cond(BPF_OP(code))) { - emit_sext_32(ctx, tm, is32); - emit_sext_32(ctx, t2, is32); - } else { - emit_zext_32(ctx, tm, is32); - emit_zext_32(ctx, t2, is32); - } + emit_insn(ctx, addw, t2, dst, LOONGARCH_GPR_ZERO); if (emit_cond_jmp(ctx, cond, t2, tm, jmp_offset) < 0) goto toofar; break; @@ -1120,7 +1166,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext case BPF_JMP32 | BPF_JSET | BPF_X: jmp_offset = bpf2la_offset(i, off, ctx); emit_insn(ctx, and, t1, dst, src); - emit_zext_32(ctx, t1, is32); + if (BPF_CLASS(code) == BPF_JMP32) + emit_insn(ctx, bstrpickd, t1, t1, 31, 0); if (emit_cond_jmp(ctx, cond, t1, LOONGARCH_GPR_ZERO, jmp_offset) < 0) goto toofar; break; @@ -1129,9 +1176,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext case BPF_JMP | BPF_JSET | BPF_K: case BPF_JMP32 | BPF_JSET | BPF_K: jmp_offset = bpf2la_offset(i, off, ctx); - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); emit_insn(ctx, and, t1, dst, t1); - emit_zext_32(ctx, t1, is32); + if (BPF_CLASS(code) == BPF_JMP32) + emit_insn(ctx, bstrpickd, t1, t1, 31, 0); if (emit_cond_jmp(ctx, cond, t1, LOONGARCH_GPR_ZERO, jmp_offset) < 0) goto toofar; break; @@ -1227,7 +1275,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext if (bpf_pseudo_func(insn)) move_addr(ctx, dst, imm64); else - move_imm(ctx, dst, imm64, is32); + move_imm(ctx, dst, imm64); return 1; } @@ -1268,7 +1316,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext else emit_insn(ctx, ldbu, dst, src, off); } else { - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); if (sign_extend) emit_insn(ctx, ldxb, dst, src, t1); else @@ -1282,7 +1330,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext else emit_insn(ctx, ldhu, dst, src, off); } else { - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); if (sign_extend) emit_insn(ctx, ldxh, dst, src, t1); else @@ -1296,7 +1344,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext else emit_insn(ctx, ldwu, dst, src, off); } else { - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); if (sign_extend) emit_insn(ctx, ldxw, dst, src, t1); else @@ -1304,7 +1352,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext } break; case BPF_DW: - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); emit_insn(ctx, ldxd, dst, src, t1); break; } @@ -1331,42 +1379,42 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext switch (BPF_SIZE(code)) { case BPF_B: - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); if (is_signed_imm12(off)) { emit_insn(ctx, stb, t1, dst, off); } else { - move_imm(ctx, t2, off, is32); + move_imm(ctx, t2, off); emit_insn(ctx, stxb, t1, dst, t2); } break; case BPF_H: - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); if (is_signed_imm12(off)) { emit_insn(ctx, sth, t1, dst, off); } else { - move_imm(ctx, t2, off, is32); + move_imm(ctx, t2, off); emit_insn(ctx, stxh, t1, dst, t2); } break; case BPF_W: - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); if (is_signed_imm12(off)) { emit_insn(ctx, stw, t1, dst, off); } else if (is_signed_imm14(off)) { emit_insn(ctx, stptrw, t1, dst, off); } else { - move_imm(ctx, t2, off, is32); + move_imm(ctx, t2, off); emit_insn(ctx, stxw, t1, dst, t2); } break; case BPF_DW: - move_imm(ctx, t1, imm, is32); + move_imm(ctx, t1, imm); if (is_signed_imm12(off)) { emit_insn(ctx, std, t1, dst, off); } else if (is_signed_imm14(off)) { emit_insn(ctx, stptrd, t1, dst, off); } else { - move_imm(ctx, t2, off, is32); + move_imm(ctx, t2, off); emit_insn(ctx, stxd, t1, dst, t2); } break; @@ -1397,7 +1445,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext if (is_signed_imm12(off)) { emit_insn(ctx, stb, src, dst, off); } else { - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); emit_insn(ctx, stxb, src, dst, t1); } break; @@ -1405,7 +1453,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext if (is_signed_imm12(off)) { emit_insn(ctx, sth, src, dst, off); } else { - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); emit_insn(ctx, stxh, src, dst, t1); } break; @@ -1415,7 +1463,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext } else if (is_signed_imm14(off)) { emit_insn(ctx, stptrw, src, dst, off); } else { - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); emit_insn(ctx, stxw, src, dst, t1); } break; @@ -1425,7 +1473,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext } else if (is_signed_imm14(off)) { emit_insn(ctx, stptrd, src, dst, off); } else { - move_imm(ctx, t1, off, is32); + move_imm(ctx, t1, off); emit_insn(ctx, stxd, src, dst, t1); } break; @@ -1458,6 +1506,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext return -EINVAL; } + if (is32) + emit_insn(ctx, bstrpickd, dst, dst, 31, 0); + return 0; toofar: @@ -1537,7 +1588,7 @@ static int emit_jump_and_link(struct jit_ctx *ctx, u8 rd, u64 target) return -EFAULT; } - move_imm(ctx, LOONGARCH_GPR_T1, target, false); + move_imm(ctx, LOONGARCH_GPR_T1, target); emit_insn(ctx, jirl, rd, LOONGARCH_GPR_T1, 0); return 0; @@ -1674,17 +1725,17 @@ int bpf_arch_text_invalidate(void *dst, size_t len) return ret; } -static void store_args(struct jit_ctx *ctx, int nr_arg_slots, int args_off) +static void store_args(struct jit_ctx *ctx, int nr_arg_slots, int args_off, bool is_struct_ops) { int i; + int stack_args_off = is_struct_ops ? 0 : 16; for (i = 0; i < nr_arg_slots; i++) { if (i < LOONGARCH_MAX_REG_ARGS) emit_insn(ctx, std, LOONGARCH_GPR_A0 + i, LOONGARCH_GPR_FP, -args_off); else { - /* Skip slots for T0 and FP of traced function */ emit_insn(ctx, ldd, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, - 16 + (i - LOONGARCH_MAX_REG_ARGS) * 8); + stack_args_off + (i - LOONGARCH_MAX_REG_ARGS) * 8); emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -args_off); } args_off -= 8; @@ -1734,7 +1785,7 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im, emit_insn(ctx, std, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_FP, -run_ctx_off + cookie_off); /* arg1: prog */ - move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p, false); + move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p); /* arg2: &run_ctx */ emit_insn(ctx, addid, LOONGARCH_GPR_A1, LOONGARCH_GPR_FP, -run_ctx_off); ret = emit_call(ctx, (const u64)bpf_trampoline_enter(p)); @@ -1755,7 +1806,7 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im, /* arg1: &args_off */ emit_insn(ctx, addid, LOONGARCH_GPR_A0, LOONGARCH_GPR_FP, -args_off); if (!p->jited) - move_imm(ctx, LOONGARCH_GPR_A1, (const s64)p->insnsi, false); + move_imm(ctx, LOONGARCH_GPR_A1, (const s64)p->insnsi); ret = emit_call(ctx, (const u64)p->bpf_func); if (ret) return ret; @@ -1772,7 +1823,7 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im, } /* arg1: prog */ - move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p, false); + move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p); /* arg2: prog start time */ move_reg(ctx, LOONGARCH_GPR_A1, LOONGARCH_GPR_S1); /* arg3: &run_ctx */ @@ -2017,7 +2068,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i func_meta = nr_arg_slots; emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -func_meta_off, func_meta); - store_args(ctx, nr_arg_slots, args_off); + store_args(ctx, nr_arg_slots, args_off, is_struct_ops); if (bpf_fsession_cnt(tnodes)) { /* clear all session cookies' value */ diff --git a/arch/loongarch/net/bpf_jit.h b/arch/loongarch/net/bpf_jit.h index bb58c42c2f2a..2bd0dc5b911c 100644 --- a/arch/loongarch/net/bpf_jit.h +++ b/arch/loongarch/net/bpf_jit.h @@ -72,24 +72,6 @@ static inline int epilogue_offset(const struct jit_ctx *ctx) return (to - from); } -/* Zero-extend 32 bits into 64 bits */ -static inline void emit_zext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, bool is32) -{ - if (!is32) - return; - - emit_insn(ctx, lu32id, reg, 0); -} - -/* Signed-extend 32 bits into 64 bits */ -static inline void emit_sext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, bool is32) -{ - if (!is32) - return; - - emit_insn(ctx, addiw, reg, reg, 0); -} - /* Emit proper extension according to ABI requirements. * Note that it requires a value of size `size` already resides in register `reg`. */ @@ -137,7 +119,7 @@ static inline void move_addr(struct jit_ctx *ctx, enum loongarch_gpr rd, u64 add emit_insn(ctx, lu52id, rd, rd, imm_63_52); } -static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm, bool is32) +static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm) { long imm_11_0, imm_31_12, imm_51_32, imm_63_52, imm_51_0, imm_51_31; @@ -150,7 +132,7 @@ static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm /* addiw rd, $zero, imm_11_0 */ if (is_signed_imm12(imm)) { emit_insn(ctx, addiw, rd, LOONGARCH_GPR_ZERO, imm); - goto zext; + return; } /* ori rd, $zero, imm_11_0 */ @@ -195,9 +177,6 @@ static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm if (!is_signed_imm52(imm)) emit_insn(ctx, lu52id, rd, rd, imm_63_52); } - -zext: - emit_zext_32(ctx, rd, is32); } static inline void move_reg(struct jit_ctx *ctx, enum loongarch_gpr rd, diff --git a/arch/loongarch/pci/pci.c b/arch/loongarch/pci/pci.c index f33c7ea1443d..0b99b32110a5 100644 --- a/arch/loongarch/pci/pci.c +++ b/arch/loongarch/pci/pci.c @@ -12,6 +12,7 @@ #include <linux/io-64-nonatomic-lo-hi.h> #include <asm/cacheflush.h> #include <asm/loongson.h> +#include <asm/numa.h> #define PCI_DEVICE_ID_LOONGSON_HOST 0x7a00 #define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06 @@ -43,7 +44,7 @@ int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, phys_addr_t mcfg_addr_init(int node) { - return (((u64)node << 44) | MCFG_EXT_PCICFG_BASE); + return (nid_to_addrbase(node) | MCFG_EXT_PCICFG_BASE); } static int __init pcibios_init(void) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index cc1e58fa664b..fa3eb52b22cd 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -550,6 +550,10 @@ if ARM64 source "drivers/acpi/arm64/Kconfig" endif +if LOONGARCH +source "drivers/acpi/loongarch/Kconfig" +endif + if RISCV source "drivers/acpi/riscv/Kconfig" endif diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d1b0affb844f..91584a3c1e01 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -131,6 +131,6 @@ obj-y += dptf/ obj-$(CONFIG_ARM64) += arm64/ obj-$(CONFIG_ACPI_VIOT) += viot.o - +obj-$(CONFIG_LOONGARCH) += loongarch/ obj-$(CONFIG_RISCV) += riscv/ obj-$(CONFIG_X86) += x86/ diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d5d234dfa9a2..1d6867dec925 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1449,6 +1449,7 @@ struct kobject *acpi_kobj; EXPORT_SYMBOL_GPL(acpi_kobj); void __weak __init acpi_arch_init(void) { } +void __weak __init acpi_arch_late_init(void) { } static int __init acpi_init(void) { @@ -1487,6 +1488,7 @@ static int __init acpi_init(void) acpi_wakeup_device_init(); acpi_debugger_init(); acpi_setup_sb_notify_handler(); + acpi_arch_late_init(); acpi_viot_init(); return 0; } diff --git a/drivers/acpi/loongarch/Kconfig b/drivers/acpi/loongarch/Kconfig new file mode 100644 index 000000000000..91ba3c35b9bf --- /dev/null +++ b/drivers/acpi/loongarch/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# ACPI Configuration for LOONGARCH +# + +config ACPI_IOVT + bool diff --git a/drivers/acpi/loongarch/Makefile b/drivers/acpi/loongarch/Makefile new file mode 100644 index 000000000000..d0cb177294a6 --- /dev/null +++ b/drivers/acpi/loongarch/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += init.o +obj-$(CONFIG_ACPI_IOVT) += iovt.o diff --git a/drivers/acpi/loongarch/init.c b/drivers/acpi/loongarch/init.c new file mode 100644 index 000000000000..e7272ee197c7 --- /dev/null +++ b/drivers/acpi/loongarch/init.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/acpi.h> +#include "init.h" + +void __init acpi_arch_init(void) +{ + if (IS_ENABLED(CONFIG_ACPI_IOVT)) + acpi_iovt_init(); +} + +void __init acpi_arch_late_init(void) +{ + if (IS_ENABLED(CONFIG_ACPI_IOVT)) + acpi_iovt_late_init(); +} diff --git a/drivers/acpi/loongarch/init.h b/drivers/acpi/loongarch/init.h new file mode 100644 index 000000000000..85e5197553ad --- /dev/null +++ b/drivers/acpi/loongarch/init.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <linux/init.h> + +void __init acpi_iovt_init(void); +void __init acpi_iovt_late_init(void); diff --git a/drivers/acpi/loongarch/iovt.c b/drivers/acpi/loongarch/iovt.c new file mode 100644 index 000000000000..87cee4f0fc80 --- /dev/null +++ b/drivers/acpi/loongarch/iovt.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/acpi.h> +#include <linux/acpi_iovt.h> +#include <linux/pci.h> +#include "init.h" + +struct iovt_device_entry { + struct list_head list; + int start_devid, end_devid; +}; + +struct iovt_fwnode { + struct list_head list; + struct fwnode_handle *fwnode; + int flag; + int nid, segment, devid; + struct list_head ep_list; +}; + +static LIST_HEAD(iovt_fwnode_list); +static DEFINE_SPINLOCK(iovt_fwnode_lock); + +#ifdef CONFIG_PCI +static void __init iovt_enable_acs(struct acpi_iovt_iommu *iommu) +{ + static bool acs_enabled __initdata; + + if (acs_enabled) + return; + + /* IOMMU V1 only supports PCI device management */ + if ((iommu->header.type == ACPI_IOVT_IOMMU_V1) || + (iommu->flags & (ACPI_IOVT_IOMMU_PCI_DEVICE | ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT))) { + pci_request_acs(); + acs_enabled = true; + } +} +#else +static inline void iovt_enable_acs(struct acpi_iovt_iommu *iommu) { } +#endif + +static int __init iovt_get_pci_iommu_fwnode(struct iovt_fwnode *np, u16 segment, u16 bdf) +{ + struct pci_dev *pdev; + struct fwnode_handle *fwnode; + + pdev = pci_get_domain_bus_and_slot(segment, PCI_BUS_NUM(bdf), bdf & 0xff); + if (!pdev) { + pr_err("No PCI IOMMU found for segment 0x%x bdf 0x%x\n", segment, bdf); + return -ENODEV; + } + + fwnode = dev_fwnode(&pdev->dev); + if (!fwnode) { + /* + * PCI devices aren't necessarily described by ACPI. Create + * a fwnode so the IOMMU subsystem can identify this device. + */ + fwnode = acpi_alloc_fwnode_static(); + if (!fwnode) { + pci_dev_put(pdev); + return -ENOMEM; + } + set_primary_fwnode(&pdev->dev, fwnode); + } + + np->fwnode = dev_fwnode(&pdev->dev); + if (np->flag & ACPI_IOVT_IOMMU_PXM_VALID) + set_dev_node(&pdev->dev, np->nid); + pci_dev_put(pdev); + + return 0; +} + +static int __init iovt_add_iommu(struct acpi_iovt_iommu *iommu) +{ + int i, ret; + bool is_start = false; + struct iovt_fwnode *np; + struct iovt_device_entry *entry; + struct acpi_iovt_device_entry *ep; + + np = kzalloc_obj(struct iovt_fwnode, GFP_ATOMIC); + if (WARN_ON(!np)) + return -ENOMEM; + + INIT_LIST_HEAD(&np->list); + np->flag = iommu->flags; + np->segment = iommu->segment; + if (np->flag & ACPI_IOVT_IOMMU_PXM_VALID) + np->nid = pxm_to_node(iommu->proximity_domain); + + if (np->flag & ACPI_IOVT_IOMMU_PCI_DEVICE) { + np->devid = iommu->device_id; + ret = iovt_get_pci_iommu_fwnode(np, np->segment, np->devid); + if (ret < 0) { + kfree(np); + return ret; + } + } else { + np->fwnode = acpi_alloc_fwnode_static(); + if (!np->fwnode) { + kfree(np); + return -ENOMEM; + } + } + + /* All devices in the segment are managed by this IOMMU */ + if (np->flag & ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT) + goto skip; + + INIT_LIST_HEAD(&np->ep_list); + ep = ACPI_ADD_PTR(struct acpi_iovt_device_entry, iommu, iommu->device_entry_offset); + for (i = 0; i < iommu->device_entry_num; i++) { + switch (ep->type) { + case ACPI_IOVT_DEVICE_ENTRY_START: + is_start = true; + entry->start_devid = ep->device_id; + break; + case ACPI_IOVT_DEVICE_ENTRY_END: + if (!is_start) + break; + + entry = kzalloc_obj(struct iovt_device_entry, GFP_ATOMIC); + if (!entry) + return -ENOMEM; + + is_start = false; + entry->end_devid = ep->device_id; + list_add_tail(&entry->list, &np->ep_list); + break; + case ACPI_IOVT_DEVICE_ENTRY_SINGLE: + entry = kzalloc_obj(struct iovt_device_entry, GFP_ATOMIC); + if (!entry) + return -ENOMEM; + + is_start = false; + entry->start_devid = ep->device_id; + entry->end_devid = ep->device_id; + list_add_tail(&entry->list, &np->ep_list); + break; + default: + break; + } + ep = ACPI_ADD_PTR(struct acpi_iovt_device_entry, ep, ep->length); + } + +skip: + spin_lock(&iovt_fwnode_lock); + list_add_tail(&np->list, &iovt_fwnode_list); + spin_unlock(&iovt_fwnode_lock); + return 0; +} + +static void __init iovt_init_devices(struct acpi_table_header *header) +{ + int i; + struct acpi_table_iovt *iovt; + struct acpi_iovt_iommu *iommu; + + /* Get the first IOVT node */ + iovt = (struct acpi_table_iovt *)header; + iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iovt, iovt->iommu_offset); + for (i = 0; i < iovt->iommu_count; i++) { + iovt_add_iommu(iommu); + iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iommu, iommu->header.length); + } +} + +void __init acpi_iovt_init(void) +{ + int i; + acpi_status status; + struct acpi_table_header *hdr; + struct acpi_table_iovt *iovt; + struct acpi_iovt_iommu *iommu; + + status = acpi_get_table(ACPI_SIG_IOVT, 0, &hdr); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + pr_err("Failed to get table, %s\n", acpi_format_exception(status)); + + return; + } + + iovt = (struct acpi_table_iovt *)&hdr; + iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iovt, iovt->iommu_offset); + for (i = 0; i < iovt->iommu_count; i++) { + iovt_enable_acs(iommu); + iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iommu, iommu->header.length); + } + + acpi_put_table(hdr); +} + +void __init acpi_iovt_late_init(void) +{ + acpi_status status; + struct acpi_table_header *hdr; + + status = acpi_get_table(ACPI_SIG_IOVT, 0, &hdr); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + pr_err("Failed to get table, %s\n", acpi_format_exception(status)); + + return; + } + + iovt_init_devices(hdr); + acpi_put_table(hdr); +} + +static int iovt_pci_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data) +{ + struct iovt_fwnode *np; + struct iovt_device_entry *entry; + struct device *aliased_dev = data; + u32 domain = pci_domain_nr(pdev->bus); + + list_for_each_entry(np, &iovt_fwnode_list, list) { + if (domain != np->segment) + continue; + + /* We're not translating ourself */ + if (dev_id == np->devid) + return -EINVAL; + + if (np->flag & ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT) + goto found; + + list_for_each_entry(entry, &np->ep_list, list) { + if (dev_id >= entry->start_devid && dev_id <= entry->end_devid) + goto found; + } + } + + return -ENODEV; + +found: + return acpi_iommu_fwspec_init(aliased_dev, (domain << 16) + dev_id, np->fwnode); +} + +/* + * iovt_iommu_configure_id - Set-up IOMMU configuration for a device. + * + * @dev: device to configure + * @id_in: optional input id const value pointer + * + * Returns: 0 on success, <0 on failure + */ +int iovt_iommu_configure_id(struct device *dev, const u32 *id_in) +{ + if (!dev_is_pci(dev)) + return -ENODEV; + + return pci_for_each_dma_alias(to_pci_dev(dev), iovt_pci_iommu_init, dev); +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0b17a7e51956..96b8b0dfe339 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/acpi.h> #include <linux/acpi_iort.h> +#include <linux/acpi_iovt.h> #include <linux/acpi_rimt.h> #include <linux/acpi_viot.h> #include <linux/iommu.h> @@ -1626,6 +1627,8 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in) if (err && err != -EPROBE_DEFER) err = rimt_iommu_configure_id(dev, id_in); if (err && err != -EPROBE_DEFER) + err = iovt_iommu_configure_id(dev, id_in); + if (err && err != -EPROBE_DEFER) err = viot_iommu_configure(dev); mutex_unlock(&iommu_probe_device_lock); diff --git a/drivers/soc/loongson/loongson2_guts.c b/drivers/soc/loongson/loongson2_guts.c index 16913c3ef65c..a2f2c1e119fe 100644 --- a/drivers/soc/loongson/loongson2_guts.c +++ b/drivers/soc/loongson/loongson2_guts.c @@ -92,8 +92,8 @@ static u32 loongson2_guts_get_svr(void) static int loongson2_guts_probe(struct platform_device *pdev) { - struct device_node *root, *np = pdev->dev.of_node; struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; const struct loongson2_soc_die_attr *soc_die; const char *machine; u32 svr; @@ -109,11 +109,8 @@ static int loongson2_guts_probe(struct platform_device *pdev) if (IS_ERR(guts->regs)) return PTR_ERR(guts->regs); - /* Register soc device */ - root = of_find_node_by_path("/"); - if (of_property_read_string(root, "model", &machine)) - of_property_read_string_index(root, "compatible", 0, &machine); - of_node_put(root); + if (of_property_read_string(of_root, "model", &machine)) + of_property_read_string_index(of_root, "compatible", 0, &machine); if (machine) { soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL); if (!soc_dev_attr.machine) diff --git a/drivers/soc/loongson/loongson2_pm.c b/drivers/soc/loongson/loongson2_pm.c index b8e5e1e3528a..1e2c897d055b 100644 --- a/drivers/soc/loongson/loongson2_pm.c +++ b/drivers/soc/loongson/loongson2_pm.c @@ -175,7 +175,7 @@ static int loongson2_pm_probe(struct platform_device *pdev) return irq; if (!device_property_read_u64(dev, "loongson,suspend-address", &suspend_addr)) - loongson_sysconf.suspend_addr = (u64)phys_to_virt(suspend_addr); + loongson_sysconf.suspend_addr = (unsigned long)phys_to_virt(suspend_addr); else dev_err(dev, "No loongson,suspend-address, could not support S3!\n"); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d7f1f3d05390..9d3f039ebd94 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1637,6 +1637,7 @@ static inline int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, #endif void acpi_arch_init(void); +void acpi_arch_late_init(void); #ifdef CONFIG_ACPI_PCC void acpi_init_pcc(void); diff --git a/include/linux/acpi_iovt.h b/include/linux/acpi_iovt.h new file mode 100644 index 000000000000..663b4c679bc5 --- /dev/null +++ b/include/linux/acpi_iovt.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ACPI_IOVT_H__ +#define __ACPI_IOVT_H__ + +#ifdef CONFIG_ACPI_IOVT +int iovt_iommu_configure_id(struct device *dev, const u32 *id_in); +#else +static inline int iovt_iommu_configure_id(struct device *dev, const u32 *id_in) +{ return -ENODEV; } +#endif + +#endif /* __ACPI_IOVT_H__ */ |
