summaryrefslogtreecommitdiff
path: root/arch/riscv/include
diff options
context:
space:
mode:
authorDjordje Todorovic <djordje.todorovic@htecgroup.com>2026-09-17 17:06:39 +0200
committerPaul Walmsley <pjw@kernel.org>2026-10-08 14:11:53 -0600
commit2cf0b2992203da6b383e21d8a1756d91ca4bfcfc (patch)
tree5a8e06464850614b64992b794b220b8297fba4bc /arch/riscv/include
parent5c6e22ad386bc4a1299f0dd0732aefb9dfbc6a29 (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.h37
-rw-r--r--arch/riscv/include/asm/errata_list_vendors.h5
-rw-r--r--arch/riscv/include/asm/processor.h3
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;