[PATCH v2 4/6] LoongArch: Drop pernode exception handlers

From: Jinyang He
Date: Tue Feb 28 2023 - 03:04:29 EST


1, set the value of CSR.EENTRY to &__ex_handlers.
2, set the value of CSR.TLBRENTRY to &__tlbr_entry.
3, set the value of CSR.MERRENTRY to &__ex_handlers.
Then, we can drop the pernode exception handlers.

Signed-off-by: Jinyang He <hejinyang@xxxxxxxxxxx>
---
arch/loongarch/include/asm/setup.h | 7 ---
arch/loongarch/include/asm/traps.h | 29 ++++++++++
arch/loongarch/kernel/genex.S | 8 ---
arch/loongarch/kernel/traps.c | 74 +------------------------
arch/loongarch/kernel/unwind_prologue.c | 62 +--------------------
arch/loongarch/mm/cache.c | 6 --
arch/loongarch/mm/tlb.c | 40 -------------
arch/loongarch/power/suspend.c | 5 +-
8 files changed, 33 insertions(+), 198 deletions(-)

diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h
index be05c0e706a2..4074225339ec 100644
--- a/arch/loongarch/include/asm/setup.h
+++ b/arch/loongarch/include/asm/setup.h
@@ -9,17 +9,10 @@
#include <linux/types.h>
#include <uapi/asm/setup.h>

-#define VECSIZE 0x200
-
-extern unsigned long eentry;
-extern unsigned long tlbrentry;
extern char init_command_line[COMMAND_LINE_SIZE];
extern void tlb_init(int cpu);
extern void cpu_cache_init(void);
-extern void cache_error_setup(void);
extern void per_cpu_trap_init(int cpu);
-extern void set_handler(unsigned long offset, void *addr, unsigned long len);
-extern void set_merr_handler(unsigned long offset, void *addr, unsigned long len);

#ifdef CONFIG_RELOCATABLE

diff --git a/arch/loongarch/include/asm/traps.h b/arch/loongarch/include/asm/traps.h
index b348d66c16a1..8f276253f145 100644
--- a/arch/loongarch/include/asm/traps.h
+++ b/arch/loongarch/include/asm/traps.h
@@ -34,6 +34,35 @@
.pushsection .tlbrhandler, "ax"; \
__VA_ARGS__; \
.popsection;
+
+#else /* __ASSEMBLY__ */
+
+#define VECSIZE 0x200
+extern void *__ex_handlers;
+extern void *__tlbr_entry;
+
+static inline void set_eentry(void *entry)
+{
+ csr_write64((unsigned long)entry, LOONGARCH_CSR_EENTRY);
+}
+
+static inline void set_tlbrentry(void *entry)
+{
+ csr_write64((unsigned long)entry, LOONGARCH_CSR_TLBRENTRY);
+}
+
+static inline void set_merrentry(void *entry)
+{
+ csr_write64((unsigned long)entry, LOONGARCH_CSR_MERRENTRY);
+}
+
+static inline void configure_exception_vector(void)
+{
+ set_eentry(&__ex_handlers);
+ set_tlbrentry(&__tlbr_entry);
+ set_merrentry(&__ex_handlers);
+}
+
#endif /* __ASSEMBLY__ */

#endif /* _ASM_TRAPS_H */
diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S
index 86abafc8b95b..256e2e5b83d4 100644
--- a/arch/loongarch/kernel/genex.S
+++ b/arch/loongarch/kernel/genex.S
@@ -72,19 +72,14 @@ SYM_FUNC_END(except_vec_cex)
.macro BUILD_HANDLER exception handler prep
.align 5
SYM_FUNC_START(handle_\exception)
- 666:
BACKUP_T0T1
SAVE_ALL
build_prep_\prep
move a0, sp
la_abs t0, do_\handler
jirl ra, t0, 0
- 668:
RESTORE_ALL_AND_RET
SYM_FUNC_END(handle_\exception)
- .pushsection .rodata
-SYM_DATA(unwind_hint_\exception, .word 668b - 666b)
- .popsection
.endm

SET_EXCEPTION_HANDLER(EXCCODE_SIP0, _handle_vint)
@@ -123,6 +118,3 @@ SET_EXCEPTION_HANDLER(\i, BUILD_HANDLER reserved\i reserved none)
.irp i, EXCCODE_NOHND
SET_EXCEPTION_HANDLER(\i, BUILD_HANDLER reserved\i reserved none)
.endr
-
-/* Create handle_reserved for temporary build. */
-BUILD_HANDLER reserved reserved none
diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index c8b3bd76c941..84ac78bc8c57 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -43,6 +43,7 @@
#include <asm/siginfo.h>
#include <asm/stacktrace.h>
#include <asm/tlb.h>
+#include <asm/traps.h>
#include <asm/types.h>
#include <asm/unwind.h>

