Re: [PATCH v2] riscv: Add ERRATA_MIPS_P8700_WFI to replace WFI with mips.pause

From: Aleksa Paunovic

Date: Wed Jul 22 2026 - 07:38:00 EST


On 7/1/26 15:45, Aleksa Paunovic wrote:
> On 6/8/26 16:41, Aleksa Paunovic via B4 Relay wrote:
>> From: Djordje Todorovic <djordje.todorovic@xxxxxxxxxxxxx>
>>
>> The MIPS P8700 has bugs with the WFI instruction. This errata
>> 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@xxxxxxxxxxxxx>
>> Signed-off-by: Aleksa Paunovic <aleksa.paunovic@xxxxxxxxxxxxx>
>> ---
>> This patch was tested on QEMU configured with eight P8700 harts,
>> as well as on the MIPS Boston board, configured with a single P8700 CPU.
>> Errata application was tested by disassembling with GDB on QEMU
>> and inserting an illegal instruction on the Boston board.
>> Correctness was tested with a combination of kselftests
>> and torture tests (rcu, locktorture), along with coremark testing.
>> ---
>> Changes in v2:
>> - Replace .insn with .4byte in ALT_WFI macro
>> - Add explanatory comments
>> - Link to v1: https://lore.kernel.org/r/20260511-p8700-wfi-v1-1-099b1d10fcf2@xxxxxxxxxxxxx
>> ---
>> arch/riscv/Kconfig.errata | 11 ++++++++++
>> arch/riscv/errata/mips/errata.c | 14 ++++++++++++
>> arch/riscv/include/asm/errata_list.h | 33 ++++++++++++++++++++++++++++
>> arch/riscv/include/asm/errata_list_vendors.h | 5 +++--
>> arch/riscv/include/asm/processor.h | 3 ++-
>> arch/riscv/kernel/head.S | 4 +++-
>> 6 files changed, 66 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
>> index 3c945d086c7d0266b685f9506d58b0662af071c4..cc75e6f70513d08afeedf650b14dba83eea84632 100644
>> --- a/arch/riscv/Kconfig.errata
>> +++ b/arch/riscv/Kconfig.errata
>> @@ -44,6 +44,17 @@ config ERRATA_MIPS_P8700_PAUSE_OPCODE
>>
>> If you are not using the P8700 processor, say n.
>>
>> +config ERRATA_MIPS_P8700_WFI
>> + bool "Replace WFI with mips.pause for MIPS P8700"
>> + depends on ERRATA_MIPS && 64BIT
>> + default n
>> + help
>> + The RISCV MIPS P8700 has bugs with the WFI instruction.
>> + This errata replaces all WFI instructions with the MIPS
>> + P8700 pause opcode to avoid these issues.
>> +
>> + If you are not using the P8700 processor, say n.
>> +
>> config ERRATA_SIFIVE
>> bool "SiFive errata"
>> depends on RISCV_ALTERNATIVE
>> diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c
>> index e984a8152208c34690f89d8101571b097485c360..67b59f8c1708ea8b7a040f7939e111b8f30e6a75 100644
>> --- a/arch/riscv/errata/mips/errata.c
>> +++ b/arch/riscv/errata/mips/errata.c
>> @@ -23,6 +23,17 @@ static inline bool errata_probe_pause(void)
>> return true;
>> }
>>
>> +static inline bool errata_probe_wfi(void)
>> +{
>> + if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_WFI))
>> + return false;
>> +
>> + if (!riscv_isa_vendor_extension_available(MIPS_VENDOR_ID, XMIPSEXECTL))
>> + return false;
>> +
>> + return true;
>> +}
>> +
>> static u32 mips_errata_probe(void)
>> {
>> u32 cpu_req_errata = 0;
>> @@ -30,6 +41,9 @@ static u32 mips_errata_probe(void)
>> if (errata_probe_pause())
>> cpu_req_errata |= BIT(ERRATA_MIPS_P8700_PAUSE_OPCODE);
>>
>> + if (errata_probe_wfi())
>> + cpu_req_errata |= BIT(ERRATA_MIPS_P8700_WFI);
>> +
>> return cpu_req_errata;
>> }
>>
>> diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
>> index 6694b5ccdcf85cfe7e767ea4de981b34f2b17b04..5c936882c42a90bac2bf40369a795d067a86d31d 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,29 @@ 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.
>> + */
>> +#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 ec7eba3734371a2d8b68fbd4cbd88a8e7135a413..4505317a6b949be602f507547fc9cd495c923e32 100644
>> --- a/arch/riscv/include/asm/errata_list_vendors.h
>> +++ b/arch/riscv/include/asm/errata_list_vendors.h
>> @@ -22,8 +22,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 4c3dd94d0f63844fecc32a7e2c1a184113ee49d9..ae4faed371c16ba33f31373561de03e89d35d04c 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) \
>> ({ \
>> @@ -176,7 +177,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;
>> diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
>> index 9c99c5ad6fe8a32e24c8ce7e0badd63469d2c387..14935e8eec2639844c45bd37db29db74fee38a22 100644
>> --- a/arch/riscv/kernel/head.S
>> +++ b/arch/riscv/kernel/head.S
>> @@ -16,6 +16,8 @@
>> #include <asm/scs.h>
>> #include <asm/xip_fixup.h>
>> #include <asm/usercfi.h>
>> +#include <asm/alternative.h>
>> +#include <asm/errata_list.h>
>> #include "efi-header.S"
>>
>> __HEAD
>> @@ -196,7 +198,7 @@ secondary_start_sbi:
>> * - receive an early trap, before setup_trap_vector finished
>> * - fail in smp_callin(), as a successful one wouldn't return
>> */
>> - wfi
>> + ALT_WFI
>> j .Lsecondary_park
>>
>> .align 2
>>
>> ---
>> base-commit: c369299895a591d96745d6492d4888259b004a9e
>> change-id: 20260415-p8700-wfi-9083b1d87d22
>>
>> Best regards,
>> --
>> Aleksa Paunovic <aleksa.paunovic@xxxxxxxxxxxxx>
>>
>>
> Gentle ping.
Pinging this.