Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) * * Modifications for ppc64: * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> */ #include <linux/string.h> #include <linux/sched.h> #include <linux/threads.h> #include <linux/init.h> #include <linux/export.h> #include <linux/jump_label.h> #include <linux/of.h> #include <asm/cputable.h> #include <asm/mce.h> #include <asm/mmu.h> #include <asm/setup.h> #include <asm/cpu_setup.h> static struct cpu_spec the_cpu_spec __read_mostly; struct cpu_spec* cur_cpu_spec __read_mostly = NULL; EXPORT_SYMBOL(cur_cpu_spec); /* The platform string corresponding to the real PVR */ const char *powerpc_base_platform; #include "cpu_specs.h" void __init set_cur_cpu_spec(struct cpu_spec *s) { struct cpu_spec *t = &the_cpu_spec; t = PTRRELOC(t); /* * use memcpy() instead of *t = *s so that GCC replaces it * by __memcpy() when KASAN is active */ memcpy(t, s, sizeof(*t)); *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec; } static struct cpu_spec * __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s) { struct cpu_spec *t = &the_cpu_spec; struct cpu_spec old; t = PTRRELOC(t); old = *t; /* * Copy everything, then do fixups. Use memcpy() instead of *t = *s * so that GCC replaces it by __memcpy() when KASAN is active */ memcpy(t, s, sizeof(*t)); /* * If we are overriding a previous value derived from the real * PVR with a new value obtained using a logical PVR value, * don't modify the performance monitor fields. */ if (old.num_pmcs && !s->num_pmcs) { t->num_pmcs = old.num_pmcs; t->pmc_type = old.pmc_type; /* * Let's ensure that the * fix for the PMAO bug is enabled on compatibility mode. */ t->cpu_features |= old.cpu_features & CPU_FTR_PMAO_BUG; } *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec; /* * Set the base platform string once; assumes * we're called with real pvr first. */ if (*PTRRELOC(&powerpc_base_platform) == NULL) *PTRRELOC(&powerpc_base_platform) = t->platform; #if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE) /* ppc64 and booke expect identify_cpu to also call setup_cpu for * that processor. I will consolidate that at a later time, for now, * just use #ifdef. We also don't need to PTRRELOC the function * pointer on ppc64 and booke as we are running at 0 in real mode * on ppc64 and reloc_offset is always 0 on booke. */ if (t->cpu_setup) { t->cpu_setup(offset, t); } #endif /* CONFIG_PPC64 || CONFIG_BOOKE */ return t; } struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) { struct cpu_spec *s = cpu_specs; int i; BUILD_BUG_ON(!ARRAY_SIZE(cpu_specs)); s = PTRRELOC(s); for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) { if ((pvr & s->pvr_mask) == s->pvr_value) return setup_cpu_spec(offset, s); } BUG(); return NULL; } /* * Used by cpufeatures to get the name for CPUs with a PVR table. * If they don't hae a PVR table, cpufeatures gets the name from * cpu device-tree node. */ void __init identify_cpu_name(unsigned int pvr) { struct cpu_spec *s = cpu_specs; struct cpu_spec *t = &the_cpu_spec; int i; s = PTRRELOC(s); t = PTRRELOC(t); for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) { if ((pvr & s->pvr_mask) == s->pvr_value) { t->cpu_name = s->cpu_name; return; } } } #ifdef CONFIG_JUMP_LABEL_FEATURE_CHECKS struct static_key_true cpu_feature_keys[NUM_CPU_FTR_KEYS] = { [0 ... NUM_CPU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT }; EXPORT_SYMBOL_GPL(cpu_feature_keys); void __init cpu_feature_keys_init(void) { int i; for (i = 0; i < NUM_CPU_FTR_KEYS; i++) { unsigned long f = 1ul << i; if (!(cur_cpu_spec->cpu_features & f)) static_branch_disable(&cpu_feature_keys[i]); } } struct static_key_true mmu_feature_keys[NUM_MMU_FTR_KEYS] = { [0 ... NUM_MMU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT }; EXPORT_SYMBOL(mmu_feature_keys); void __init mmu_feature_keys_init(void) { int i; for (i = 0; i < NUM_MMU_FTR_KEYS; i++) { unsigned long f = 1ul << i; if (!(cur_cpu_spec->mmu_features & f)) static_branch_disable(&mmu_feature_keys[i]); } } #endif |