@@ -798,25 +799,8 @@ asmlinkage void noinstr do_vint(struct pt_regs *regs, unsigned long sp)
irqentry_exit(regs, state);
}

-unsigned long eentry;
-unsigned long tlbrentry;
-
-long exception_handlers[VECSIZE * 128 / sizeof(long)] __aligned(SZ_64K);
-
-static void configure_exception_vector(void)
-{
- eentry = (unsigned long)exception_handlers;
- tlbrentry = (unsigned long)exception_handlers + 80*VECSIZE;
-
- csr_write64(eentry, LOONGARCH_CSR_EENTRY);
- csr_write64(eentry, LOONGARCH_CSR_MERRENTRY);
- csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
-}
-
void per_cpu_trap_init(int cpu)
{
- unsigned int i;
-
setup_vint_size(VECSIZE);

configure_exception_vector();
@@ -829,62 +813,6 @@ void per_cpu_trap_init(int cpu)
BUG_ON(current->mm);
enter_lazy_tlb(&init_mm, current);

- /* Initialise exception handlers */
- if (cpu == 0)
- for (i = 0; i < 64; i++)
- set_handler(i * VECSIZE, handle_reserved, VECSIZE);
-
tlb_init(cpu);
cpu_cache_init();
}
-
-/* Install CPU exception handler */
-void set_handler(unsigned long offset, void *addr, unsigned long size)
-{
- memcpy((void *)(eentry + offset), addr, size);
- local_flush_icache_range(eentry + offset, eentry + offset + size);
-}
-
-static const char panic_null_cerr[] =
- "Trying to set NULL cache error exception handler\n";
-
-/*
- * Install uncached CPU exception handler.
- * This is suitable only for the cache error exception which is the only
- * exception handler that is being run uncached.
- */
-void set_merr_handler(unsigned long offset, void *addr, unsigned long size)
-{
- unsigned long uncached_eentry = TO_UNCACHE(__pa(eentry));
-
- if (!addr)
- panic(panic_null_cerr);
-
- memcpy((void *)(uncached_eentry + offset), addr, size);
-}
-
-void __init trap_init(void)
-{
- long i;
-
- /* Set interrupt vector handler */
- for (i = EXCCODE_INT_START; i < EXCCODE_INT_END; i++)
- set_handler(i * VECSIZE, handle_vint, VECSIZE);
-
- set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE);
- set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE);
- set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE);
- set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE);
- set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE);
- set_handler(EXCCODE_IPE * VECSIZE, handle_ri, VECSIZE);
- set_handler(EXCCODE_FPDIS * VECSIZE, handle_fpu, VECSIZE);
- set_handler(EXCCODE_LSXDIS * VECSIZE, handle_lsx, VECSIZE);
- set_handler(EXCCODE_LASXDIS * VECSIZE, handle_lasx, VECSIZE);
- set_handler(EXCCODE_FPE * VECSIZE, handle_fpe, VECSIZE);
- set_handler(EXCCODE_BTDIS * VECSIZE, handle_lbt, VECSIZE);
- set_handler(EXCCODE_WATCH * VECSIZE, handle_watch, VECSIZE);
-
- cache_error_setup();
-
- local_flush_icache_range(eentry, eentry + 0x400);
-}
diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kernel/unwind_prologue.c
index 9095fde8e55d..de18335c6ba6 100644
--- a/arch/loongarch/kernel/unwind_prologue.c
+++ b/arch/loongarch/kernel/unwind_prologue.c
@@ -12,69 +12,9 @@
#include <asm/setup.h>
#include <asm/unwind.h>

