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