riscv: errata: Fix the PAUSE Opcode for MIPS P8700
authorDjordje Todorovic <djordje.todorovic@htecgroup.com>
Thu, 24 Jul 2025 15:23:31 +0000 (17:23 +0200)
committerPaul Walmsley <pjw@kernel.org>
Fri, 19 Sep 2025 16:33:56 +0000 (10:33 -0600)
Add ERRATA_MIPS and ERRATA_MIPS_P8700_PAUSE_OPCODE configs.
Handle errata for the MIPS PAUSE instruction.

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Signed-off-by: Aleksandar Rikalo <arikalo@gmail.com>
Signed-off-by: Raj Vishwanathan4 <rvishwanathan@mips.com>
Signed-off-by: Aleksa Paunovic <aleksa.paunovic@htecgroup.com>
Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Link: https://lore.kernel.org/r/20250724-p8700-pause-v5-7-a6cbbe1c3412@htecgroup.com
[pjw@kernel.org: updated to apply and compile; fixed a checkpatch issue]
Signed-off-by: Paul Walmsley <pjw@kernel.org>
12 files changed:
arch/riscv/Kconfig.errata
arch/riscv/errata/Makefile
arch/riscv/errata/mips/Makefile [new file with mode: 0644]
arch/riscv/errata/mips/errata.c [new file with mode: 0644]
arch/riscv/include/asm/alternative.h
arch/riscv/include/asm/cmpxchg.h
arch/riscv/include/asm/errata_list.h
arch/riscv/include/asm/errata_list_vendors.h
arch/riscv/include/asm/vdso/processor.h
arch/riscv/kernel/alternative.c
arch/riscv/kernel/entry.S
arch/riscv/mm/init.c

index e318119..aca9b0c 100644 (file)
@@ -21,6 +21,29 @@ config ERRATA_ANDES_CMO
 
          If you don't know what to do here, say "Y".
 
+config ERRATA_MIPS
+       bool "MIPS errata"
+       depends on RISCV_ALTERNATIVE
+       help
+         All MIPS errata Kconfig depend on this Kconfig. Disabling
+         this Kconfig will disable all MIPS errata. Please say "Y"
+         here if your platform uses MIPS CPU cores.
+
+         Otherwise, please say "N" here to avoid unnecessary overhead.
+
+config ERRATA_MIPS_P8700_PAUSE_OPCODE
+       bool "Fix the PAUSE Opcode for MIPS P8700"
+       depends on ERRATA_MIPS && 64BIT
+       default n
+       help
+          The RISCV MIPS P8700 uses a different opcode for PAUSE.
+          It is a 'hint' encoding of the SLLI instruction,
+          with rd=0, rs1=0 and imm=5. It will behave as a NOP
+          instruction if no additional behavior beyond that of
+          SLLI is implemented.
+
+          If you are not using the P8700 processor, say n.
+
 config ERRATA_SIFIVE
        bool "SiFive errata"
        depends on RISCV_ALTERNATIVE
index bc6c77b..02a7a33 100644 (file)
@@ -13,5 +13,6 @@ endif
 endif
 
 obj-$(CONFIG_ERRATA_ANDES) += andes/
+obj-$(CONFIG_ERRATA_MIPS) += mips/
 obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
 obj-$(CONFIG_ERRATA_THEAD) += thead/
diff --git a/arch/riscv/errata/mips/Makefile b/arch/riscv/errata/mips/Makefile
new file mode 100644 (file)
index 0000000..6278c38
--- /dev/null
@@ -0,0 +1,5 @@
+ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
+CFLAGS_errata.o := -mcmodel=medany
+endif
+
+obj-y += errata.o
diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c
new file mode 100644 (file)
index 0000000..e984a81
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 MIPS.
+ */
+
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <asm/text-patching.h>
+#include <asm/alternative.h>
+#include <asm/errata_list.h>
+#include <asm/vendorid_list.h>
+#include <asm/vendor_extensions.h>
+#include <asm/vendor_extensions/mips.h>
+
+static inline bool errata_probe_pause(void)
+{
+       if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE))
+               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;
+
+       if (errata_probe_pause())
+               cpu_req_errata |= BIT(ERRATA_MIPS_P8700_PAUSE_OPCODE);
+
+       return cpu_req_errata;
+}
+
+void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
+                           unsigned long archid, unsigned long impid,
+                           unsigned int stage)
+{
+       struct alt_entry *alt;
+       u32 cpu_req_errata = mips_errata_probe();
+       u32 tmp;
+
+       BUILD_BUG_ON(ERRATA_MIPS_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
+
+       if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
+               return;
+
+       for (alt = begin; alt < end; alt++) {
+               if (alt->vendor_id != MIPS_VENDOR_ID)
+                       continue;
+
+               if (alt->patch_id >= ERRATA_MIPS_NUMBER) {
+                       WARN(1, "MIPS errata id:%d not in kernel errata list\n",
+                            alt->patch_id);
+                       continue;
+               }
+
+               tmp = (1U << alt->patch_id);
+               if (cpu_req_errata && tmp) {
+                       mutex_lock(&text_mutex);
+                       patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt),
+                                         alt->alt_len);
+                       mutex_unlock(&text_mutex);
+               }
+       }
+}
index 0e95539..8407d1d 100644 (file)
@@ -48,6 +48,9 @@ struct alt_entry {
 void andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
                             unsigned long archid, unsigned long impid,
                             unsigned int stage);
