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

Aleksa Paunovic aleksa.paunovic at htecgroup.com
Wed Jul 1 06:45:01 PDT 2026


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.


More information about the linux-riscv mailing list