xref: /linux/arch/riscv/errata/sifive/errata.c (revision a35707c3d850dda0ceefb75b1b3bd191921d5765)
11a0e5dbdSVincent Chen // SPDX-License-Identifier: GPL-2.0-only
21a0e5dbdSVincent Chen /*
31a0e5dbdSVincent Chen  * Copyright (C) 2021 Sifive.
41a0e5dbdSVincent Chen  */
51a0e5dbdSVincent Chen 
61a0e5dbdSVincent Chen #include <linux/kernel.h>
7a8e91016SHeiko Stuebner #include <linux/module.h>
81a0e5dbdSVincent Chen #include <linux/string.h>
91a0e5dbdSVincent Chen #include <linux/bug.h>
101a0e5dbdSVincent Chen #include <asm/patch.h>
111a0e5dbdSVincent Chen #include <asm/alternative.h>
121a0e5dbdSVincent Chen #include <asm/vendorid_list.h>
131a0e5dbdSVincent Chen #include <asm/errata_list.h>
141a0e5dbdSVincent Chen 
151a0e5dbdSVincent Chen struct errata_info_t {
161a0e5dbdSVincent Chen 	char name[ERRATA_STRING_LENGTH_MAX];
171a0e5dbdSVincent Chen 	bool (*check_func)(unsigned long  arch_id, unsigned long impid);
181a0e5dbdSVincent Chen };
191a0e5dbdSVincent Chen 
20800149a7SVincent Chen static bool errata_cip_453_check_func(unsigned long  arch_id, unsigned long impid)
21800149a7SVincent Chen {
22800149a7SVincent Chen 	/*
23800149a7SVincent Chen 	 * Affected cores:
24800149a7SVincent Chen 	 * Architecture ID: 0x8000000000000007
25800149a7SVincent Chen 	 * Implement ID: 0x20181004 <= impid <= 0x20191105
26800149a7SVincent Chen 	 */
27800149a7SVincent Chen 	if (arch_id != 0x8000000000000007 ||
28800149a7SVincent Chen 	    (impid < 0x20181004 || impid > 0x20191105))
29800149a7SVincent Chen 		return false;
30800149a7SVincent Chen 	return true;
31800149a7SVincent Chen }
32800149a7SVincent Chen 
33bff3ff52SVincent Chen static bool errata_cip_1200_check_func(unsigned long  arch_id, unsigned long impid)
34bff3ff52SVincent Chen {
35bff3ff52SVincent Chen 	/*
36bff3ff52SVincent Chen 	 * Affected cores:
37bff3ff52SVincent Chen 	 * Architecture ID: 0x8000000000000007 or 0x1
38bff3ff52SVincent Chen 	 * Implement ID: mimpid[23:0] <= 0x200630 and mimpid != 0x01200626
39bff3ff52SVincent Chen 	 */
40bff3ff52SVincent Chen 	if (arch_id != 0x8000000000000007 && arch_id != 0x1)
41bff3ff52SVincent Chen 		return false;
42bff3ff52SVincent Chen 	if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626)
43bff3ff52SVincent Chen 		return false;
44bff3ff52SVincent Chen 	return true;
45bff3ff52SVincent Chen }
46bff3ff52SVincent Chen 
47800149a7SVincent Chen static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
48800149a7SVincent Chen 	{
49800149a7SVincent Chen 		.name = "cip-453",
50800149a7SVincent Chen 		.check_func = errata_cip_453_check_func
51800149a7SVincent Chen 	},
52bff3ff52SVincent Chen 	{
53bff3ff52SVincent Chen 		.name = "cip-1200",
54bff3ff52SVincent Chen 		.check_func = errata_cip_1200_check_func
55bff3ff52SVincent Chen 	},
56800149a7SVincent Chen };
57800149a7SVincent Chen 
58a8e91016SHeiko Stuebner static u32 __init_or_module sifive_errata_probe(unsigned long archid,
59a8e91016SHeiko Stuebner 						unsigned long impid)
601a0e5dbdSVincent Chen {
611a0e5dbdSVincent Chen 	int idx;
621a0e5dbdSVincent Chen 	u32 cpu_req_errata = 0;
631a0e5dbdSVincent Chen 
641a0e5dbdSVincent Chen 	for (idx = 0; idx < ERRATA_SIFIVE_NUMBER; idx++)
651a0e5dbdSVincent Chen 		if (errata_list[idx].check_func(archid, impid))
661a0e5dbdSVincent Chen 			cpu_req_errata |= (1U << idx);
671a0e5dbdSVincent Chen 
681a0e5dbdSVincent Chen 	return cpu_req_errata;
691a0e5dbdSVincent Chen }
701a0e5dbdSVincent Chen 
71a8e91016SHeiko Stuebner static void __init_or_module warn_miss_errata(u32 miss_errata)
721a0e5dbdSVincent Chen {
731a0e5dbdSVincent Chen 	int i;
741a0e5dbdSVincent Chen 
751a0e5dbdSVincent Chen 	pr_warn("----------------------------------------------------------------\n");
761a0e5dbdSVincent Chen 	pr_warn("WARNING: Missing the following errata may cause potential issues\n");
771a0e5dbdSVincent Chen 	for (i = 0; i < ERRATA_SIFIVE_NUMBER; i++)
781a0e5dbdSVincent Chen 		if (miss_errata & 0x1 << i)
791a0e5dbdSVincent Chen 			pr_warn("\tSiFive Errata[%d]:%s\n", i, errata_list[i].name);
801a0e5dbdSVincent Chen 	pr_warn("Please enable the corresponding Kconfig to apply them\n");
811a0e5dbdSVincent Chen 	pr_warn("----------------------------------------------------------------\n");
821a0e5dbdSVincent Chen }
831a0e5dbdSVincent Chen 
84a8e91016SHeiko Stuebner void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
85a8e91016SHeiko Stuebner 					       struct alt_entry *end,
86a8e91016SHeiko Stuebner 					       unsigned long archid,
87a8e91016SHeiko Stuebner 					       unsigned long impid,
88d14ca1f8SHeiko Stuebner 					       unsigned int stage)
891a0e5dbdSVincent Chen {
901a0e5dbdSVincent Chen 	struct alt_entry *alt;
91*a35707c3SHeiko Stuebner 	u32 cpu_req_errata;
921a0e5dbdSVincent Chen 	u32 cpu_apply_errata = 0;
931a0e5dbdSVincent Chen 	u32 tmp;
941a0e5dbdSVincent Chen 
95*a35707c3SHeiko Stuebner 	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
96*a35707c3SHeiko Stuebner 		return;
97*a35707c3SHeiko Stuebner 
98*a35707c3SHeiko Stuebner 	cpu_req_errata = sifive_errata_probe(archid, impid);
99*a35707c3SHeiko Stuebner 
1001a0e5dbdSVincent Chen 	for (alt = begin; alt < end; alt++) {
1011a0e5dbdSVincent Chen 		if (alt->vendor_id != SIFIVE_VENDOR_ID)
1021a0e5dbdSVincent Chen 			continue;
1031a0e5dbdSVincent Chen 		if (alt->errata_id >= ERRATA_SIFIVE_NUMBER) {
1041a0e5dbdSVincent Chen 			WARN(1, "This errata id:%d is not in kernel errata list", alt->errata_id);
1051a0e5dbdSVincent Chen 			continue;
1061a0e5dbdSVincent Chen 		}
1071a0e5dbdSVincent Chen 
1081a0e5dbdSVincent Chen 		tmp = (1U << alt->errata_id);
1091a0e5dbdSVincent Chen 		if (cpu_req_errata & tmp) {
1101a0e5dbdSVincent Chen 			patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
1111a0e5dbdSVincent Chen 			cpu_apply_errata |= tmp;
1121a0e5dbdSVincent Chen 		}
1131a0e5dbdSVincent Chen 	}
1141a0e5dbdSVincent Chen 	if (cpu_apply_errata != cpu_req_errata)
1151a0e5dbdSVincent Chen 		warn_miss_errata(cpu_req_errata - cpu_apply_errata);
1161a0e5dbdSVincent Chen }
117