]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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 e318119d570de0acc0850a2e1a2505ecb71bea08..aca9b0cfcfecf91d4d1910f294ee109ed15f2d6c 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 bc6c77ba837d2da4c98dabab18083d27f46629c7..02a7a3335b1d557933e04cd6d0cf7bf4260b8c40 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 0e95539ba451ba55abb15ee4a26b6125c9d0261a..8407d1d535b8527054824cd280d9163875bd8b26 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 0b749e7102162477432f7cf9a34768fbdf2e8cc7..80bd52363c68690f33bfd54e0cc40399cd60b57b 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 a2481f14b68d56b3435d160793699002a45472eb..6694b5ccdcf85cfe7e767ea4de981b34f2b17b04 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 d448b9ce7c7c58e6618e070ba913f27f08862743..ec7eba3734371a2d8b68fbd4cbd88a8e7135a413 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 98fb44336c055f1c60899cb25c99f2416184c466..c42f95dc8811d8a949898f7338151dcc4e987372 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 7eb3cb1215c62130c63a72fc650cddff6bae62af..7642704c7f1841f67fc23738063f22b4ecf58194 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 d0ded2438533c4aa07116f645ee0501cb77b94cc..d3d92a4becc726ef77f8b129ca4032519335b0c9 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 85cb70b10c0715ff752cf9455c6ea594123d2800..6091f3f06fa35da14f0cab4d9b51e036a90c9dd0 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>