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/memory.h> 9 #include <linux/module.h> 10 #include <linux/string.h> 11 #include <linux/uaccess.h> 12 #include <asm/alternative.h> 13 #include <asm/cacheflush.h> 14 #include <asm/cpufeature.h> 15 #include <asm/errata_list.h> 16 #include <asm/hwprobe.h> 17 #include <asm/patch.h> 18 #include <asm/vendorid_list.h> 19 20 static bool errata_probe_pbmt(unsigned int stage, 21 unsigned long arch_id, unsigned long impid) 22 { 23 if (!IS_ENABLED(CONFIG_ERRATA_THEAD_PBMT)) 24 return false; 25 26 if (arch_id != 0 || impid != 0) 27 return false; 28 29 if (stage == RISCV_ALTERNATIVES_EARLY_BOOT || 30 stage == RISCV_ALTERNATIVES_MODULE) 31 return true; 32 33 return false; 34 } 35 36 static bool errata_probe_cmo(unsigned int stage, 37 unsigned long arch_id, unsigned long impid) 38 { 39 if (!IS_ENABLED(CONFIG_ERRATA_THEAD_CMO)) 40 return false; 41 42 if (arch_id != 0 || impid != 0) 43 return false; 44 45 if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) 46 return false; 47 48 riscv_cbom_block_size = L1_CACHE_BYTES; 49 riscv_noncoherent_supported(); 50 return true; 51 } 52 53 static bool errata_probe_pmu(unsigned int stage, 54 unsigned long arch_id, unsigned long impid) 55 { 56 if (!IS_ENABLED(CONFIG_ERRATA_THEAD_PMU)) 57 return false; 58 59 /* target-c9xx cores report arch_id and impid as 0 */ 60 if (arch_id != 0 || impid != 0) 61 return false; 62 63 if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) 64 return false; 65 66 return true; 67 } 68 69 static u32 thead_errata_probe(unsigned int stage, 70 unsigned long archid, unsigned long impid) 71 { 72 u32 cpu_req_errata = 0; 73 74 if (errata_probe_pbmt(stage, archid, impid)) 75 cpu_req_errata |= BIT(ERRATA_THEAD_PBMT); 76 77 if (errata_probe_cmo(stage, archid, impid)) 78 cpu_req_errata |= BIT(ERRATA_THEAD_CMO); 79 80 if (errata_probe_pmu(stage, archid, impid)) 81 cpu_req_errata |= BIT(ERRATA_THEAD_PMU); 82 83 return cpu_req_errata; 84 } 85 86 void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, 87 unsigned long archid, unsigned long impid, 88 unsigned int stage) 89 { 90 struct alt_entry *alt; 91 u32 cpu_req_errata = thead_errata_probe(stage, archid, impid); 92 u32 tmp; 93 void *oldptr, *altptr; 94 95 for (alt = begin; alt < end; alt++) { 96 if (alt->vendor_id != THEAD_VENDOR_ID) 97 continue; 98 if (alt->patch_id >= ERRATA_THEAD_NUMBER) 99 continue; 100 101 tmp = (1U << alt->patch_id); 102 if (cpu_req_errata & tmp) { 103 oldptr = ALT_OLD_PTR(alt); 104 altptr = ALT_ALT_PTR(alt); 105 106 /* On vm-alternatives, the mmu isn't running yet */ 107 if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) { 108 memcpy(oldptr, altptr, alt->alt_len); 109 } else { 110 mutex_lock(&text_mutex); 111 patch_text_nosync(oldptr, altptr, alt->alt_len); 112 mutex_unlock(&text_mutex); 113 } 114 } 115 } 116 117 if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) 118 local_flush_icache_all(); 119 } 120 121 void thead_feature_probe_func(unsigned int cpu, 122 unsigned long archid, 123 unsigned long impid) 124 { 125 if ((archid == 0) && (impid == 0)) 126 per_cpu(misaligned_access_speed, cpu) = RISCV_HWPROBE_MISALIGNED_FAST; 127 } 128