1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021 Sifive.
4  */
5 
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/string.h>
9 #include <linux/bug.h>
10 #include <asm/patch.h>
11 #include <asm/alternative.h>
12 #include <asm/vendorid_list.h>
13 #include <asm/errata_list.h>
14 
15 struct errata_info_t {
16 	char name[ERRATA_STRING_LENGTH_MAX];
17 	bool (*check_func)(unsigned long  arch_id, unsigned long impid);
18 };
19 
errata_cip_453_check_func(unsigned long arch_id,unsigned long impid)20 static bool errata_cip_453_check_func(unsigned long  arch_id, unsigned long impid)
21 {
22 	/*
23 	 * Affected cores:
24 	 * Architecture ID: 0x8000000000000007
25 	 * Implement ID: 0x20181004 <= impid <= 0x20191105
26 	 */
27 	if (arch_id != 0x8000000000000007 ||
28 	    (impid < 0x20181004 || impid > 0x20191105))
29 		return false;
30 	return true;
31 }
32 
errata_cip_1200_check_func(unsigned long arch_id,unsigned long impid)33 static bool errata_cip_1200_check_func(unsigned long  arch_id, unsigned long impid)
34 {
35 	/*
36 	 * Affected cores:
37 	 * Architecture ID: 0x8000000000000007 or 0x1
38 	 * Implement ID: mimpid[23:0] <= 0x200630 and mimpid != 0x01200626
39 	 */
40 	if (arch_id != 0x8000000000000007 && arch_id != 0x1)
41 		return false;
42 	if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626)
43 		return false;
44 	return true;
45 }
46 
47 static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
48 	{
49 		.name = "cip-453",
50 		.check_func = errata_cip_453_check_func
51 	},
52 	{
53 		.name = "cip-1200",
54 		.check_func = errata_cip_1200_check_func
55 	},
56 };
57 
sifive_errata_probe(unsigned long archid,unsigned long impid)58 static u32 __init_or_module sifive_errata_probe(unsigned long archid,
59 						unsigned long impid)
60 {
61 	int idx;
62 	u32 cpu_req_errata = 0;
63 
64 	for (idx = 0; idx < ERRATA_SIFIVE_NUMBER; idx++)
65 		if (errata_list[idx].check_func(archid, impid))
66 			cpu_req_errata |= (1U << idx);
67 
68 	return cpu_req_errata;
69 }
70 
warn_miss_errata(u32 miss_errata)71 static void __init_or_module warn_miss_errata(u32 miss_errata)
72 {
73 	int i;
74 
75 	pr_warn("----------------------------------------------------------------\n");
76 	pr_warn("WARNING: Missing the following errata may cause potential issues\n");
77 	for (i = 0; i < ERRATA_SIFIVE_NUMBER; i++)
78 		if (miss_errata & 0x1 << i)
79 			pr_warn("\tSiFive Errata[%d]:%s\n", i, errata_list[i].name);
80 	pr_warn("Please enable the corresponding Kconfig to apply them\n");
81 	pr_warn("----------------------------------------------------------------\n");
82 }
83 
sifive_errata_patch_func(struct alt_entry * begin,struct alt_entry * end,unsigned long archid,unsigned long impid,unsigned int stage)84 void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
85 					       struct alt_entry *end,
86 					       unsigned long archid,
87 					       unsigned long impid,
88 					       unsigned int stage)
89 {
90 	struct alt_entry *alt;
91 	u32 cpu_req_errata;
92 	u32 cpu_apply_errata = 0;
93 	u32 tmp;
94 
95 	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
96 		return;
97 
98 	cpu_req_errata = sifive_errata_probe(archid, impid);
99 
100 	for (alt = begin; alt < end; alt++) {
101 		if (alt->vendor_id != SIFIVE_VENDOR_ID)
102 			continue;
103 		if (alt->errata_id >= ERRATA_SIFIVE_NUMBER) {
104 			WARN(1, "This errata id:%d is not in kernel errata list", alt->errata_id);
105 			continue;
106 		}
107 
108 		tmp = (1U << alt->errata_id);
109 		if (cpu_req_errata & tmp) {
110 			patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
111 			cpu_apply_errata |= tmp;
112 		}
113 	}
114 	if (stage != RISCV_ALTERNATIVES_MODULE &&
115 	    cpu_apply_errata != cpu_req_errata)
116 		warn_miss_errata(cpu_req_errata - cpu_apply_errata);
117 }
118