xref: /linux/arch/riscv/errata/sifive/errata.c (revision 148ab873d8194cb44f29474da3b4428fa2e100d1)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021 Sifive.
4  */
5 
6 #include <linux/kernel.h>
7 #include <linux/memory.h>
8 #include <linux/module.h>
9 #include <linux/string.h>
10 #include <linux/bug.h>
11 #include <asm/text-patching.h>
12 #include <asm/alternative.h>
13 #include <asm/vendorid_list.h>
14 #include <asm/errata_list.h>
15 #include <asm/vendor_extensions.h>
16 
17 struct errata_info_t {
18 	char name[32];
19 	bool (*check_func)(unsigned long  arch_id, unsigned long impid);
20 };
21 
22 static bool errata_cip_453_check_func(unsigned long  arch_id, unsigned long impid)
23 {
24 	/*
25 	 * Affected cores:
26 	 * Architecture ID: 0x8000000000000007
27 	 * Implement ID: 0x20181004 <= impid <= 0x20191105
28 	 */
29 	if (arch_id != 0x8000000000000007 ||
30 	    (impid < 0x20181004 || impid > 0x20191105))
31 		return false;
32 	return true;
33 }
34 
35 static bool errata_cip_1200_check_func(unsigned long  arch_id, unsigned long impid)
36 {
37 	/*
38 	 * Affected cores:
39 	 * Architecture ID: 0x8000000000000007 or 0x1
40 	 * Implement ID: mimpid[23:0] <= 0x200630 and mimpid != 0x01200626
41 	 */
42 	if (arch_id != 0x8000000000000007 && arch_id != 0x1)
43 		return false;
44 	if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626)
45 		return false;
46 
47 #ifdef CONFIG_MMU
48 	tlb_flush_all_threshold = 0;
49 #endif
50 
51 	return true;
52 }
53 
54 static bool errata_mal_9092_check_func(unsigned long  arch_id, unsigned long impid)
55 {
56 	/*
57 	 * Affected cores:
58 	 * Architecture ID: 0x8000000000000109
59 	 * Implementation ID: 0x19251031, 0x19251217, 0x19260320
60 	 */
61 
62 	if (arch_id != 0x8000000000000109)
63 		return false;
64 	if (impid != 0x19251031 && impid != 0x19251217 && impid != 0x19260320)
65 		return false;
66 
67 	return true;
68 }
69 
70 static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
71 	{
72 		.name = "cip-453",
73 		.check_func = errata_cip_453_check_func
74 	},
75 	{
76 		.name = "cip-1200",
77 		.check_func = errata_cip_1200_check_func
78 	},
79 	{
80 		.name = "mal-9092",
81 		.check_func = errata_mal_9092_check_func
82 	},
83 };
84 
85 static u32 __init_or_module sifive_errata_probe(unsigned long archid,
86 						unsigned long impid)
87 {
88 	int idx;
89 	u32 cpu_req_errata = 0;
90 
91 	for (idx = 0; idx < ERRATA_SIFIVE_NUMBER; idx++)
92 		if (errata_list[idx].check_func(archid, impid))
93 			cpu_req_errata |= (1U << idx);
94 
95 	return cpu_req_errata;
96 }
97 
98 void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
99 			      unsigned long archid, unsigned long impid,
100 			      unsigned int stage)
101 {
102 	struct alt_entry *alt;
103 	u32 cpu_req_errata;
104 	u32 tmp;
105 
106 	BUILD_BUG_ON(ERRATA_SIFIVE_NUMBER >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
107 
108 	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
109 		return;
110 
111 	cpu_req_errata = sifive_errata_probe(archid, impid);
112 
113 	for (alt = begin; alt < end; alt++) {
114 		if (alt->vendor_id != SIFIVE_VENDOR_ID)
115 			continue;
116 		if (alt->patch_id >= ERRATA_SIFIVE_NUMBER)
117 			continue;
118 
119 		tmp = (1U << alt->patch_id);
120 		if (cpu_req_errata & tmp) {
121 			mutex_lock(&text_mutex);
122 			patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt),
123 					  alt->alt_len);
124 			mutex_unlock(&text_mutex);
125 		}
126 	}
127 }
128