+void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
+                           unsigned long archid, unsigned long impid,
+                           unsigned int stage);
 void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
                              unsigned long archid, unsigned long impid,
                              unsigned int stage);
index 0b749e7..80bd523 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/insn-def.h>
 #include <asm/cpufeature-macros.h>
 #include <asm/processor.h>
+#include <asm/errata_list.h>
 
 #define __arch_xchg_masked(sc_sfx, swap_sfx, prepend, sc_append,               \
                           swap_append, r, p, n)                                \
@@ -438,7 +439,7 @@ static __always_inline void __cmpwait(volatile void *ptr,
        return;
 
 no_zawrs:
-       asm volatile(RISCV_PAUSE : : : "memory");
+       ALT_RISCV_PAUSE();
 }
 
 #define __cmpwait_relaxed(ptr, val) \
index a2481f1..6694b5c 100644 (file)
@@ -5,12 +5,12 @@
 #ifndef ASM_ERRATA_LIST_H
 #define ASM_ERRATA_LIST_H
 
-#include <asm/alternative.h>
 #include <asm/csr.h>
 #include <asm/insn-def.h>
 #include <asm/hwcap.h>
 #include <asm/vendorid_list.h>
 #include <asm/errata_list_vendors.h>
+#include <asm/vendor_extensions/mips.h>
 
 #ifdef __ASSEMBLER__
 
@@ -42,6 +42,17 @@ asm(ALTERNATIVE("sfence.vma %0, %1", "sfence.vma", SIFIVE_VENDOR_ID, \
                ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200)  \
                : : "r" (addr), "r" (asid) : "memory")
 
+#define ALT_RISCV_PAUSE()                                      \
+asm(ALTERNATIVE(       \
+               RISCV_PAUSE, /* Original RISC‑V pause insn */ \
+               MIPS_PAUSE, /* Replacement for MIPS P8700 */    \
+               MIPS_VENDOR_ID, /* Vendor ID to match */        \
+               ERRATA_MIPS_P8700_PAUSE_OPCODE, /* patch_id */  \
+               CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE)  \
+       : /* no outputs */      \
+       : /* no inputs */       \
+       : "memory")
+
 /*
  * _val is marked as "will be overwritten", so need to set it to 0
  * in the default case.
index d448b9c..ec7eba3 100644 (file)
@@ -21,4 +21,9 @@
 #define        ERRATA_THEAD_NUMBER 3
 #endif
 
+#ifdef CONFIG_ERRATA_MIPS
+#define        ERRATA_MIPS_P8700_PAUSE_OPCODE 0
+#define        ERRATA_MIPS_NUMBER 1
+#endif
+
 #endif /* ASM_ERRATA_LIST_VENDORS_H */
index 98fb443..c42f95d 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef __ASSEMBLER__
 
 #include <asm/barrier.h>
+#include <asm/errata_list.h>
 #include <asm/insn-def.h>
 
 static inline void cpu_relax(void)
@@ -19,7 +20,7 @@ static inline void cpu_relax(void)
         * Reduce instruction retirement.
         * This assumes the PC changes.
         */
-       __asm__ __volatile__ (RISCV_PAUSE);
+       ALT_RISCV_PAUSE();
        barrier();
 }
 
index 7eb3cb1..7642704 100644 (file)
@@ -47,6 +47,11 @@ static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info
                cpu_mfr_info->patch_func = andes_errata_patch_func;
                break;
 #endif
+#ifdef CONFIG_ERRATA_MIPS
+       case MIPS_VENDOR_ID:
+               cpu_mfr_info->patch_func = mips_errata_patch_func;
+               break;
+#endif
 #ifdef CONFIG_ERRATA_SIFIVE
        case SIFIVE_VENDOR_ID:
                cpu_mfr_info->patch_func = sifive_errata_patch_func;
index d0ded24..d3d92a4 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 
+#include <asm/alternative-macros.h>
 #include <asm/asm.h>
 #include <asm/csr.h>
 #include <asm/scs.h>
index 85cb70b..6091f3f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/kfence.h>
 #include <linux/execmem.h>
 
+#include <asm/alternative.h>
 #include <asm/fixmap.h>
 #include <asm/io.h>
 #include <asm/kasan.h>