errata.c (2131B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2021 Heiko Stuebner <heiko@sntech.de> 4 */ 5 6#include <linux/bug.h> 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/string.h> 10#include <linux/uaccess.h> 11#include <asm/alternative.h> 12#include <asm/cacheflush.h> 13#include <asm/errata_list.h> 14#include <asm/patch.h> 15#include <asm/vendorid_list.h> 16 17struct errata_info { 18 char name[ERRATA_STRING_LENGTH_MAX]; 19 bool (*check_func)(unsigned long arch_id, unsigned long impid); 20 unsigned int stage; 21}; 22 23static bool errata_mt_check_func(unsigned long arch_id, unsigned long impid) 24{ 25 if (arch_id != 0 || impid != 0) 26 return false; 27 return true; 28} 29 30static const struct errata_info errata_list[ERRATA_THEAD_NUMBER] = { 31 { 32 .name = "memory-types", 33 .stage = RISCV_ALTERNATIVES_EARLY_BOOT, 34 .check_func = errata_mt_check_func 35 }, 36}; 37 38static u32 thead_errata_probe(unsigned int stage, unsigned long archid, unsigned long impid) 39{ 40 const struct errata_info *info; 41 u32 cpu_req_errata = 0; 42 int idx; 43 44 for (idx = 0; idx < ERRATA_THEAD_NUMBER; idx++) { 45 info = &errata_list[idx]; 46 47 if ((stage == RISCV_ALTERNATIVES_MODULE || 48 info->stage == stage) && info->check_func(archid, impid)) 49 cpu_req_errata |= (1U << idx); 50 } 51 52 return cpu_req_errata; 53} 54 55void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, 56 unsigned long archid, unsigned long impid, 57 unsigned int stage) 58{ 59 struct alt_entry *alt; 60 u32 cpu_req_errata = thead_errata_probe(stage, archid, impid); 61 u32 tmp; 62 63 for (alt = begin; alt < end; alt++) { 64 if (alt->vendor_id != THEAD_VENDOR_ID) 65 continue; 66 if (alt->errata_id >= ERRATA_THEAD_NUMBER) 67 continue; 68 69 tmp = (1U << alt->errata_id); 70 if (cpu_req_errata & tmp) { 71 /* On vm-alternatives, the mmu isn't running yet */ 72 if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) 73 memcpy((void *)__pa_symbol(alt->old_ptr), 74 (void *)__pa_symbol(alt->alt_ptr), alt->alt_len); 75 else 76 patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len); 77 } 78 } 79 80 if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) 81 local_flush_icache_all(); 82}