1*0b0ca959SDjordje Todorovic // SPDX-License-Identifier: GPL-2.0-only
2*0b0ca959SDjordje Todorovic /*
3*0b0ca959SDjordje Todorovic * Copyright (C) 2025 MIPS.
4*0b0ca959SDjordje Todorovic */
5*0b0ca959SDjordje Todorovic
6*0b0ca959SDjordje Todorovic #include <linux/memory.h>
7*0b0ca959SDjordje Todorovic #include <linux/module.h>
8*0b0ca959SDjordje Todorovic #include <asm/text-patching.h>
9*0b0ca959SDjordje Todorovic #include <asm/alternative.h>
10*0b0ca959SDjordje Todorovic #include <asm/errata_list.h>
11*0b0ca959SDjordje Todorovic #include <asm/vendorid_list.h>
12*0b0ca959SDjordje Todorovic #include <asm/vendor_extensions.h>
13*0b0ca959SDjordje Todorovic #include <asm/vendor_extensions/mips.h>
14*0b0ca959SDjordje Todorovic
errata_probe_pause(void)15*0b0ca959SDjordje Todorovic static inline bool errata_probe_pause(void)
16*0b0ca959SDjordje Todorovic {
17*0b0ca959SDjordje Todorovic if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE))
18*0b0ca959SDjordje Todorovic return false;
19*0b0ca959SDjordje Todorovic
20*0b0ca959SDjordje Todorovic if (!riscv_isa_vendor_extension_available(MIPS_VENDOR_ID, XMIPSEXECTL))
21*0b0ca959SDjordje Todorovic return false;
22*0b0ca959SDjordje Todorovic
23*0b0ca959SDjordje Todorovic return true;
24*0b0ca959SDjordje Todorovic }
25*0b0ca959SDjordje Todorovic
mips_errata_probe(void)26*0b0ca959SDjordje Todorovic static u32 mips_errata_probe(void)
27*0b0ca959SDjordje Todorovic {
28*0b0ca959SDjordje Todorovic u32 cpu_req_errata = 0;
29*0b0ca959SDjordje Todorovic
30*0b0ca959SDjordje Todorovic if (errata_probe_pause())
31*0b0ca959SDjordje Todorovic cpu_req_errata |= BIT(ERRATA_MIPS_P8700_PAUSE_OPCODE);
32*0b0ca959SDjordje Todorovic
33*0b0ca959SDjordje Todorovic return cpu_req_errata;
34*0b0ca959SDjordje Todorovic }
35*0b0ca959SDjordje Todorovic
mips_errata_patch_func(struct alt_entry * begin,struct alt_entry * end,unsigned long archid,unsigned long impid,unsigned int stage)36*0b0ca959SDjordje Todorovic void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
37*0b0ca959SDjordje Todorovic unsigned long archid, unsigned long impid,
38*0b0ca959SDjordje Todorovic unsigned int stage)
39*0b0ca959SDjordje Todorovic {
40*0b0ca959SDjordje Todorovic struct alt_entry *alt;
41*0b0ca959SDjordje Todorovic u32 cpu_req_errata = mips_errata_probe();
42*0b0ca959SDjordje Todorovic u32 tmp;
43*0b0ca959SDjordje Todorovic
44*0b0ca959SDjordje Todorovic BUILD_BUG_ON(ERRATA_MIPS_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
45*0b0ca959SDjordje Todorovic
46*0b0ca959SDjordje Todorovic if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
47*0b0ca959SDjordje Todorovic return;
48*0b0ca959SDjordje Todorovic
49*0b0ca959SDjordje Todorovic for (alt = begin; alt < end; alt++) {
50*0b0ca959SDjordje Todorovic if (alt->vendor_id != MIPS_VENDOR_ID)
51*0b0ca959SDjordje Todorovic continue;
52*0b0ca959SDjordje Todorovic
53*0b0ca959SDjordje Todorovic if (alt->patch_id >= ERRATA_MIPS_NUMBER) {
54*0b0ca959SDjordje Todorovic WARN(1, "MIPS errata id:%d not in kernel errata list\n",
55*0b0ca959SDjordje Todorovic alt->patch_id);
56*0b0ca959SDjordje Todorovic continue;
57*0b0ca959SDjordje Todorovic }
58*0b0ca959SDjordje Todorovic
59*0b0ca959SDjordje Todorovic tmp = (1U << alt->patch_id);
60*0b0ca959SDjordje Todorovic if (cpu_req_errata && tmp) {
61*0b0ca959SDjordje Todorovic mutex_lock(&text_mutex);
62*0b0ca959SDjordje Todorovic patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt),
63*0b0ca959SDjordje Todorovic alt->alt_len);
64*0b0ca959SDjordje Todorovic mutex_unlock(&text_mutex);
65*0b0ca959SDjordje Todorovic }
66*0b0ca959SDjordje Todorovic }
67*0b0ca959SDjordje Todorovic }
68