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>
This commit is contained in:
Djordje Todorovic 2025-07-24 17:23:31 +02:00 committed by Paul Walmsley
parent c9a9fc2322
commit 0b0ca959d2
12 changed files with 127 additions and 3 deletions

View 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

View 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/

View File

@ -0,0 +1,5 @@
ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
CFLAGS_errata.o := -mcmodel=medany
endif
obj-y += errata.o

View File

@ -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);
}
}
}

View 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);

View 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) \

View 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 RISCV 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.

View 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 */

View 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();
}

View 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;

View 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>

View 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>