summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-27 13:26:07 +0000
committerMark Brown <broonie@kernel.org>2026-10-27 13:26:07 +0000
commitc863dee9cf208fbd124be3468346d9eb557c242a (patch)
tree5c5cbbadacb811bea525b10aca96aa871ef088a0
parent804e4955ac7d4ec75c6ec4414ec51d3e2125362f (diff)
parentecb531544804101cb6ca0b124b5a446ee2db2f9f (diff)
downloadlinux-next-c863dee9cf208fbd124be3468346d9eb557c242a.tar.gz
linux-next-c863dee9cf208fbd124be3468346d9eb557c242a.zip
Merge branch 'loongarch-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git
-rw-r--r--Documentation/admin-guide/kdump/vmcoreinfo.rst36
-rw-r--r--MAINTAINERS9
-rw-r--r--arch/loongarch/Kconfig1
-rw-r--r--arch/loongarch/boot/dts/loongson-2k0500-ref.dts2
-rw-r--r--arch/loongarch/include/asm/barrier.h3
-rw-r--r--arch/loongarch/include/asm/cpu-features.h2
-rw-r--r--arch/loongarch/include/asm/cpu.h66
-rw-r--r--arch/loongarch/include/asm/hw_breakpoint.h8
-rw-r--r--arch/loongarch/include/asm/loongarch.h7
-rw-r--r--arch/loongarch/include/asm/numa.h2
-rw-r--r--arch/loongarch/include/asm/processor.h1
-rw-r--r--arch/loongarch/include/asm/switch_to.h2
-rw-r--r--arch/loongarch/include/uapi/asm/hwcap.h2
-rw-r--r--arch/loongarch/kernel/Makefile1
-rw-r--r--arch/loongarch/kernel/cpu-probe.c10
-rw-r--r--arch/loongarch/kernel/efi-header.S2
-rw-r--r--arch/loongarch/kernel/env.c5
-rw-r--r--arch/loongarch/kernel/hw_breakpoint.c66
-rw-r--r--arch/loongarch/kernel/irq.c3
-rw-r--r--arch/loongarch/kernel/numa.c8
-rw-r--r--arch/loongarch/kernel/proc.c4
-rw-r--r--arch/loongarch/kernel/traps.c13
-rw-r--r--arch/loongarch/kernel/vmcore_info.c22
-rw-r--r--arch/loongarch/pci/pci.c3
-rw-r--r--drivers/acpi/Kconfig4
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/loongarch/Kconfig7
-rw-r--r--drivers/acpi/loongarch/Makefile3
-rw-r--r--drivers/acpi/loongarch/init.c16
-rw-r--r--drivers/acpi/loongarch/init.h5
-rw-r--r--drivers/acpi/loongarch/iovt.c258
-rw-r--r--drivers/acpi/scan.c3
-rw-r--r--drivers/soc/loongson/loongson2_guts.c9
-rw-r--r--drivers/soc/loongson/loongson2_pm.c2
-rw-r--r--include/linux/acpi.h1
-rw-r--r--include/linux/acpi_iovt.h13
37 files changed, 524 insertions, 79 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 ff54bf2d87a9..2efe7f9361c0 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/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/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 f165d14cf61a..192e6f18eda1 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__ */