diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata index a6aac8774f25..53e28e5b4f92 100644 --- a/arch/riscv/Kconfig.errata +++ b/arch/riscv/Kconfig.errata @@ -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" diff --git a/arch/riscv/errata/mips/Makefile b/arch/riscv/errata/mips/Makefile index 6278c389b801..137e700d9d3f 100644 --- a/arch/riscv/errata/mips/Makefile +++ b/arch/riscv/errata/mips/Makefile @@ -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 diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c index 2c3dc2259e93..ac9a12d0a30c 100644 --- a/arch/riscv/errata/mips/errata.c +++ b/arch/riscv/errata/mips/errata.c @@ -7,12 +7,13 @@ #include #include #include +#include #include #include #include #include -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(); }