xref: /linux/arch/riscv/errata/sifive/errata.c (revision 800149a77c2cb8746a94457939b1ba1e37d2c14e)
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>
71a0e5dbdSVincent Chen #include <linux/string.h>
81a0e5dbdSVincent Chen #include <linux/bug.h>
91a0e5dbdSVincent Chen #include <asm/patch.h>
101a0e5dbdSVincent Chen #include <asm/alternative.h>
111a0e5dbdSVincent Chen #include <asm/vendorid_list.h>
121a0e5dbdSVincent Chen #include <asm/errata_list.h>
131a0e5dbdSVincent Chen 
141a0e5dbdSVincent Chen struct errata_info_t {
151a0e5dbdSVincent Chen 	char name[ERRATA_STRING_LENGTH_MAX];
161a0e5dbdSVincent Chen 	bool (*check_func)(unsigned long  arch_id, unsigned long impid);
171a0e5dbdSVincent Chen };
181a0e5dbdSVincent Chen 
19*800149a7SVincent Chen static bool errata_cip_453_check_func(unsigned long  arch_id, unsigned long impid)
20*800149a7SVincent Chen {
21*800149a7SVincent Chen 	/*
22*800149a7SVincent Chen 	 * Affected cores:
23*800149a7SVincent Chen 	 * Architecture ID: 0x8000000000000007
24*800149a7SVincent Chen 	 * Implement ID: 0x20181004 <= impid <= 0x20191105
25*800149a7SVincent Chen 	 */
26*800149a7SVincent Chen 	if (arch_id != 0x8000000000000007 ||
27*800149a7SVincent Chen 	    (impid < 0x20181004 || impid > 0x20191105))
28*800149a7SVincent Chen 		return false;
29*800149a7SVincent Chen 	return true;
30*800149a7SVincent Chen }
31*800149a7SVincent Chen 
32*800149a7SVincent Chen static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
33*800149a7SVincent Chen 	{
34*800149a7SVincent Chen 		.name = "cip-453",
35*800149a7SVincent Chen 		.check_func = errata_cip_453_check_func
36*800149a7SVincent Chen 	},
37*800149a7SVincent Chen };
38*800149a7SVincent Chen 
391a0e5dbdSVincent Chen static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
401a0e5dbdSVincent Chen {
411a0e5dbdSVincent Chen 	int idx;
421a0e5dbdSVincent Chen 	u32 cpu_req_errata = 0;
431a0e5dbdSVincent Chen 
441a0e5dbdSVincent Chen 	for (idx = 0; idx < ERRATA_SIFIVE_NUMBER; idx++)
451a0e5dbdSVincent Chen 		if (errata_list[idx].check_func(archid, impid))
461a0e5dbdSVincent Chen 			cpu_req_errata |= (1U << idx);
471a0e5dbdSVincent Chen 
481a0e5dbdSVincent Chen 	return cpu_req_errata;
491a0e5dbdSVincent Chen }
501a0e5dbdSVincent Chen 
511a0e5dbdSVincent Chen static void __init warn_miss_errata(u32 miss_errata)
521a0e5dbdSVincent Chen {
531a0e5dbdSVincent Chen 	int i;
541a0e5dbdSVincent Chen 
551a0e5dbdSVincent Chen 	pr_warn("----------------------------------------------------------------\n");
561a0e5dbdSVincent Chen 	pr_warn("WARNING: Missing the following errata may cause potential issues\n");
571a0e5dbdSVincent Chen 	for (i = 0; i < ERRATA_SIFIVE_NUMBER; i++)
581a0e5dbdSVincent Chen 		if (miss_errata & 0x1 << i)
591a0e5dbdSVincent Chen 			pr_warn("\tSiFive Errata[%d]:%s\n", i, errata_list[i].name);
601a0e5dbdSVincent Chen 	pr_warn("Please enable the corresponding Kconfig to apply them\n");
611a0e5dbdSVincent Chen 	pr_warn("----------------------------------------------------------------\n");
621a0e5dbdSVincent Chen }
631a0e5dbdSVincent Chen 
641a0e5dbdSVincent Chen void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
651a0e5dbdSVincent Chen 				     unsigned long archid, unsigned long impid)
661a0e5dbdSVincent Chen {
671a0e5dbdSVincent Chen 	struct alt_entry *alt;
681a0e5dbdSVincent Chen 	u32 cpu_req_errata = sifive_errata_probe(archid, impid);
691a0e5dbdSVincent Chen 	u32 cpu_apply_errata = 0;
701a0e5dbdSVincent Chen 	u32 tmp;
711a0e5dbdSVincent Chen 
721a0e5dbdSVincent Chen 	for (alt = begin; alt < end; alt++) {
731a0e5dbdSVincent Chen 		if (alt->vendor_id != SIFIVE_VENDOR_ID)
741a0e5dbdSVincent Chen 			continue;
751a0e5dbdSVincent Chen 		if (alt->errata_id >= ERRATA_SIFIVE_NUMBER) {
761a0e5dbdSVincent Chen 			WARN(1, "This errata id:%d is not in kernel errata list", alt->errata_id);
771a0e5dbdSVincent Chen 			continue;
781a0e5dbdSVincent Chen 		}
791a0e5dbdSVincent Chen 
801a0e5dbdSVincent Chen 		tmp = (1U << alt->errata_id);
811a0e5dbdSVincent Chen 		if (cpu_req_errata & tmp) {
821a0e5dbdSVincent Chen 			patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
831a0e5dbdSVincent Chen 			cpu_apply_errata |= tmp;
841a0e5dbdSVincent Chen 		}
851a0e5dbdSVincent Chen 	}
861a0e5dbdSVincent Chen 	if (cpu_apply_errata != cpu_req_errata)
871a0e5dbdSVincent Chen 		warn_miss_errata(cpu_req_errata - cpu_apply_errata);
881a0e5dbdSVincent Chen }
89