xref: /linux/arch/riscv/errata/mips/errata.c (revision cb7e3669c683669d93139184adff68a7d9000536)
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 
errata_probe_pause(void)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 
mips_errata_probe(void)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 
mips_errata_patch_func(struct alt_entry * begin,struct alt_entry * end,unsigned long archid,unsigned long impid,unsigned int stage)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