summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDjordje Todorovic <djordje.todorovic@htecgroup.com>2025-07-24 17:23:31 +0200
committerPaul Walmsley <pjw@kernel.org>2025-09-19 10:33:56 -0600
commit0b0ca959d20689fece038954bbf1d7b14c0b11c3 (patch)
tree9356093f02b93df5c4f6a27dfff39379a841a20a
parentc9a9fc23228f447beefe473224207944521b14a1 (diff)
riscv: errata: Fix the PAUSE Opcode for MIPS P8700
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>
-rw-r--r--arch/riscv/Kconfig.errata23
-rw-r--r--arch/riscv/errata/Makefile1
-rw-r--r--arch/riscv/errata/mips/Makefile5
-rw-r--r--arch/riscv/errata/mips/errata.c67
-rw-r--r--arch/riscv/include/asm/alternative.h3
-rw-r--r--arch/riscv/include/asm/cmpxchg.h3
-rw-r--r--arch/riscv/include/asm/errata_list.h13
-rw-r--r--arch/riscv/include/asm/errata_list_vendors.h5
-rw-r--r--arch/riscv/include/asm/vdso/processor.h3
-rw-r--r--arch/riscv/kernel/alternative.c5
-rw-r--r--arch/riscv/kernel/entry.S1
-rw-r--r--arch/riscv/mm/init.c1
12 files changed, 127 insertions, 3 deletions
diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
index e318119d570d..aca9b0cfcfec 100644
--- a/arch/riscv/Kconfig.errata
+++ b/arch/riscv/Kconfig.errata
@@ -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
diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile
index bc6c77ba837d..02a7a3335b1d 100644
--- a/arch/riscv/errata/Makefile
+++ b/arch/riscv/errata/Makefile
@@ -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
index 000000000000..6278c389b801
--- /dev/null
+++ b/arch/riscv/errata/mips/Makefile
@@ -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
index 000000000000..e984a8152208
--- /dev/null
+++ b/arch/riscv/errata/mips/errata.c
@@ -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);
+ }
+ }
+}
diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
index 0e95539ba451..8407d1d535b8 100644
--- a/arch/riscv/include/asm/alternative.h
+++ b/arch/riscv/include/asm/alternative.h
@@ -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);
diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
index 0b749e710216..80bd52363c68 100644
--- a/arch/riscv/include/asm/cmpxchg.h
+++ b/arch/riscv/include/asm/cmpxchg.h
@@ -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) \
diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
index a2481f14b68d..6694b5ccdcf8 100644
--- a/arch/riscv/include/asm/errata_list.h
+++ b/arch/riscv/include/asm/errata_list.h
@@ -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.
diff --git a/arch/riscv/include/asm/errata_list_vendors.h b/arch/riscv/include/asm/errata_list_vendors.h
index d448b9ce7c7c..ec7eba373437 100644
--- a/arch/riscv/include/asm/errata_list_vendors.h
+++ b/arch/riscv/include/asm/errata_list_vendors.h
@@ -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 */
diff --git a/arch/riscv/include/asm/vdso/processor.h b/arch/riscv/include/asm/vdso/processor.h
index 98fb44336c05..c42f95dc8811 100644
--- a/arch/riscv/include/asm/vdso/processor.h
+++ b/arch/riscv/include/asm/vdso/processor.h
@@ -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();
}
diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
index 7eb3cb1215c6..7642704c7f18 100644
--- a/arch/riscv/kernel/alternative.c
+++ b/arch/riscv/kernel/alternative.c
@@ -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;
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index d0ded2438533..d3d92a4becc7 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -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>
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 85cb70b10c07..6091f3f06fa3 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -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>