Skip to content

Commit 0b0ca95

Browse files
djtodoroPaul Walmsley
authored andcommitted
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>
1 parent c9a9fc2 commit 0b0ca95

12 files changed

Lines changed: 127 additions & 3 deletions

File tree

arch/riscv/Kconfig.errata

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,29 @@ config ERRATA_ANDES_CMO
2121

2222
If you don't know what to do here, say "Y".
2323

24+
config ERRATA_MIPS
25+
bool "MIPS errata"
26+
depends on RISCV_ALTERNATIVE
27+
help
28+
All MIPS errata Kconfig depend on this Kconfig. Disabling
29+
this Kconfig will disable all MIPS errata. Please say "Y"
30+
here if your platform uses MIPS CPU cores.
31+
32+
Otherwise, please say "N" here to avoid unnecessary overhead.
33+
34+
config ERRATA_MIPS_P8700_PAUSE_OPCODE
35+
bool "Fix the PAUSE Opcode for MIPS P8700"
36+
depends on ERRATA_MIPS && 64BIT
37+
default n
38+
help
39+
The RISCV MIPS P8700 uses a different opcode for PAUSE.
40+
It is a 'hint' encoding of the SLLI instruction,
41+
with rd=0, rs1=0 and imm=5. It will behave as a NOP
42+
instruction if no additional behavior beyond that of
43+
SLLI is implemented.
44+
45+
If you are not using the P8700 processor, say n.
46+
2447
config ERRATA_SIFIVE
2548
bool "SiFive errata"
2649
depends on RISCV_ALTERNATIVE

arch/riscv/errata/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ endif
1313
endif
1414

1515
obj-$(CONFIG_ERRATA_ANDES) += andes/
16+
obj-$(CONFIG_ERRATA_MIPS) += mips/
1617
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
1718
obj-$(CONFIG_ERRATA_THEAD) += thead/

arch/riscv/errata/mips/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
2+
CFLAGS_errata.o := -mcmodel=medany
3+
endif
4+
5+
obj-y += errata.o

arch/riscv/errata/mips/errata.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2025 MIPS.
4+
*/
5+
6+
#include <linux/memory.h>
7+
#include <linux/module.h>
8+
#include <asm/text-patching.h>
9+
#include <asm/alternative.h>
10+
#include <asm/errata_list.h>
11+
#include <asm/vendorid_list.h>
12+
#include <asm/vendor_extensions.h>
13+
#include <asm/vendor_extensions/mips.h>
14+
15+
static inline bool errata_probe_pause(void)
16+
{
17+
if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE))
18+
return false;
19+
20+
if (!riscv_isa_vendor_extension_available(MIPS_VENDOR_ID, XMIPSEXECTL))
21+
return false;
22+
23+
return true;
24+
}
25+
26+
static u32 mips_errata_probe(void)
27+
{
28+
u32 cpu_req_errata = 0;
29+
30+
if (errata_probe_pause())
31+
cpu_req_errata |= BIT(ERRATA_MIPS_P8700_PAUSE_OPCODE);
32+
33+
return cpu_req_errata;
34+
}
35+
36+
void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
37+
unsigned long archid, unsigned long impid,
38+
unsigned int stage)
39+
{
40+
struct alt_entry *alt;
41+
u32 cpu_req_errata = mips_errata_probe();
42+
u32 tmp;
43+
44+
BUILD_BUG_ON(ERRATA_MIPS_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
45+
46+
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
47+
return;
48+
49+
for (alt = begin; alt < end; alt++) {
50+
if (alt->vendor_id != MIPS_VENDOR_ID)
51+
continue;
52+
53+
if (alt->patch_id >= ERRATA_MIPS_NUMBER) {
54+
WARN(1, "MIPS errata id:%d not in kernel errata list\n",
55+
alt->patch_id);
56+
continue;
57+
}
58+
59+
tmp = (1U << alt->patch_id);
60+
if (cpu_req_errata && tmp) {
61+
mutex_lock(&text_mutex);
62+
patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt),
63+
alt->alt_len);
64+
mutex_unlock(&text_mutex);
65+
}
66+
}
67+
}

