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

Aleksa Paunovic aleksa.paunovic at htecgroup.com
Wed Jul 22 04:31:58 PDT 2026


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 at htecgroup.com>
>>
>> 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 at htecgroup.com>
>> Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>> ---
>> 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@htecgroup.com
>> ---
>>  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 at htecgroup.com>
>>
>>
> Gentle ping.
Pinging this. 


More information about the linux-riscv mailing list