riscv: Add support for early boot errata application on MIPS chips

MIPS errata implementation previously skipped early boot application
entirely. Although the only currently existing MIPS erratum does not
require this, amending this now should make any future addition easier to
implement.

This commit was based on the existing T-Head implementation.

Suggested-by: Jesse Taube <jtaubepe@redhat.com>
Link: https://lore.kernel.org/linux-riscv/CADRr4bcbD57hmR0XGgo8BjgNp4shEADOondZEtwscCJ9-nxXRQ@mail.gmail.com/
Signed-off-by: Aleksa Paunovic <aleksa.paunovic@htecgroup.com>
Link: https://patch.msgid.link/20260810-p8700-early-boot-v1-1-5c4aa08d500f@htecgroup.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>
This commit is contained in:
Aleksa Paunovic 2026-10-05 19:02:53 -06:00 committed by Paul Walmsley
parent 282f4a8aa9
commit 30755e71ab
3 changed files with 30 additions and 15 deletions

View File

@ -24,6 +24,7 @@ config ERRATA_ANDES_CMO
config ERRATA_MIPS
bool "MIPS errata"
depends on RISCV_ALTERNATIVE
select RISCV_ALTERNATIVE_EARLY
help
All MIPS errata Kconfig depend on this Kconfig. Disabling
this Kconfig will disable all MIPS errata. Please say "Y"

View File

@ -1,5 +1,11 @@
ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
CFLAGS_errata.o := -mcmodel=medany
ifdef CONFIG_FTRACE
CFLAGS_REMOVE_errata.o = $(CC_FLAGS_FTRACE)
endif
ifdef CONFIG_KASAN
KASAN_SANITIZE_errata.o := n
endif
endif
obj-y += errata.o

View File

@ -7,12 +7,13 @@
#include <linux/module.h>
#include <asm/text-patching.h>
#include <asm/alternative.h>
#include <asm/cacheflush.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)
static inline bool errata_probe_pause(unsigned int stage)
{
if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE))
return false;
@ -20,14 +21,17 @@ static inline bool errata_probe_pause(void)
if (!riscv_isa_vendor_extension_available(MIPS_VENDOR_ID, XMIPSEXECTL))
return false;
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
return false;
return true;
}
static u32 mips_errata_probe(void)
static u32 mips_errata_probe(unsigned int stage)
{
u32 cpu_req_errata = 0;
if (errata_probe_pause())
if (errata_probe_pause(stage))
cpu_req_errata |= BIT(ERRATA_MIPS_P8700_PAUSE_OPCODE);
return cpu_req_errata;
@ -38,30 +42,34 @@ void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned int stage)
{
struct alt_entry *alt;
u32 cpu_req_errata = mips_errata_probe();
u32 cpu_req_errata = mips_errata_probe(stage);
u32 tmp;
void *oldptr, *altptr;
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);
if (alt->patch_id >= ERRATA_MIPS_NUMBER)
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);
oldptr = ALT_OLD_PTR(alt);
altptr = ALT_ALT_PTR(alt);
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) {
memcpy(oldptr, altptr, alt->alt_len);
} else {
mutex_lock(&text_mutex);
patch_text_nosync(oldptr, altptr, alt->alt_len);
mutex_unlock(&text_mutex);
}
}
}
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
local_flush_icache_all();
}