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 } 68