diff options
| author | Djordje Todorovic <djordje.todorovic@htecgroup.com> | 2026-09-17 17:06:39 +0200 |
|---|---|---|
| committer | Paul Walmsley <pjw@kernel.org> | 2026-10-08 14:11:53 -0600 |
| commit | 2cf0b2992203da6b383e21d8a1756d91ca4bfcfc (patch) | |
| tree | 5a8e06464850614b64992b794b220b8297fba4bc /arch/riscv/include | |
| parent | 5c6e22ad386bc4a1299f0dd0732aefb9dfbc6a29 (diff) | |
riscv: Add ERRATA_MIPS_P8700_WFI to replace WFI with mips.pause
The MIPS P8700 has bugs with the WFI instruction. A WFI instruction
after a mispredicted branch can result in erroneous address
translation on the MIPS P8700. MIPS has not published an erratum
for this.
The workaround uses the RISC-V alternatives framework to patch all WFI
instructions with the MIPS P8700 pause opcode (0x00501013)
at runtime when running on P8700 hardware.
Two call sites are patched:
- arch/riscv/kernel/head.S: secondary hart parking loop
- arch/riscv/include/asm/processor.h: wait_for_interrupt()
Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Signed-off-by: Aleksa Paunovic <aleksa.paunovic@htecgroup.com>
Link: https://patch.msgid.link/20260917-p8700-wfi-v3-1-ada4b0584712@htecgroup.com
[pjw@kernel.org: updated to apply]
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Diffstat (limited to 'arch/riscv/include')
| -rw-r--r-- | arch/riscv/include/asm/errata_list.h | 37 | ||||
| -rw-r--r-- | arch/riscv/include/asm/errata_list_vendors.h | 5 | ||||
| -rw-r--r-- | arch/riscv/include/asm/processor.h | 3 |
3 files changed, 42 insertions, 3 deletions
diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h index 6694b5ccdcf8..6fdb445c0f45 100644 --- a/arch/riscv/include/asm/errata_list.h +++ b/arch/riscv/include/asm/errata_list.h @@ -25,6 +25,16 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault), \ __stringify(RISCV_PTR sifive_cip_453_page_fault_trp), \ SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453, \ CONFIG_ERRATA_SIFIVE_CIP_453) + +#ifdef CONFIG_ERRATA_MIPS_P8700_WFI +#define ALT_WFI \ +ALTERNATIVE("wfi; .rept 7; nop; .endr;", \ + ".rept 8; .4byte 0x00501013; .endr;", MIPS_VENDOR_ID, \ + ERRATA_MIPS_P8700_WFI, CONFIG_ERRATA_MIPS_P8700_WFI) +#else +#define ALT_WFI wfi +#endif + #else /* !__ASSEMBLER__ */ #define ALT_SFENCE_VMA_ASID(asid) \ @@ -53,6 +63,33 @@ asm(ALTERNATIVE( \ : /* no inputs */ \ : "memory") +#ifdef CONFIG_ERRATA_MIPS_P8700_WFI +/* + * A WFI instruction after a mispredicted branch can result in erroneous address translation + * on the MIPS P8700. + * The number of MIPS_PAUSE instructions required was determined by measuring + * Coremark performance on a one-core, two-hart configuration. Eight PAUSE instructions matched + * the latency of a single WFI instruction. + * Usually, the maximum number of cycles per PAUSE instruction is 63. Exceptionally, if the hart's + * LR reservation bit is set, the maximum number of cycles is extended to 255 + * (and the hart is woken up once it is cleared). This case should not affect the patched sites. + */ +#define ALT_RISCV_WFI() \ +asm volatile(ALTERNATIVE( \ + "wfi\n" /* Original RISC-V wfi insn */ \ + __nops(7), \ + ".rept 8;" MIPS_PAUSE ".endr;\n", /* Replacement: mips.pause for P8700 */ \ + MIPS_VENDOR_ID, /* Vendor ID to match */ \ + ERRATA_MIPS_P8700_WFI, /* patch_id */ \ + CONFIG_ERRATA_MIPS_P8700_WFI) \ + : /* no outputs */ \ + : /* no inputs */ \ + : "memory") +#else +#define ALT_RISCV_WFI() \ + __asm__ __volatile__ ("wfi") +#endif + /* * _val is marked as "will be overwritten", so need to set it to 0 * in the default case. diff --git a/arch/riscv/include/asm/errata_list_vendors.h b/arch/riscv/include/asm/errata_list_vendors.h index c62a82f60468..02b5ab0d23a8 100644 --- a/arch/riscv/include/asm/errata_list_vendors.h +++ b/arch/riscv/include/asm/errata_list_vendors.h @@ -23,8 +23,9 @@ #endif #ifdef CONFIG_ERRATA_MIPS -#define ERRATA_MIPS_P8700_PAUSE_OPCODE 0 -#define ERRATA_MIPS_NUMBER 1 +#define ERRATA_MIPS_P8700_PAUSE_OPCODE 0 +#define ERRATA_MIPS_P8700_WFI 1 +#define ERRATA_MIPS_NUMBER 2 #endif #endif /* ASM_ERRATA_LIST_VENDORS_H */ diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 815715c67f94..3686f871c8ed 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -17,6 +17,7 @@ #include <asm/alternative-macros.h> #include <asm/hwcap.h> #include <asm/usercfi.h> +#include <asm/errata_list.h> #define arch_get_mmap_end(addr, len, flags) \ ({ \ @@ -187,7 +188,7 @@ extern unsigned long __get_wchan(struct task_struct *p); static inline void wait_for_interrupt(void) { - __asm__ __volatile__ ("wfi"); + ALT_RISCV_WFI(); } extern phys_addr_t dma32_phys_limit; |