arch/riscv/include/asm/alternative.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ struct alt_entry {
4848
void andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
4949
unsigned long archid, unsigned long impid,
5050
unsigned int stage);
51+
void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
52+
unsigned long archid, unsigned long impid,
53+
unsigned int stage);
5154
void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
5255
unsigned long archid, unsigned long impid,
5356
unsigned int stage);

arch/riscv/include/asm/cmpxchg.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <asm/insn-def.h>
1515
#include <asm/cpufeature-macros.h>
1616
#include <asm/processor.h>
17+
#include <asm/errata_list.h>
1718

1819
#define __arch_xchg_masked(sc_sfx, swap_sfx, prepend, sc_append, \
1920
swap_append, r, p, n) \
@@ -438,7 +439,7 @@ static __always_inline void __cmpwait(volatile void *ptr,
438439
return;
439440

440441
no_zawrs:
441-
asm volatile(RISCV_PAUSE : : : "memory");
442+
ALT_RISCV_PAUSE();
442443
}
443444

444445
#define __cmpwait_relaxed(ptr, val) \

arch/riscv/include/asm/errata_list.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
#ifndef ASM_ERRATA_LIST_H
66
#define ASM_ERRATA_LIST_H
77

8-
#include <asm/alternative.h>
98
#include <asm/csr.h>
109
#include <asm/insn-def.h>
1110
#include <asm/hwcap.h>
1211
#include <asm/vendorid_list.h>
1312
#include <asm/errata_list_vendors.h>
13+
#include <asm/vendor_extensions/mips.h>
1414

1515
#ifdef __ASSEMBLER__
1616

@@ -42,6 +42,17 @@ asm(ALTERNATIVE("sfence.vma %0, %1", "sfence.vma", SIFIVE_VENDOR_ID, \
4242
ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \
4343
: : "r" (addr), "r" (asid) : "memory")
4444

45+
#define ALT_RISCV_PAUSE() \
46+
asm(ALTERNATIVE( \
47+
RISCV_PAUSE, /* Original RISC‑V pause insn */ \
48+
MIPS_PAUSE, /* Replacement for MIPS P8700 */ \
49+
MIPS_VENDOR_ID, /* Vendor ID to match */ \
50+
ERRATA_MIPS_P8700_PAUSE_OPCODE, /* patch_id */ \
51+
CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE) \
52+
: /* no outputs */ \
53+
: /* no inputs */ \
54+
: "memory")
55+
4556
/*
4657
* _val is marked as "will be overwritten", so need to set it to 0
4758
* in the default case.

arch/riscv/include/asm/errata_list_vendors.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,9 @@
2121
#define ERRATA_THEAD_NUMBER 3
2222
#endif
2323

24+
#ifdef CONFIG_ERRATA_MIPS
25+
#define ERRATA_MIPS_P8700_PAUSE_OPCODE 0
26+
#define ERRATA_MIPS_NUMBER 1
27+
#endif
28+
2429
#endif /* ASM_ERRATA_LIST_VENDORS_H */

arch/riscv/include/asm/vdso/processor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef __ASSEMBLER__
66

77
#include <asm/barrier.h>
8+
#include <asm/errata_list.h>
89
#include <asm/insn-def.h>
910

1011
static inline void cpu_relax(void)
@@ -19,7 +20,7 @@ static inline void cpu_relax(void)
1920
* Reduce instruction retirement.
2021
* This assumes the PC changes.
2122
*/
22-
__asm__ __volatile__ (RISCV_PAUSE);
23+
ALT_RISCV_PAUSE();
2324
barrier();
2425
}
2526

arch/riscv/kernel/alternative.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info
4747
cpu_mfr_info->patch_func = andes_errata_patch_func;
4848
break;
4949
#endif
50+
#ifdef CONFIG_ERRATA_MIPS
51+
case MIPS_VENDOR_ID:
52+
cpu_mfr_info->patch_func = mips_errata_patch_func;
53+
break;
54+
#endif
5055
#ifdef CONFIG_ERRATA_SIFIVE
5156
case SIFIVE_VENDOR_ID:
5257
cpu_mfr_info->patch_func = sifive_errata_patch_func;

0 commit comments

Comments
 (0)