-extern const int unwind_hint_ade;
-extern const int unwind_hint_ale;
-extern const int unwind_hint_bp;
-extern const int unwind_hint_fpe;
-extern const int unwind_hint_fpu;
-extern const int unwind_hint_lsx;
-extern const int unwind_hint_lasx;
-extern const int unwind_hint_lbt;
-extern const int unwind_hint_ri;
-extern const int unwind_hint_watch;
-extern unsigned long eentry;
-#ifdef CONFIG_NUMA
-extern unsigned long pcpu_handlers[NR_CPUS];
-#endif
-
-static inline bool scan_handlers(unsigned long entry_offset)
-{
- int idx, offset;
-
- if (entry_offset >= EXCCODE_INT_START * VECSIZE)
- return false;
-
- idx = entry_offset / VECSIZE;
- offset = entry_offset % VECSIZE;
- switch (idx) {
- case EXCCODE_ADE:
- return offset == unwind_hint_ade;
- case EXCCODE_ALE:
- return offset == unwind_hint_ale;
- case EXCCODE_BP:
- return offset == unwind_hint_bp;
- case EXCCODE_FPE:
- return offset == unwind_hint_fpe;
- case EXCCODE_FPDIS:
- return offset == unwind_hint_fpu;
- case EXCCODE_LSXDIS:
- return offset == unwind_hint_lsx;
- case EXCCODE_LASXDIS:
- return offset == unwind_hint_lasx;
- case EXCCODE_BTDIS:
- return offset == unwind_hint_lbt;
- case EXCCODE_INE:
- return offset == unwind_hint_ri;
- case EXCCODE_WATCH:
- return offset == unwind_hint_watch;
- default:
- return false;
- }
-}
-
static inline bool fix_exception(unsigned long pc)
{
-#ifdef CONFIG_NUMA
- int cpu;
-
- for_each_possible_cpu(cpu) {
- if (!pcpu_handlers[cpu])
- continue;
- if (scan_handlers(pc - pcpu_handlers[cpu]))
- return true;
- }
-#endif
- return scan_handlers(pc - eentry);
+ return false;
}

/*
diff --git a/arch/loongarch/mm/cache.c b/arch/loongarch/mm/cache.c
index 72685a48eaf0..d8e53702d61f 100644
--- a/arch/loongarch/mm/cache.c
+++ b/arch/loongarch/mm/cache.c
@@ -25,12 +25,6 @@
#include <asm/processor.h>
#include <asm/setup.h>

-void cache_error_setup(void)
-{
- extern char __weak except_vec_cex;
- set_merr_handler(0x0, &except_vec_cex, 0x80);
-}
-
/*
* LoongArch maintains ICache/DCache coherency by hardware,
* we just need "ibar" to avoid instruction hazard here.
diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c
index 8bad6b0cff59..dda35eae1c49 100644
--- a/arch/loongarch/mm/tlb.c
+++ b/arch/loongarch/mm/tlb.c
@@ -250,50 +250,10 @@ static void output_pgtable_bits_defines(void)
pr_debug("\n");
}

-#ifdef CONFIG_NUMA
-unsigned long pcpu_handlers[NR_CPUS];
-#endif
-extern long exception_handlers[VECSIZE * 128 / sizeof(long)];
-
void setup_tlb_handler(int cpu)
{
setup_ptwalker();
local_flush_tlb_all();
-
- /* The tlb handlers are generated only once */
- if (cpu == 0) {
- memcpy((void *)tlbrentry, handle_tlb_refill, 0x80);
- local_flush_icache_range(tlbrentry, tlbrentry + 0x80);
- set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load, VECSIZE);
- set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load, VECSIZE);
- set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store, VECSIZE);
- set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify, VECSIZE);
- set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE);
- set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE);
- set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE);
- }
-#ifdef CONFIG_NUMA
- else {
- void *addr;
- struct page *page;
- const int vec_sz = sizeof(exception_handlers);
-
- if (pcpu_handlers[cpu])
- return;
-
- page = alloc_pages_node(cpu_to_node(cpu), GFP_ATOMIC, get_order(vec_sz));
- if (!page)
- return;
-
- addr = page_address(page);
- pcpu_handlers[cpu] = (unsigned long)addr;
- memcpy((void *)addr, (void *)eentry, vec_sz);
- local_flush_icache_range((unsigned long)addr, (unsigned long)addr + vec_sz);
- csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_EENTRY);
- csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_MERRENTRY);
- csr_write64(pcpu_handlers[cpu] + 80*VECSIZE, LOONGARCH_CSR_TLBRENTRY);
- }
-#endif
}

void tlb_init(int cpu)
diff --git a/arch/loongarch/power/suspend.c b/arch/loongarch/power/suspend.c
index 5e19733e5e05..b2a10a33b372 100644
--- a/arch/loongarch/power/suspend.c
+++ b/arch/loongarch/power/suspend.c
@@ -14,6 +14,7 @@
#include <asm/setup.h>
#include <asm/time.h>
#include <asm/tlbflush.h>
+#include <asm/traps.h>

u64 loongarch_suspend_addr;

@@ -45,9 +46,7 @@ static void arch_common_resume(void)
sync_counter();
local_flush_tlb_all();
csr_write64(per_cpu_offset(0), PERCPU_BASE_KS);
- csr_write64(eentry, LOONGARCH_CSR_EENTRY);
- csr_write64(eentry, LOONGARCH_CSR_MERRENTRY);
- csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
+ configure_exception_vector();

csr_write64(saved_regs.pgd, LOONGARCH_CSR_PGDL);
csr_write64(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
--
2.34.3