arm: Use device_set_private for cpuN. For cpu at fdt, nix the fdt softc -- this was leaked and never used for anything. The device's private storage is the cpu_info.diff -r1.68 -r1.69 src/sys/arch/aarch64/aarch64/cpu.c
(riastradh)
--- src/sys/arch/aarch64/aarch64/cpu.c 2021/11/12 06:44:46 1.68
+++ src/sys/arch/aarch64/aarch64/cpu.c 2022/03/03 06:26:05 1.69
@@ -1,741 +1,741 @@ | @@ -1,741 +1,741 @@ | |||
1 | /* $NetBSD: cpu.c,v 1.68 2021/11/12 06:44:46 skrll Exp $ */ | 1 | /* $NetBSD: cpu.c,v 1.69 2022/03/03 06:26:05 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2017 Ryo Shimizu <ryo@nerv.org> | 4 | * Copyright (c) 2017 Ryo Shimizu <ryo@nerv.org> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
24 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | 24 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
25 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 25 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | 26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | __KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.68 2021/11/12 06:44:46 skrll Exp $"); | 30 | __KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.69 2022/03/03 06:26:05 riastradh Exp $"); | |
31 | 31 | |||
32 | #include "locators.h" | 32 | #include "locators.h" | |
33 | #include "opt_arm_debug.h" | 33 | #include "opt_arm_debug.h" | |
34 | #include "opt_ddb.h" | 34 | #include "opt_ddb.h" | |
35 | #include "opt_fdt.h" | 35 | #include "opt_fdt.h" | |
36 | #include "opt_multiprocessor.h" | 36 | #include "opt_multiprocessor.h" | |
37 | 37 | |||
38 | #include <sys/param.h> | 38 | #include <sys/param.h> | |
39 | #include <sys/atomic.h> | 39 | #include <sys/atomic.h> | |
40 | #include <sys/cpu.h> | 40 | #include <sys/cpu.h> | |
41 | #include <sys/device.h> | 41 | #include <sys/device.h> | |
42 | #include <sys/kmem.h> | 42 | #include <sys/kmem.h> | |
43 | #include <sys/reboot.h> | 43 | #include <sys/reboot.h> | |
44 | #include <sys/rndsource.h> | 44 | #include <sys/rndsource.h> | |
45 | #include <sys/sysctl.h> | 45 | #include <sys/sysctl.h> | |
46 | #include <sys/systm.h> | 46 | #include <sys/systm.h> | |
47 | 47 | |||
48 | #include <crypto/aes/aes_impl.h> | 48 | #include <crypto/aes/aes_impl.h> | |
49 | #include <crypto/aes/arch/arm/aes_armv8.h> | 49 | #include <crypto/aes/arch/arm/aes_armv8.h> | |
50 | #include <crypto/aes/arch/arm/aes_neon.h> | 50 | #include <crypto/aes/arch/arm/aes_neon.h> | |
51 | #include <crypto/chacha/chacha_impl.h> | 51 | #include <crypto/chacha/chacha_impl.h> | |
52 | #include <crypto/chacha/arch/arm/chacha_neon.h> | 52 | #include <crypto/chacha/arch/arm/chacha_neon.h> | |
53 | 53 | |||
54 | #include <aarch64/armreg.h> | 54 | #include <aarch64/armreg.h> | |
55 | #include <aarch64/cpu.h> | 55 | #include <aarch64/cpu.h> | |
56 | #include <aarch64/cpu_counter.h> | 56 | #include <aarch64/cpu_counter.h> | |
57 | #ifdef DDB | 57 | #ifdef DDB | |
58 | #include <aarch64/db_machdep.h> | 58 | #include <aarch64/db_machdep.h> | |
59 | #endif | 59 | #endif | |
60 | #include <aarch64/machdep.h> | 60 | #include <aarch64/machdep.h> | |
61 | 61 | |||
62 | #include <arm/cpufunc.h> | 62 | #include <arm/cpufunc.h> | |
63 | #include <arm/cpu_topology.h> | 63 | #include <arm/cpu_topology.h> | |
64 | #ifdef FDT | 64 | #ifdef FDT | |
65 | #include <arm/fdt/arm_fdtvar.h> | 65 | #include <arm/fdt/arm_fdtvar.h> | |
66 | #endif | 66 | #endif | |
67 | 67 | |||
68 | #ifdef VERBOSE_INIT_ARM | 68 | #ifdef VERBOSE_INIT_ARM | |
69 | #define VPRINTF(...) printf(__VA_ARGS__) | 69 | #define VPRINTF(...) printf(__VA_ARGS__) | |
70 | #else | 70 | #else | |
71 | #define VPRINTF(...) __nothing | 71 | #define VPRINTF(...) __nothing | |
72 | #endif | 72 | #endif | |
73 | 73 | |||
74 | void cpu_attach(device_t, cpuid_t); | 74 | void cpu_attach(device_t, cpuid_t); | |
75 | void cpu_setup_id(struct cpu_info *); | 75 | void cpu_setup_id(struct cpu_info *); | |
76 | 76 | |||
77 | static void identify_aarch64_model(uint32_t, char *, size_t); | 77 | static void identify_aarch64_model(uint32_t, char *, size_t); | |
78 | static void cpu_identify(device_t self, struct cpu_info *); | 78 | static void cpu_identify(device_t self, struct cpu_info *); | |
79 | static void cpu_identify1(device_t self, struct cpu_info *); | 79 | static void cpu_identify1(device_t self, struct cpu_info *); | |
80 | static void cpu_identify2(device_t self, struct cpu_info *); | 80 | static void cpu_identify2(device_t self, struct cpu_info *); | |
81 | static void cpu_init_counter(struct cpu_info *); | 81 | static void cpu_init_counter(struct cpu_info *); | |
82 | static void cpu_setup_sysctl(device_t, struct cpu_info *); | 82 | static void cpu_setup_sysctl(device_t, struct cpu_info *); | |
83 | static void cpu_setup_rng(device_t, struct cpu_info *); | 83 | static void cpu_setup_rng(device_t, struct cpu_info *); | |
84 | static void cpu_setup_aes(device_t, struct cpu_info *); | 84 | static void cpu_setup_aes(device_t, struct cpu_info *); | |
85 | static void cpu_setup_chacha(device_t, struct cpu_info *); | 85 | static void cpu_setup_chacha(device_t, struct cpu_info *); | |
86 | 86 | |||
87 | #ifdef MULTIPROCESSOR | 87 | #ifdef MULTIPROCESSOR | |
88 | #define NCPUINFO MAXCPUS | 88 | #define NCPUINFO MAXCPUS | |
89 | #else | 89 | #else | |
90 | #define NCPUINFO 1 | 90 | #define NCPUINFO 1 | |
91 | #endif /* MULTIPROCESSOR */ | 91 | #endif /* MULTIPROCESSOR */ | |
92 | 92 | |||
93 | /* | 93 | /* | |
94 | * Our exported cpu_info structs; these will be first used by the | 94 | * Our exported cpu_info structs; these will be first used by the | |
95 | * secondary cpus as part of cpu_mpstart and the hatching process. | 95 | * secondary cpus as part of cpu_mpstart and the hatching process. | |
96 | */ | 96 | */ | |
97 | struct cpu_info cpu_info_store[NCPUINFO] = { | 97 | struct cpu_info cpu_info_store[NCPUINFO] = { | |
98 | [0] = { | 98 | [0] = { | |
99 | .ci_cpl = IPL_HIGH, | 99 | .ci_cpl = IPL_HIGH, | |
100 | .ci_curlwp = &lwp0 | 100 | .ci_curlwp = &lwp0 | |
101 | } | 101 | } | |
102 | }; | 102 | }; | |
103 | 103 | |||
104 | void | 104 | void | |
105 | cpu_attach(device_t dv, cpuid_t id) | 105 | cpu_attach(device_t dv, cpuid_t id) | |
106 | { | 106 | { | |
107 | struct cpu_info *ci; | 107 | struct cpu_info *ci; | |
108 | const int unit = device_unit(dv); | 108 | const int unit = device_unit(dv); | |
109 | 109 | |||
110 | if (unit == 0) { | 110 | if (unit == 0) { | |
111 | ci = curcpu(); | 111 | ci = curcpu(); | |
112 | ci->ci_cpuid = id; | 112 | ci->ci_cpuid = id; | |
113 | } else { | 113 | } else { | |
114 | #ifdef MULTIPROCESSOR | 114 | #ifdef MULTIPROCESSOR | |
115 | if ((boothowto & RB_MD1) != 0) { | 115 | if ((boothowto & RB_MD1) != 0) { | |
116 | aprint_naive("\n"); | 116 | aprint_naive("\n"); | |
117 | aprint_normal(": multiprocessor boot disabled\n"); | 117 | aprint_normal(": multiprocessor boot disabled\n"); | |
118 | return; | 118 | return; | |
119 | } | 119 | } | |
120 | 120 | |||
121 | KASSERT(unit < MAXCPUS); | 121 | KASSERT(unit < MAXCPUS); | |
122 | ci = &cpu_info_store[unit]; | 122 | ci = &cpu_info_store[unit]; | |
123 | 123 | |||
124 | ci->ci_cpl = IPL_HIGH; | 124 | ci->ci_cpl = IPL_HIGH; | |
125 | ci->ci_cpuid = id; | 125 | ci->ci_cpuid = id; | |
126 | /* ci_id is stored by own cpus when hatching */ | 126 | /* ci_id is stored by own cpus when hatching */ | |
127 | 127 | |||
128 | cpu_info[ncpu] = ci; | 128 | cpu_info[ncpu] = ci; | |
129 | if (cpu_hatched_p(unit) == 0) { | 129 | if (cpu_hatched_p(unit) == 0) { | |
130 | ci->ci_dev = dv; | 130 | ci->ci_dev = dv; | |
131 | dv->dv_private = ci; | 131 | device_set_private(dv, ci); | |
132 | ci->ci_index = -1; | 132 | ci->ci_index = -1; | |
133 | 133 | |||
134 | aprint_naive(": disabled\n"); | 134 | aprint_naive(": disabled\n"); | |
135 | aprint_normal(": disabled (unresponsive)\n"); | 135 | aprint_normal(": disabled (unresponsive)\n"); | |
136 | return; | 136 | return; | |
137 | } | 137 | } | |
138 | #else /* MULTIPROCESSOR */ | 138 | #else /* MULTIPROCESSOR */ | |
139 | aprint_naive(": disabled\n"); | 139 | aprint_naive(": disabled\n"); | |
140 | aprint_normal(": disabled (uniprocessor kernel)\n"); | 140 | aprint_normal(": disabled (uniprocessor kernel)\n"); | |
141 | return; | 141 | return; | |
142 | #endif /* MULTIPROCESSOR */ | 142 | #endif /* MULTIPROCESSOR */ | |
143 | } | 143 | } | |
144 | 144 | |||
145 | ci->ci_dev = dv; | 145 | ci->ci_dev = dv; | |
146 | dv->dv_private = ci; | 146 | device_set_private(dv, ci); | |
147 | 147 | |||
148 | ci->ci_kfpu_spl = -1; | 148 | ci->ci_kfpu_spl = -1; | |
149 | 149 | |||
150 | arm_cpu_do_topology(ci); // XXXNH move this after mi_cpu_attach | 150 | arm_cpu_do_topology(ci); // XXXNH move this after mi_cpu_attach | |
151 | cpu_identify(dv, ci); | 151 | cpu_identify(dv, ci); | |
152 | 152 | |||
153 | cpu_setup_sysctl(dv, ci); | 153 | cpu_setup_sysctl(dv, ci); | |
154 | 154 | |||
155 | #ifdef MULTIPROCESSOR | 155 | #ifdef MULTIPROCESSOR | |
156 | if (unit != 0) { | 156 | if (unit != 0) { | |
157 | mi_cpu_attach(ci); | 157 | mi_cpu_attach(ci); | |
158 | pmap_tlb_info_attach(&pmap_tlb0_info, ci); | 158 | pmap_tlb_info_attach(&pmap_tlb0_info, ci); | |
159 | aarch64_parsecacheinfo(ci); | 159 | aarch64_parsecacheinfo(ci); | |
160 | } | 160 | } | |
161 | #endif /* MULTIPROCESSOR */ | 161 | #endif /* MULTIPROCESSOR */ | |
162 | 162 | |||
163 | fpu_attach(ci); | 163 | fpu_attach(ci); | |
164 | 164 | |||
165 | cpu_identify1(dv, ci); | 165 | cpu_identify1(dv, ci); | |
166 | aarch64_printcacheinfo(dv, ci); | 166 | aarch64_printcacheinfo(dv, ci); | |
167 | cpu_identify2(dv, ci); | 167 | cpu_identify2(dv, ci); | |
168 | 168 | |||
169 | if (unit != 0) { | 169 | if (unit != 0) { | |
170 | return; | 170 | return; | |
171 | } | 171 | } | |
172 | 172 | |||
173 | db_machdep_init(ci); | 173 | db_machdep_init(ci); | |
174 | 174 | |||
175 | cpu_init_counter(ci); | 175 | cpu_init_counter(ci); | |
176 | 176 | |||
177 | /* These currently only check the BP. */ | 177 | /* These currently only check the BP. */ | |
178 | cpu_setup_rng(dv, ci); | 178 | cpu_setup_rng(dv, ci); | |
179 | cpu_setup_aes(dv, ci); | 179 | cpu_setup_aes(dv, ci); | |
180 | cpu_setup_chacha(dv, ci); | 180 | cpu_setup_chacha(dv, ci); | |
181 | } | 181 | } | |
182 | 182 | |||
183 | struct cpuidtab { | 183 | struct cpuidtab { | |
184 | uint32_t cpu_partnum; | 184 | uint32_t cpu_partnum; | |
185 | const char *cpu_name; | 185 | const char *cpu_name; | |
186 | const char *cpu_vendor; | 186 | const char *cpu_vendor; | |
187 | const char *cpu_architecture; | 187 | const char *cpu_architecture; | |
188 | }; | 188 | }; | |
189 | 189 | |||
190 | #define CPU_PARTMASK (CPU_ID_IMPLEMENTOR_MASK | CPU_ID_PARTNO_MASK) | 190 | #define CPU_PARTMASK (CPU_ID_IMPLEMENTOR_MASK | CPU_ID_PARTNO_MASK) | |
191 | 191 | |||
192 | const struct cpuidtab cpuids[] = { | 192 | const struct cpuidtab cpuids[] = { | |
193 | { CPU_ID_CORTEXA35R0 & CPU_PARTMASK, "Cortex-A35", "Arm", "v8-A" }, | 193 | { CPU_ID_CORTEXA35R0 & CPU_PARTMASK, "Cortex-A35", "Arm", "v8-A" }, | |
194 | { CPU_ID_CORTEXA53R0 & CPU_PARTMASK, "Cortex-A53", "Arm", "v8-A" }, | 194 | { CPU_ID_CORTEXA53R0 & CPU_PARTMASK, "Cortex-A53", "Arm", "v8-A" }, | |
195 | { CPU_ID_CORTEXA57R0 & CPU_PARTMASK, "Cortex-A57", "Arm", "v8-A" }, | 195 | { CPU_ID_CORTEXA57R0 & CPU_PARTMASK, "Cortex-A57", "Arm", "v8-A" }, | |
196 | { CPU_ID_CORTEXA55R1 & CPU_PARTMASK, "Cortex-A55", "Arm", "v8.2-A+" }, | 196 | { CPU_ID_CORTEXA55R1 & CPU_PARTMASK, "Cortex-A55", "Arm", "v8.2-A+" }, | |
197 | { CPU_ID_CORTEXA65R0 & CPU_PARTMASK, "Cortex-A65", "Arm", "v8.2-A+" }, | 197 | { CPU_ID_CORTEXA65R0 & CPU_PARTMASK, "Cortex-A65", "Arm", "v8.2-A+" }, | |
198 | { CPU_ID_CORTEXA72R0 & CPU_PARTMASK, "Cortex-A72", "Arm", "v8-A" }, | 198 | { CPU_ID_CORTEXA72R0 & CPU_PARTMASK, "Cortex-A72", "Arm", "v8-A" }, | |
199 | { CPU_ID_CORTEXA73R0 & CPU_PARTMASK, "Cortex-A73", "Arm", "v8-A" }, | 199 | { CPU_ID_CORTEXA73R0 & CPU_PARTMASK, "Cortex-A73", "Arm", "v8-A" }, | |
200 | { CPU_ID_CORTEXA75R2 & CPU_PARTMASK, "Cortex-A75", "Arm", "v8.2-A+" }, | 200 | { CPU_ID_CORTEXA75R2 & CPU_PARTMASK, "Cortex-A75", "Arm", "v8.2-A+" }, | |
201 | { CPU_ID_CORTEXA76R3 & CPU_PARTMASK, "Cortex-A76", "Arm", "v8.2-A+" }, | 201 | { CPU_ID_CORTEXA76R3 & CPU_PARTMASK, "Cortex-A76", "Arm", "v8.2-A+" }, | |
202 | { CPU_ID_CORTEXA76AER1 & CPU_PARTMASK, "Cortex-A76AE", "Arm", "v8.2-A+" }, | 202 | { CPU_ID_CORTEXA76AER1 & CPU_PARTMASK, "Cortex-A76AE", "Arm", "v8.2-A+" }, | |
203 | { CPU_ID_CORTEXA77R0 & CPU_PARTMASK, "Cortex-A77", "Arm", "v8.2-A+" }, | 203 | { CPU_ID_CORTEXA77R0 & CPU_PARTMASK, "Cortex-A77", "Arm", "v8.2-A+" }, | |
204 | { CPU_ID_NVIDIADENVER2 & CPU_PARTMASK, "Denver2", "NVIDIA", "v8-A" }, | 204 | { CPU_ID_NVIDIADENVER2 & CPU_PARTMASK, "Denver2", "NVIDIA", "v8-A" }, | |
205 | { CPU_ID_EMAG8180 & CPU_PARTMASK, "eMAG", "Ampere", "v8-A" }, | 205 | { CPU_ID_EMAG8180 & CPU_PARTMASK, "eMAG", "Ampere", "v8-A" }, | |
206 | { CPU_ID_NEOVERSEE1R1 & CPU_PARTMASK, "Neoverse E1", "Arm", "v8.2-A+" }, | 206 | { CPU_ID_NEOVERSEE1R1 & CPU_PARTMASK, "Neoverse E1", "Arm", "v8.2-A+" }, | |
207 | { CPU_ID_NEOVERSEN1R3 & CPU_PARTMASK, "Neoverse N1", "Arm", "v8.2-A+" }, | 207 | { CPU_ID_NEOVERSEN1R3 & CPU_PARTMASK, "Neoverse N1", "Arm", "v8.2-A+" }, | |
208 | { CPU_ID_THUNDERXRX, "ThunderX", "Cavium", "v8-A" }, | 208 | { CPU_ID_THUNDERXRX, "ThunderX", "Cavium", "v8-A" }, | |
209 | { CPU_ID_THUNDERX81XXRX, "ThunderX CN81XX", "Cavium", "v8-A" }, | 209 | { CPU_ID_THUNDERX81XXRX, "ThunderX CN81XX", "Cavium", "v8-A" }, | |
210 | { CPU_ID_THUNDERX83XXRX, "ThunderX CN83XX", "Cavium", "v8-A" }, | 210 | { CPU_ID_THUNDERX83XXRX, "ThunderX CN83XX", "Cavium", "v8-A" }, | |
211 | { CPU_ID_THUNDERX2RX, "ThunderX2", "Marvell", "v8.1-A" }, | 211 | { CPU_ID_THUNDERX2RX, "ThunderX2", "Marvell", "v8.1-A" }, | |
212 | { CPU_ID_APPLE_M1_ICESTORM & CPU_PARTMASK, "M1 Icestorm", "Apple", "Apple Silicon" }, | 212 | { CPU_ID_APPLE_M1_ICESTORM & CPU_PARTMASK, "M1 Icestorm", "Apple", "Apple Silicon" }, | |
213 | { CPU_ID_APPLE_M1_FIRESTORM & CPU_PARTMASK, "M1 Firestorm", "Apple", "Apple Silicon" }, | 213 | { CPU_ID_APPLE_M1_FIRESTORM & CPU_PARTMASK, "M1 Firestorm", "Apple", "Apple Silicon" }, | |
214 | }; | 214 | }; | |
215 | 215 | |||
216 | static void | 216 | static void | |
217 | identify_aarch64_model(uint32_t cpuid, char *buf, size_t len) | 217 | identify_aarch64_model(uint32_t cpuid, char *buf, size_t len) | |
218 | { | 218 | { | |
219 | int i; | 219 | int i; | |
220 | uint32_t cpupart, variant, revision; | 220 | uint32_t cpupart, variant, revision; | |
221 | 221 | |||
222 | cpupart = cpuid & CPU_PARTMASK; | 222 | cpupart = cpuid & CPU_PARTMASK; | |
223 | variant = __SHIFTOUT(cpuid, CPU_ID_VARIANT_MASK); | 223 | variant = __SHIFTOUT(cpuid, CPU_ID_VARIANT_MASK); | |
224 | revision = __SHIFTOUT(cpuid, CPU_ID_REVISION_MASK); | 224 | revision = __SHIFTOUT(cpuid, CPU_ID_REVISION_MASK); | |
225 | 225 | |||
226 | for (i = 0; i < __arraycount(cpuids); i++) { | 226 | for (i = 0; i < __arraycount(cpuids); i++) { | |
227 | if (cpupart == cpuids[i].cpu_partnum) { | 227 | if (cpupart == cpuids[i].cpu_partnum) { | |
228 | snprintf(buf, len, "%s %s r%dp%d (%s)", | 228 | snprintf(buf, len, "%s %s r%dp%d (%s)", | |
229 | cpuids[i].cpu_vendor, cpuids[i].cpu_name, | 229 | cpuids[i].cpu_vendor, cpuids[i].cpu_name, | |
230 | variant, revision, | 230 | variant, revision, | |
231 | cpuids[i].cpu_architecture); | 231 | cpuids[i].cpu_architecture); | |
232 | return; | 232 | return; | |
233 | } | 233 | } | |
234 | } | 234 | } | |
235 | 235 | |||
236 | snprintf(buf, len, "unknown CPU (ID = 0x%08x)", cpuid); | 236 | snprintf(buf, len, "unknown CPU (ID = 0x%08x)", cpuid); | |
237 | } | 237 | } | |
238 | 238 | |||
239 | static void | 239 | static void | |
240 | cpu_identify(device_t self, struct cpu_info *ci) | 240 | cpu_identify(device_t self, struct cpu_info *ci) | |
241 | { | 241 | { | |
242 | char model[128]; | 242 | char model[128]; | |
243 | const char *m; | 243 | const char *m; | |
244 | 244 | |||
245 | identify_aarch64_model(ci->ci_id.ac_midr, model, sizeof(model)); | 245 | identify_aarch64_model(ci->ci_id.ac_midr, model, sizeof(model)); | |
246 | 246 | |||
247 | aprint_naive("\n"); | 247 | aprint_naive("\n"); | |
248 | aprint_normal(": %s, id 0x%lx\n", model, ci->ci_cpuid); | 248 | aprint_normal(": %s, id 0x%lx\n", model, ci->ci_cpuid); | |
249 | aprint_normal_dev(ci->ci_dev, "package %u, core %u, smt %u\n", | 249 | aprint_normal_dev(ci->ci_dev, "package %u, core %u, smt %u\n", | |
250 | ci->ci_package_id, ci->ci_core_id, ci->ci_smt_id); | 250 | ci->ci_package_id, ci->ci_core_id, ci->ci_smt_id); | |
251 | 251 | |||
252 | if (ci->ci_index == 0) { | 252 | if (ci->ci_index == 0) { | |
253 | m = cpu_getmodel(); | 253 | m = cpu_getmodel(); | |
254 | if (m == NULL || *m == 0) | 254 | if (m == NULL || *m == 0) | |
255 | cpu_setmodel("%s", model); | 255 | cpu_setmodel("%s", model); | |
256 | 256 | |||
257 | if (CPU_ID_ERRATA_CAVIUM_THUNDERX_1_1_P(ci->ci_id.ac_midr)) | 257 | if (CPU_ID_ERRATA_CAVIUM_THUNDERX_1_1_P(ci->ci_id.ac_midr)) | |
258 | aprint_normal("WARNING: ThunderX Pass 1.1 detected.\n" | 258 | aprint_normal("WARNING: ThunderX Pass 1.1 detected.\n" | |
259 | "This has known hardware bugs that may cause the " | 259 | "This has known hardware bugs that may cause the " | |
260 | "incorrect operation of atomic operations.\n"); | 260 | "incorrect operation of atomic operations.\n"); | |
261 | } | 261 | } | |
262 | } | 262 | } | |
263 | 263 | |||
264 | static void | 264 | static void | |
265 | cpu_identify1(device_t self, struct cpu_info *ci) | 265 | cpu_identify1(device_t self, struct cpu_info *ci) | |
266 | { | 266 | { | |
267 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | 267 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | |
268 | uint64_t sctlr = ci->ci_sctlr_el1; | 268 | uint64_t sctlr = ci->ci_sctlr_el1; | |
269 | 269 | |||
270 | if (sctlr & SCTLR_I) | 270 | if (sctlr & SCTLR_I) | |
271 | aprint_verbose_dev(self, "IC enabled"); | 271 | aprint_verbose_dev(self, "IC enabled"); | |
272 | else | 272 | else | |
273 | aprint_verbose_dev(self, "IC disabled"); | 273 | aprint_verbose_dev(self, "IC disabled"); | |
274 | 274 | |||
275 | if (sctlr & SCTLR_C) | 275 | if (sctlr & SCTLR_C) | |
276 | aprint_verbose(", DC enabled"); | 276 | aprint_verbose(", DC enabled"); | |
277 | else | 277 | else | |
278 | aprint_verbose(", DC disabled"); | 278 | aprint_verbose(", DC disabled"); | |
279 | 279 | |||
280 | if (sctlr & SCTLR_A) | 280 | if (sctlr & SCTLR_A) | |
281 | aprint_verbose(", Alignment check enabled\n"); | 281 | aprint_verbose(", Alignment check enabled\n"); | |
282 | else { | 282 | else { | |
283 | switch (sctlr & (SCTLR_SA | SCTLR_SA0)) { | 283 | switch (sctlr & (SCTLR_SA | SCTLR_SA0)) { | |
284 | case SCTLR_SA | SCTLR_SA0: | 284 | case SCTLR_SA | SCTLR_SA0: | |
285 | aprint_verbose( | 285 | aprint_verbose( | |
286 | ", EL0/EL1 stack Alignment check enabled\n"); | 286 | ", EL0/EL1 stack Alignment check enabled\n"); | |
287 | break; | 287 | break; | |
288 | case SCTLR_SA: | 288 | case SCTLR_SA: | |
289 | aprint_verbose(", EL1 stack Alignment check enabled\n"); | 289 | aprint_verbose(", EL1 stack Alignment check enabled\n"); | |
290 | break; | 290 | break; | |
291 | case SCTLR_SA0: | 291 | case SCTLR_SA0: | |
292 | aprint_verbose(", EL0 stack Alignment check enabled\n"); | 292 | aprint_verbose(", EL0 stack Alignment check enabled\n"); | |
293 | break; | 293 | break; | |
294 | case 0: | 294 | case 0: | |
295 | aprint_verbose(", Alignment check disabled\n"); | 295 | aprint_verbose(", Alignment check disabled\n"); | |
296 | break; | 296 | break; | |
297 | } | 297 | } | |
298 | } | 298 | } | |
299 | 299 | |||
300 | /* | 300 | /* | |
301 | * CTR - Cache Type Register | 301 | * CTR - Cache Type Register | |
302 | */ | 302 | */ | |
303 | const uint64_t ctr = id->ac_ctr; | 303 | const uint64_t ctr = id->ac_ctr; | |
304 | const uint64_t clidr = id->ac_clidr; | 304 | const uint64_t clidr = id->ac_clidr; | |
305 | aprint_verbose_dev(self, "Cache Writeback Granule %" PRIu64 "B," | 305 | aprint_verbose_dev(self, "Cache Writeback Granule %" PRIu64 "B," | |
306 | " Exclusives Reservation Granule %" PRIu64 "B\n", | 306 | " Exclusives Reservation Granule %" PRIu64 "B\n", | |
307 | __SHIFTOUT(ctr, CTR_EL0_CWG_LINE) * 4, | 307 | __SHIFTOUT(ctr, CTR_EL0_CWG_LINE) * 4, | |
308 | __SHIFTOUT(ctr, CTR_EL0_ERG_LINE) * 4); | 308 | __SHIFTOUT(ctr, CTR_EL0_ERG_LINE) * 4); | |
309 | 309 | |||
310 | aprint_verbose_dev(self, "Dcache line %ld, Icache line %ld" | 310 | aprint_verbose_dev(self, "Dcache line %ld, Icache line %ld" | |
311 | ", DIC=%lu, IDC=%lu, LoUU=%lu, LoC=%lu, LoUIS=%lu\n", | 311 | ", DIC=%lu, IDC=%lu, LoUU=%lu, LoC=%lu, LoUIS=%lu\n", | |
312 | sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_DMIN_LINE), | 312 | sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_DMIN_LINE), | |
313 | sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_IMIN_LINE), | 313 | sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_IMIN_LINE), | |
314 | __SHIFTOUT(ctr, CTR_EL0_DIC), | 314 | __SHIFTOUT(ctr, CTR_EL0_DIC), | |
315 | __SHIFTOUT(ctr, CTR_EL0_IDC), | 315 | __SHIFTOUT(ctr, CTR_EL0_IDC), | |
316 | __SHIFTOUT(clidr, CLIDR_LOUU), | 316 | __SHIFTOUT(clidr, CLIDR_LOUU), | |
317 | __SHIFTOUT(clidr, CLIDR_LOC), | 317 | __SHIFTOUT(clidr, CLIDR_LOC), | |
318 | __SHIFTOUT(clidr, CLIDR_LOUIS)); | 318 | __SHIFTOUT(clidr, CLIDR_LOUIS)); | |
319 | } | 319 | } | |
320 | 320 | |||
321 | 321 | |||
322 | /* | 322 | /* | |
323 | * identify vfp, etc. | 323 | * identify vfp, etc. | |
324 | */ | 324 | */ | |
325 | static void | 325 | static void | |
326 | cpu_identify2(device_t self, struct cpu_info *ci) | 326 | cpu_identify2(device_t self, struct cpu_info *ci) | |
327 | { | 327 | { | |
328 | struct aarch64_sysctl_cpu_id * const id = &ci->ci_id; | 328 | struct aarch64_sysctl_cpu_id * const id = &ci->ci_id; | |
329 | 329 | |||
330 | aprint_debug_dev(self, "midr=0x%" PRIx32 " mpidr=0x%" PRIx32 "\n", | 330 | aprint_debug_dev(self, "midr=0x%" PRIx32 " mpidr=0x%" PRIx32 "\n", | |
331 | (uint32_t)id->ac_midr, (uint32_t)id->ac_mpidr); | 331 | (uint32_t)id->ac_midr, (uint32_t)id->ac_mpidr); | |
332 | aprint_verbose_dev(self, "revID=0x%" PRIx64, id->ac_revidr); | 332 | aprint_verbose_dev(self, "revID=0x%" PRIx64, id->ac_revidr); | |
333 | 333 | |||
334 | /* ID_AA64DFR0_EL1 */ | 334 | /* ID_AA64DFR0_EL1 */ | |
335 | switch (__SHIFTOUT(id->ac_aa64dfr0, ID_AA64DFR0_EL1_PMUVER)) { | 335 | switch (__SHIFTOUT(id->ac_aa64dfr0, ID_AA64DFR0_EL1_PMUVER)) { | |
336 | case ID_AA64DFR0_EL1_PMUVER_V3: | 336 | case ID_AA64DFR0_EL1_PMUVER_V3: | |
337 | aprint_verbose(", PMCv3"); | 337 | aprint_verbose(", PMCv3"); | |
338 | break; | 338 | break; | |
339 | case ID_AA64DFR0_EL1_PMUVER_NOV3: | 339 | case ID_AA64DFR0_EL1_PMUVER_NOV3: | |
340 | aprint_verbose(", PMC"); | 340 | aprint_verbose(", PMC"); | |
341 | break; | 341 | break; | |
342 | } | 342 | } | |
343 | 343 | |||
344 | /* ID_AA64MMFR0_EL1 */ | 344 | /* ID_AA64MMFR0_EL1 */ | |
345 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN4)) { | 345 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN4)) { | |
346 | case ID_AA64MMFR0_EL1_TGRAN4_4KB: | 346 | case ID_AA64MMFR0_EL1_TGRAN4_4KB: | |
347 | aprint_verbose(", 4k table"); | 347 | aprint_verbose(", 4k table"); | |
348 | break; | 348 | break; | |
349 | } | 349 | } | |
350 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN16)) { | 350 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN16)) { | |
351 | case ID_AA64MMFR0_EL1_TGRAN16_16KB: | 351 | case ID_AA64MMFR0_EL1_TGRAN16_16KB: | |
352 | aprint_verbose(", 16k table"); | 352 | aprint_verbose(", 16k table"); | |
353 | break; | 353 | break; | |
354 | } | 354 | } | |
355 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN64)) { | 355 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN64)) { | |
356 | case ID_AA64MMFR0_EL1_TGRAN64_64KB: | 356 | case ID_AA64MMFR0_EL1_TGRAN64_64KB: | |
357 | aprint_verbose(", 64k table"); | 357 | aprint_verbose(", 64k table"); | |
358 | break; | 358 | break; | |
359 | } | 359 | } | |
360 | 360 | |||
361 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_ASIDBITS)) { | 361 | switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_ASIDBITS)) { | |
362 | case ID_AA64MMFR0_EL1_ASIDBITS_8BIT: | 362 | case ID_AA64MMFR0_EL1_ASIDBITS_8BIT: | |
363 | aprint_verbose(", 8bit ASID"); | 363 | aprint_verbose(", 8bit ASID"); | |
364 | break; | 364 | break; | |
365 | case ID_AA64MMFR0_EL1_ASIDBITS_16BIT: | 365 | case ID_AA64MMFR0_EL1_ASIDBITS_16BIT: | |
366 | aprint_verbose(", 16bit ASID"); | 366 | aprint_verbose(", 16bit ASID"); | |
367 | break; | 367 | break; | |
368 | } | 368 | } | |
369 | aprint_verbose("\n"); | 369 | aprint_verbose("\n"); | |
370 | 370 | |||
371 | aprint_verbose_dev(self, "auxID=0x%" PRIx64, ci->ci_id.ac_aa64isar0); | 371 | aprint_verbose_dev(self, "auxID=0x%" PRIx64, ci->ci_id.ac_aa64isar0); | |
372 | 372 | |||
373 | /* PFR0 */ | 373 | /* PFR0 */ | |
374 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV3)) { | 374 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV3)) { | |
375 | case ID_AA64PFR0_EL1_CSV3_IMPL: | 375 | case ID_AA64PFR0_EL1_CSV3_IMPL: | |
376 | aprint_verbose(", CSV3"); | 376 | aprint_verbose(", CSV3"); | |
377 | break; | 377 | break; | |
378 | } | 378 | } | |
379 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV2)) { | 379 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV2)) { | |
380 | case ID_AA64PFR0_EL1_CSV2_IMPL: | 380 | case ID_AA64PFR0_EL1_CSV2_IMPL: | |
381 | aprint_verbose(", CSV2"); | 381 | aprint_verbose(", CSV2"); | |
382 | break; | 382 | break; | |
383 | } | 383 | } | |
384 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_GIC)) { | 384 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_GIC)) { | |
385 | case ID_AA64PFR0_EL1_GIC_CPUIF_EN: | 385 | case ID_AA64PFR0_EL1_GIC_CPUIF_EN: | |
386 | aprint_verbose(", GICv3"); | 386 | aprint_verbose(", GICv3"); | |
387 | break; | 387 | break; | |
388 | } | 388 | } | |
389 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_FP)) { | 389 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_FP)) { | |
390 | case ID_AA64PFR0_EL1_FP_NONE: | 390 | case ID_AA64PFR0_EL1_FP_NONE: | |
391 | break; | 391 | break; | |
392 | default: | 392 | default: | |
393 | aprint_verbose(", FP"); | 393 | aprint_verbose(", FP"); | |
394 | break; | 394 | break; | |
395 | } | 395 | } | |
396 | 396 | |||
397 | /* ISAR0 */ | 397 | /* ISAR0 */ | |
398 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_CRC32)) { | 398 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_CRC32)) { | |
399 | case ID_AA64ISAR0_EL1_CRC32_CRC32X: | 399 | case ID_AA64ISAR0_EL1_CRC32_CRC32X: | |
400 | aprint_verbose(", CRC32"); | 400 | aprint_verbose(", CRC32"); | |
401 | break; | 401 | break; | |
402 | } | 402 | } | |
403 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA1)) { | 403 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA1)) { | |
404 | case ID_AA64ISAR0_EL1_SHA1_SHA1CPMHSU: | 404 | case ID_AA64ISAR0_EL1_SHA1_SHA1CPMHSU: | |
405 | aprint_verbose(", SHA1"); | 405 | aprint_verbose(", SHA1"); | |
406 | break; | 406 | break; | |
407 | } | 407 | } | |
408 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA2)) { | 408 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA2)) { | |
409 | case ID_AA64ISAR0_EL1_SHA2_SHA256HSU: | 409 | case ID_AA64ISAR0_EL1_SHA2_SHA256HSU: | |
410 | aprint_verbose(", SHA256"); | 410 | aprint_verbose(", SHA256"); | |
411 | break; | 411 | break; | |
412 | } | 412 | } | |
413 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { | 413 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { | |
414 | case ID_AA64ISAR0_EL1_AES_AES: | 414 | case ID_AA64ISAR0_EL1_AES_AES: | |
415 | aprint_verbose(", AES"); | 415 | aprint_verbose(", AES"); | |
416 | break; | 416 | break; | |
417 | case ID_AA64ISAR0_EL1_AES_PMUL: | 417 | case ID_AA64ISAR0_EL1_AES_PMUL: | |
418 | aprint_verbose(", AES+PMULL"); | 418 | aprint_verbose(", AES+PMULL"); | |
419 | break; | 419 | break; | |
420 | } | 420 | } | |
421 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { | 421 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { | |
422 | case ID_AA64ISAR0_EL1_RNDR_RNDRRS: | 422 | case ID_AA64ISAR0_EL1_RNDR_RNDRRS: | |
423 | aprint_verbose(", RNDRRS"); | 423 | aprint_verbose(", RNDRRS"); | |
424 | break; | 424 | break; | |
425 | } | 425 | } | |
426 | 426 | |||
427 | /* PFR0:DIT -- data-independent timing support */ | 427 | /* PFR0:DIT -- data-independent timing support */ | |
428 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_DIT)) { | 428 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_DIT)) { | |
429 | case ID_AA64PFR0_EL1_DIT_IMPL: | 429 | case ID_AA64PFR0_EL1_DIT_IMPL: | |
430 | aprint_verbose(", DIT"); | 430 | aprint_verbose(", DIT"); | |
431 | break; | 431 | break; | |
432 | } | 432 | } | |
433 | 433 | |||
434 | /* PFR0:AdvSIMD */ | 434 | /* PFR0:AdvSIMD */ | |
435 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { | 435 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { | |
436 | case ID_AA64PFR0_EL1_ADV_SIMD_NONE: | 436 | case ID_AA64PFR0_EL1_ADV_SIMD_NONE: | |
437 | break; | 437 | break; | |
438 | default: | 438 | default: | |
439 | aprint_verbose(", NEON"); | 439 | aprint_verbose(", NEON"); | |
440 | break; | 440 | break; | |
441 | } | 441 | } | |
442 | 442 | |||
443 | /* MVFR0/MVFR1 */ | 443 | /* MVFR0/MVFR1 */ | |
444 | switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPROUND)) { | 444 | switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPROUND)) { | |
445 | case MVFR0_FPROUND_ALL: | 445 | case MVFR0_FPROUND_ALL: | |
446 | aprint_verbose(", rounding"); | 446 | aprint_verbose(", rounding"); | |
447 | break; | 447 | break; | |
448 | } | 448 | } | |
449 | switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPTRAP)) { | 449 | switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPTRAP)) { | |
450 | case MVFR0_FPTRAP_TRAP: | 450 | case MVFR0_FPTRAP_TRAP: | |
451 | aprint_verbose(", exceptions"); | 451 | aprint_verbose(", exceptions"); | |
452 | break; | 452 | break; | |
453 | } | 453 | } | |
454 | switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPDNAN)) { | 454 | switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPDNAN)) { | |
455 | case MVFR1_FPDNAN_NAN: | 455 | case MVFR1_FPDNAN_NAN: | |
456 | aprint_verbose(", NaN propagation"); | 456 | aprint_verbose(", NaN propagation"); | |
457 | break; | 457 | break; | |
458 | } | 458 | } | |
459 | switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPFTZ)) { | 459 | switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPFTZ)) { | |
460 | case MVFR1_FPFTZ_DENORMAL: | 460 | case MVFR1_FPFTZ_DENORMAL: | |
461 | aprint_verbose(", denormals"); | 461 | aprint_verbose(", denormals"); | |
462 | break; | 462 | break; | |
463 | } | 463 | } | |
464 | switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_SIMDREG)) { | 464 | switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_SIMDREG)) { | |
465 | case MVFR0_SIMDREG_16x64: | 465 | case MVFR0_SIMDREG_16x64: | |
466 | aprint_verbose(", 16x64bitRegs"); | 466 | aprint_verbose(", 16x64bitRegs"); | |
467 | break; | 467 | break; | |
468 | case MVFR0_SIMDREG_32x64: | 468 | case MVFR0_SIMDREG_32x64: | |
469 | aprint_verbose(", 32x64bitRegs"); | 469 | aprint_verbose(", 32x64bitRegs"); | |
470 | break; | 470 | break; | |
471 | } | 471 | } | |
472 | switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_SIMDFMAC)) { | 472 | switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_SIMDFMAC)) { | |
473 | case MVFR1_SIMDFMAC_FMAC: | 473 | case MVFR1_SIMDFMAC_FMAC: | |
474 | aprint_verbose(", Fused Multiply-Add"); | 474 | aprint_verbose(", Fused Multiply-Add"); | |
475 | break; | 475 | break; | |
476 | } | 476 | } | |
477 | 477 | |||
478 | aprint_verbose("\n"); | 478 | aprint_verbose("\n"); | |
479 | } | 479 | } | |
480 | 480 | |||
481 | /* | 481 | /* | |
482 | * Enable the performance counter, then estimate frequency for | 482 | * Enable the performance counter, then estimate frequency for | |
483 | * the current PE and store the result in cpu_cc_freq. | 483 | * the current PE and store the result in cpu_cc_freq. | |
484 | */ | 484 | */ | |
485 | static void | 485 | static void | |
486 | cpu_init_counter(struct cpu_info *ci) | 486 | cpu_init_counter(struct cpu_info *ci) | |
487 | { | 487 | { | |
488 | const uint64_t dfr0 = reg_id_aa64dfr0_el1_read(); | 488 | const uint64_t dfr0 = reg_id_aa64dfr0_el1_read(); | |
489 | const u_int pmuver = __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_PMUVER); | 489 | const u_int pmuver = __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_PMUVER); | |
490 | if (pmuver == ID_AA64DFR0_EL1_PMUVER_NONE) { | 490 | if (pmuver == ID_AA64DFR0_EL1_PMUVER_NONE) { | |
491 | /* Performance Monitors Extension not implemented. */ | 491 | /* Performance Monitors Extension not implemented. */ | |
492 | return; | 492 | return; | |
493 | } | 493 | } | |
494 | if (pmuver == ID_AA64DFR0_EL1_PMUVER_IMPL) { | 494 | if (pmuver == ID_AA64DFR0_EL1_PMUVER_IMPL) { | |
495 | /* Non-standard Performance Monitors are not supported. */ | 495 | /* Non-standard Performance Monitors are not supported. */ | |
496 | return; | 496 | return; | |
497 | } | 497 | } | |
498 | 498 | |||
499 | reg_pmcr_el0_write(PMCR_E | PMCR_C); | 499 | reg_pmcr_el0_write(PMCR_E | PMCR_C); | |
500 | reg_pmcntenset_el0_write(PMCNTEN_C); | 500 | reg_pmcntenset_el0_write(PMCNTEN_C); | |
501 | 501 | |||
502 | const uint32_t prev = cpu_counter32(); | 502 | const uint32_t prev = cpu_counter32(); | |
503 | delay(100000); | 503 | delay(100000); | |
504 | ci->ci_data.cpu_cc_freq = (cpu_counter32() - prev) * 10; | 504 | ci->ci_data.cpu_cc_freq = (cpu_counter32() - prev) * 10; | |
505 | } | 505 | } | |
506 | 506 | |||
507 | /* | 507 | /* | |
508 | * Fill in this CPUs id data. Must be called on all cpus. | 508 | * Fill in this CPUs id data. Must be called on all cpus. | |
509 | */ | 509 | */ | |
510 | void __noasan | 510 | void __noasan | |
511 | cpu_setup_id(struct cpu_info *ci) | 511 | cpu_setup_id(struct cpu_info *ci) | |
512 | { | 512 | { | |
513 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | 513 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | |
514 | 514 | |||
515 | /* SCTLR - System Control Register */ | 515 | /* SCTLR - System Control Register */ | |
516 | ci->ci_sctlr_el1 = reg_sctlr_el1_read(); | 516 | ci->ci_sctlr_el1 = reg_sctlr_el1_read(); | |
517 | 517 | |||
518 | memset(id, 0, sizeof *id); | 518 | memset(id, 0, sizeof *id); | |
519 | 519 | |||
520 | id->ac_midr = reg_midr_el1_read(); | 520 | id->ac_midr = reg_midr_el1_read(); | |
521 | id->ac_revidr = reg_revidr_el1_read(); | 521 | id->ac_revidr = reg_revidr_el1_read(); | |
522 | id->ac_mpidr = reg_mpidr_el1_read(); | 522 | id->ac_mpidr = reg_mpidr_el1_read(); | |
523 | 523 | |||
524 | id->ac_aa64dfr0 = reg_id_aa64dfr0_el1_read(); | 524 | id->ac_aa64dfr0 = reg_id_aa64dfr0_el1_read(); | |
525 | id->ac_aa64dfr1 = reg_id_aa64dfr1_el1_read(); | 525 | id->ac_aa64dfr1 = reg_id_aa64dfr1_el1_read(); | |
526 | 526 | |||
527 | id->ac_aa64isar0 = reg_id_aa64isar0_el1_read(); | 527 | id->ac_aa64isar0 = reg_id_aa64isar0_el1_read(); | |
528 | id->ac_aa64isar1 = reg_id_aa64isar1_el1_read(); | 528 | id->ac_aa64isar1 = reg_id_aa64isar1_el1_read(); | |
529 | 529 | |||
530 | id->ac_aa64mmfr0 = reg_id_aa64mmfr0_el1_read(); | 530 | id->ac_aa64mmfr0 = reg_id_aa64mmfr0_el1_read(); | |
531 | id->ac_aa64mmfr1 = reg_id_aa64mmfr1_el1_read(); | 531 | id->ac_aa64mmfr1 = reg_id_aa64mmfr1_el1_read(); | |
532 | id->ac_aa64mmfr2 = reg_id_aa64mmfr2_el1_read(); | 532 | id->ac_aa64mmfr2 = reg_id_aa64mmfr2_el1_read(); | |
533 | 533 | |||
534 | id->ac_mvfr0 = reg_mvfr0_el1_read(); | 534 | id->ac_mvfr0 = reg_mvfr0_el1_read(); | |
535 | id->ac_mvfr1 = reg_mvfr1_el1_read(); | 535 | id->ac_mvfr1 = reg_mvfr1_el1_read(); | |
536 | id->ac_mvfr2 = reg_mvfr2_el1_read(); | 536 | id->ac_mvfr2 = reg_mvfr2_el1_read(); | |
537 | 537 | |||
538 | id->ac_clidr = reg_clidr_el1_read(); | 538 | id->ac_clidr = reg_clidr_el1_read(); | |
539 | id->ac_ctr = reg_ctr_el0_read(); | 539 | id->ac_ctr = reg_ctr_el0_read(); | |
540 | 540 | |||
541 | /* Only in ARMv8.2. */ | 541 | /* Only in ARMv8.2. */ | |
542 | id->ac_aa64zfr0 = 0 /* reg_id_aa64zfr0_el1_read() */; | 542 | id->ac_aa64zfr0 = 0 /* reg_id_aa64zfr0_el1_read() */; | |
543 | 543 | |||
544 | id->ac_aa64pfr0 = reg_id_aa64pfr0_el1_read(); | 544 | id->ac_aa64pfr0 = reg_id_aa64pfr0_el1_read(); | |
545 | id->ac_aa64pfr1 = reg_id_aa64pfr1_el1_read(); | 545 | id->ac_aa64pfr1 = reg_id_aa64pfr1_el1_read(); | |
546 | } | 546 | } | |
547 | 547 | |||
548 | /* | 548 | /* | |
549 | * setup the per-cpu sysctl tree. | 549 | * setup the per-cpu sysctl tree. | |
550 | */ | 550 | */ | |
551 | static void | 551 | static void | |
552 | cpu_setup_sysctl(device_t dv, struct cpu_info *ci) | 552 | cpu_setup_sysctl(device_t dv, struct cpu_info *ci) | |
553 | { | 553 | { | |
554 | const struct sysctlnode *cpunode = NULL; | 554 | const struct sysctlnode *cpunode = NULL; | |
555 | 555 | |||
556 | sysctl_createv(NULL, 0, NULL, &cpunode, | 556 | sysctl_createv(NULL, 0, NULL, &cpunode, | |
557 | CTLFLAG_PERMANENT, | 557 | CTLFLAG_PERMANENT, | |
558 | CTLTYPE_NODE, device_xname(dv), NULL, | 558 | CTLTYPE_NODE, device_xname(dv), NULL, | |
559 | NULL, 0, NULL, 0, | 559 | NULL, 0, NULL, 0, | |
560 | CTL_MACHDEP, | 560 | CTL_MACHDEP, | |
561 | CTL_CREATE, CTL_EOL); | 561 | CTL_CREATE, CTL_EOL); | |
562 | 562 | |||
563 | if (cpunode == NULL) | 563 | if (cpunode == NULL) | |
564 | return; | 564 | return; | |
565 | 565 | |||
566 | sysctl_createv(NULL, 0, &cpunode, NULL, | 566 | sysctl_createv(NULL, 0, &cpunode, NULL, | |
567 | CTLFLAG_PERMANENT, | 567 | CTLFLAG_PERMANENT, | |
568 | CTLTYPE_STRUCT, "cpu_id", NULL, | 568 | CTLTYPE_STRUCT, "cpu_id", NULL, | |
569 | NULL, 0, &ci->ci_id, sizeof(ci->ci_id), | 569 | NULL, 0, &ci->ci_id, sizeof(ci->ci_id), | |
570 | CTL_CREATE, CTL_EOL); | 570 | CTL_CREATE, CTL_EOL); | |
571 | } | 571 | } | |
572 | 572 | |||
573 | static struct krndsource rndrrs_source; | 573 | static struct krndsource rndrrs_source; | |
574 | 574 | |||
575 | static void | 575 | static void | |
576 | rndrrs_get(size_t nbytes, void *cookie) | 576 | rndrrs_get(size_t nbytes, void *cookie) | |
577 | { | 577 | { | |
578 | /* Entropy bits per data byte, wild-arse guess. */ | 578 | /* Entropy bits per data byte, wild-arse guess. */ | |
579 | const unsigned bpb = 4; | 579 | const unsigned bpb = 4; | |
580 | size_t nbits = nbytes*NBBY; | 580 | size_t nbits = nbytes*NBBY; | |
581 | uint64_t x; | 581 | uint64_t x; | |
582 | int error; | 582 | int error; | |
583 | 583 | |||
584 | while (nbits) { | 584 | while (nbits) { | |
585 | /* | 585 | /* | |
586 | * x := random 64-bit sample | 586 | * x := random 64-bit sample | |
587 | * error := Z bit, set to 1 if sample is bad | 587 | * error := Z bit, set to 1 if sample is bad | |
588 | * | 588 | * | |
589 | * XXX This should be done by marking the function | 589 | * XXX This should be done by marking the function | |
590 | * __attribute__((target("arch=armv8.5-a+rng"))) and | 590 | * __attribute__((target("arch=armv8.5-a+rng"))) and | |
591 | * using `mrs %0, rndrrs', but: | 591 | * using `mrs %0, rndrrs', but: | |
592 | * | 592 | * | |
593 | * (a) the version of gcc we use doesn't support that, | 593 | * (a) the version of gcc we use doesn't support that, | |
594 | * and | 594 | * and | |
595 | * (b) clang doesn't seem to like `rndrrs' itself. | 595 | * (b) clang doesn't seem to like `rndrrs' itself. | |
596 | * | 596 | * | |
597 | * So we use the numeric encoding for now. | 597 | * So we use the numeric encoding for now. | |
598 | */ | 598 | */ | |
599 | __asm __volatile("" | 599 | __asm __volatile("" | |
600 | "mrs %0, s3_3_c2_c4_1\n" | 600 | "mrs %0, s3_3_c2_c4_1\n" | |
601 | "cset %w1, eq" | 601 | "cset %w1, eq" | |
602 | : "=r"(x), "=r"(error)); | 602 | : "=r"(x), "=r"(error)); | |
603 | if (error) | 603 | if (error) | |
604 | break; | 604 | break; | |
605 | rnd_add_data_sync(&rndrrs_source, &x, sizeof(x), | 605 | rnd_add_data_sync(&rndrrs_source, &x, sizeof(x), | |
606 | bpb*sizeof(x)); | 606 | bpb*sizeof(x)); | |
607 | nbits -= MIN(nbits, bpb*sizeof(x)); | 607 | nbits -= MIN(nbits, bpb*sizeof(x)); | |
608 | } | 608 | } | |
609 | 609 | |||
610 | explicit_memset(&x, 0, sizeof x); | 610 | explicit_memset(&x, 0, sizeof x); | |
611 | } | 611 | } | |
612 | 612 | |||
613 | /* | 613 | /* | |
614 | * setup the RNDRRS entropy source | 614 | * setup the RNDRRS entropy source | |
615 | */ | 615 | */ | |
616 | static void | 616 | static void | |
617 | cpu_setup_rng(device_t dv, struct cpu_info *ci) | 617 | cpu_setup_rng(device_t dv, struct cpu_info *ci) | |
618 | { | 618 | { | |
619 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | 619 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | |
620 | 620 | |||
621 | /* Verify that it is supported. */ | 621 | /* Verify that it is supported. */ | |
622 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { | 622 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { | |
623 | case ID_AA64ISAR0_EL1_RNDR_RNDRRS: | 623 | case ID_AA64ISAR0_EL1_RNDR_RNDRRS: | |
624 | break; | 624 | break; | |
625 | default: | 625 | default: | |
626 | return; | 626 | return; | |
627 | } | 627 | } | |
628 | 628 | |||
629 | /* Attach it. */ | 629 | /* Attach it. */ | |
630 | rndsource_setcb(&rndrrs_source, rndrrs_get, NULL); | 630 | rndsource_setcb(&rndrrs_source, rndrrs_get, NULL); | |
631 | rnd_attach_source(&rndrrs_source, "rndrrs", RND_TYPE_RNG, | 631 | rnd_attach_source(&rndrrs_source, "rndrrs", RND_TYPE_RNG, | |
632 | RND_FLAG_DEFAULT|RND_FLAG_HASCB); | 632 | RND_FLAG_DEFAULT|RND_FLAG_HASCB); | |
633 | } | 633 | } | |
634 | 634 | |||
635 | /* | 635 | /* | |
636 | * setup the AES implementation | 636 | * setup the AES implementation | |
637 | */ | 637 | */ | |
638 | static void | 638 | static void | |
639 | cpu_setup_aes(device_t dv, struct cpu_info *ci) | 639 | cpu_setup_aes(device_t dv, struct cpu_info *ci) | |
640 | { | 640 | { | |
641 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | 641 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | |
642 | 642 | |||
643 | /* Check for ARMv8.0-AES support. */ | 643 | /* Check for ARMv8.0-AES support. */ | |
644 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { | 644 | switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { | |
645 | case ID_AA64ISAR0_EL1_AES_AES: | 645 | case ID_AA64ISAR0_EL1_AES_AES: | |
646 | case ID_AA64ISAR0_EL1_AES_PMUL: | 646 | case ID_AA64ISAR0_EL1_AES_PMUL: | |
647 | aes_md_init(&aes_armv8_impl); | 647 | aes_md_init(&aes_armv8_impl); | |
648 | return; | 648 | return; | |
649 | default: | 649 | default: | |
650 | break; | 650 | break; | |
651 | } | 651 | } | |
652 | 652 | |||
653 | /* Failing that, check for SIMD support. */ | 653 | /* Failing that, check for SIMD support. */ | |
654 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { | 654 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { | |
655 | case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: | 655 | case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: | |
656 | aes_md_init(&aes_neon_impl); | 656 | aes_md_init(&aes_neon_impl); | |
657 | return; | 657 | return; | |
658 | default: | 658 | default: | |
659 | break; | 659 | break; | |
660 | } | 660 | } | |
661 | } | 661 | } | |
662 | 662 | |||
663 | /* | 663 | /* | |
664 | * setup the ChaCha implementation | 664 | * setup the ChaCha implementation | |
665 | */ | 665 | */ | |
666 | static void | 666 | static void | |
667 | cpu_setup_chacha(device_t dv, struct cpu_info *ci) | 667 | cpu_setup_chacha(device_t dv, struct cpu_info *ci) | |
668 | { | 668 | { | |
669 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | 669 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | |
670 | 670 | |||
671 | /* Check for SIMD support. */ | 671 | /* Check for SIMD support. */ | |
672 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { | 672 | switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { | |
673 | case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: | 673 | case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: | |
674 | chacha_md_init(&chacha_neon_impl); | 674 | chacha_md_init(&chacha_neon_impl); | |
675 | return; | 675 | return; | |
676 | default: | 676 | default: | |
677 | break; | 677 | break; | |
678 | } | 678 | } | |
679 | } | 679 | } | |
680 | 680 | |||
681 | #ifdef MULTIPROCESSOR | 681 | #ifdef MULTIPROCESSOR | |
682 | /* | 682 | /* | |
683 | * Initialise a secondary processor. | 683 | * Initialise a secondary processor. | |
684 | * | 684 | * | |
685 | * printf isn't available as kmutex(9) relies on curcpu which isn't setup yet. | 685 | * printf isn't available as kmutex(9) relies on curcpu which isn't setup yet. | |
686 | * | 686 | * | |
687 | */ | 687 | */ | |
688 | void __noasan | 688 | void __noasan | |
689 | cpu_init_secondary_processor(int cpuindex) | 689 | cpu_init_secondary_processor(int cpuindex) | |
690 | { | 690 | { | |
691 | struct cpu_info * ci = &cpu_info_store[cpuindex]; | 691 | struct cpu_info * ci = &cpu_info_store[cpuindex]; | |
692 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | 692 | struct aarch64_sysctl_cpu_id *id = &ci->ci_id; | |
693 | 693 | |||
694 | aarch64_setcpufuncs(ci); | 694 | aarch64_setcpufuncs(ci); | |
695 | 695 | |||
696 | /* Sets ci->ci_{sctlr,midr,mpidr}, etc */ | 696 | /* Sets ci->ci_{sctlr,midr,mpidr}, etc */ | |
697 | cpu_setup_id(ci); | 697 | cpu_setup_id(ci); | |
698 | 698 | |||
699 | arm_cpu_topology_set(ci, id->ac_mpidr); | 699 | arm_cpu_topology_set(ci, id->ac_mpidr); | |
700 | aarch64_getcacheinfo(ci); | 700 | aarch64_getcacheinfo(ci); | |
701 | 701 | |||
702 | cpu_set_hatched(cpuindex); | 702 | cpu_set_hatched(cpuindex); | |
703 | 703 | |||
704 | /* | 704 | /* | |
705 | * return to assembly to wait for cpu_boot_secondary_processors | 705 | * return to assembly to wait for cpu_boot_secondary_processors | |
706 | */ | 706 | */ | |
707 | } | 707 | } | |
708 | 708 | |||
709 | 709 | |||
710 | /* | 710 | /* | |
711 | * When we are called, the MMU and caches are on and we are running on the stack | 711 | * When we are called, the MMU and caches are on and we are running on the stack | |
712 | * of the idlelwp for this cpu. | 712 | * of the idlelwp for this cpu. | |
713 | */ | 713 | */ | |
714 | void | 714 | void | |
715 | cpu_hatch(struct cpu_info *ci) | 715 | cpu_hatch(struct cpu_info *ci) | |
716 | { | 716 | { | |
717 | KASSERT(curcpu() == ci); | 717 | KASSERT(curcpu() == ci); | |
718 | KASSERT((reg_tcr_el1_read() & TCR_EPD0) != 0); | 718 | KASSERT((reg_tcr_el1_read() & TCR_EPD0) != 0); | |
719 | 719 | |||
720 | #ifdef DDB | 720 | #ifdef DDB | |
721 | db_machdep_cpu_init(); | 721 | db_machdep_cpu_init(); | |
722 | #endif | 722 | #endif | |
723 | 723 | |||
724 | cpu_init_counter(ci); | 724 | cpu_init_counter(ci); | |
725 | 725 | |||
726 | intr_cpu_init(ci); | 726 | intr_cpu_init(ci); | |
727 | 727 | |||
728 | #ifdef FDT | 728 | #ifdef FDT | |
729 | arm_fdt_cpu_hatch(ci); | 729 | arm_fdt_cpu_hatch(ci); | |
730 | #endif | 730 | #endif | |
731 | 731 | |||
732 | /* | 732 | /* | |
733 | * clear my bit of arm_cpu_mbox to tell cpu_boot_secondary_processors(). | 733 | * clear my bit of arm_cpu_mbox to tell cpu_boot_secondary_processors(). | |
734 | * there are cpu0,1,2,3, and if cpu2 is unresponsive, | 734 | * there are cpu0,1,2,3, and if cpu2 is unresponsive, | |
735 | * ci_index are each cpu0=0, cpu1=1, cpu2=undef, cpu3=2. | 735 | * ci_index are each cpu0=0, cpu1=1, cpu2=undef, cpu3=2. | |
736 | * therefore we have to use device_unit instead of ci_index for mbox. | 736 | * therefore we have to use device_unit instead of ci_index for mbox. | |
737 | */ | 737 | */ | |
738 | 738 | |||
739 | cpu_clr_mbox(device_unit(ci->ci_dev)); | 739 | cpu_clr_mbox(device_unit(ci->ci_dev)); | |
740 | } | 740 | } | |
741 | #endif /* MULTIPROCESSOR */ | 741 | #endif /* MULTIPROCESSOR */ |
--- src/sys/arch/arm/arm32/cpu.c 2021/10/31 16:23:47 1.152
+++ src/sys/arch/arm/arm32/cpu.c 2022/03/03 06:26:05 1.153
@@ -1,915 +1,915 @@ | @@ -1,915 +1,915 @@ | |||
1 | /* $NetBSD: cpu.c,v 1.152 2021/10/31 16:23:47 skrll Exp $ */ | 1 | /* $NetBSD: cpu.c,v 1.153 2022/03/03 06:26:05 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1995 Mark Brinicombe. | 4 | * Copyright (c) 1995 Mark Brinicombe. | |
5 | * Copyright (c) 1995 Brini. | 5 | * Copyright (c) 1995 Brini. | |
6 | * All rights reserved. | 6 | * All rights reserved. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | 16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | 17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by Brini. | 18 | * This product includes software developed by Brini. | |
19 | * 4. The name of the company nor the name of the author may be used to | 19 | * 4. The name of the company nor the name of the author may be used to | |
20 | * endorse or promote products derived from this software without specific | 20 | * endorse or promote products derived from this software without specific | |
21 | * prior written permission. | 21 | * prior written permission. | |
22 | * | 22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED | 23 | * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
24 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 24 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
26 | * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 26 | * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
33 | * SUCH DAMAGE. | 33 | * SUCH DAMAGE. | |
34 | * | 34 | * | |
35 | * RiscBSD kernel project | 35 | * RiscBSD kernel project | |
36 | * | 36 | * | |
37 | * cpu.c | 37 | * cpu.c | |
38 | * | 38 | * | |
39 | * Probing and configuration for the master CPU | 39 | * Probing and configuration for the master CPU | |
40 | * | 40 | * | |
41 | * Created : 10/10/95 | 41 | * Created : 10/10/95 | |
42 | */ | 42 | */ | |
43 | 43 | |||
44 | #include "opt_armfpe.h" | 44 | #include "opt_armfpe.h" | |
45 | #include "opt_cputypes.h" | 45 | #include "opt_cputypes.h" | |
46 | #include "opt_multiprocessor.h" | 46 | #include "opt_multiprocessor.h" | |
47 | 47 | |||
48 | #include <sys/cdefs.h> | 48 | #include <sys/cdefs.h> | |
49 | __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.152 2021/10/31 16:23:47 skrll Exp $"); | 49 | __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.153 2022/03/03 06:26:05 riastradh Exp $"); | |
50 | 50 | |||
51 | #include <sys/param.h> | 51 | #include <sys/param.h> | |
52 | 52 | |||
53 | #include <sys/conf.h> | 53 | #include <sys/conf.h> | |
54 | #include <sys/cpu.h> | 54 | #include <sys/cpu.h> | |
55 | #include <sys/device.h> | 55 | #include <sys/device.h> | |
56 | #include <sys/kmem.h> | 56 | #include <sys/kmem.h> | |
57 | #include <sys/proc.h> | 57 | #include <sys/proc.h> | |
58 | #include <sys/reboot.h> | 58 | #include <sys/reboot.h> | |
59 | #include <sys/systm.h> | 59 | #include <sys/systm.h> | |
60 | 60 | |||
61 | #include <uvm/uvm_extern.h> | 61 | #include <uvm/uvm_extern.h> | |
62 | 62 | |||
63 | #include <arm/locore.h> | 63 | #include <arm/locore.h> | |
64 | #include <arm/undefined.h> | 64 | #include <arm/undefined.h> | |
65 | #include <arm/cpu_topology.h> | 65 | #include <arm/cpu_topology.h> | |
66 | 66 | |||
67 | extern const char *cpu_arch; | 67 | extern const char *cpu_arch; | |
68 | 68 | |||
69 | #ifdef MULTIPROCESSOR | 69 | #ifdef MULTIPROCESSOR | |
70 | #ifdef MPDEBUG | 70 | #ifdef MPDEBUG | |
71 | uint32_t arm_cpu_marker[2] __cacheline_aligned = { 0, 0 }; | 71 | uint32_t arm_cpu_marker[2] __cacheline_aligned = { 0, 0 }; | |
72 | #endif | 72 | #endif | |
73 | 73 | |||
74 | #endif | 74 | #endif | |
75 | 75 | |||
76 | /* Prototypes */ | 76 | /* Prototypes */ | |
77 | void identify_arm_cpu(device_t, struct cpu_info *); | 77 | void identify_arm_cpu(device_t, struct cpu_info *); | |
78 | void identify_features(device_t, struct cpu_info *); | 78 | void identify_features(device_t, struct cpu_info *); | |
79 | void identify_cortex_caches(device_t); | 79 | void identify_cortex_caches(device_t); | |
80 | 80 | |||
81 | /* | 81 | /* | |
82 | * Identify the master (boot) CPU | 82 | * Identify the master (boot) CPU | |
83 | */ | 83 | */ | |
84 | 84 | |||
85 | void | 85 | void | |
86 | cpu_attach(device_t dv, cpuid_t id) | 86 | cpu_attach(device_t dv, cpuid_t id) | |
87 | { | 87 | { | |
88 | const char * const xname = device_xname(dv); | 88 | const char * const xname = device_xname(dv); | |
89 | const int unit = device_unit(dv); | 89 | const int unit = device_unit(dv); | |
90 | struct cpu_info *ci; | 90 | struct cpu_info *ci; | |
91 | 91 | |||
92 | if (unit == 0) { | 92 | if (unit == 0) { | |
93 | ci = curcpu(); | 93 | ci = curcpu(); | |
94 | 94 | |||
95 | /* Read SCTLR from cpu */ | 95 | /* Read SCTLR from cpu */ | |
96 | ci->ci_ctrl = cpu_control(0, 0); | 96 | ci->ci_ctrl = cpu_control(0, 0); | |
97 | 97 | |||
98 | /* Get the CPU ID from coprocessor 15 */ | 98 | /* Get the CPU ID from coprocessor 15 */ | |
99 | ci->ci_cpuid = id; | 99 | ci->ci_cpuid = id; | |
100 | ci->ci_arm_cpuid = cpu_idnum(); | 100 | ci->ci_arm_cpuid = cpu_idnum(); | |
101 | ci->ci_arm_cputype = ci->ci_arm_cpuid & CPU_ID_CPU_MASK; | 101 | ci->ci_arm_cputype = ci->ci_arm_cpuid & CPU_ID_CPU_MASK; | |
102 | ci->ci_arm_cpurev = ci->ci_arm_cpuid & CPU_ID_REVISION_MASK; | 102 | ci->ci_arm_cpurev = ci->ci_arm_cpuid & CPU_ID_REVISION_MASK; | |
103 | 103 | |||
104 | /* | 104 | /* | |
105 | * Get other sysregs for BP. APs information is grabbed in | 105 | * Get other sysregs for BP. APs information is grabbed in | |
106 | * cpu_init_secondary_processor. | 106 | * cpu_init_secondary_processor. | |
107 | */ | 107 | */ | |
108 | ci->ci_actlr = armreg_auxctl_read(); | 108 | ci->ci_actlr = armreg_auxctl_read(); | |
109 | ci->ci_revidr = armreg_revidr_read(); | 109 | ci->ci_revidr = armreg_revidr_read(); | |
110 | } else { | 110 | } else { | |
111 | #ifdef MULTIPROCESSOR | 111 | #ifdef MULTIPROCESSOR | |
112 | if ((boothowto & RB_MD1) != 0) { | 112 | if ((boothowto & RB_MD1) != 0) { | |
113 | aprint_naive("\n"); | 113 | aprint_naive("\n"); | |
114 | aprint_normal(": multiprocessor boot disabled\n"); | 114 | aprint_normal(": multiprocessor boot disabled\n"); | |
115 | return; | 115 | return; | |
116 | } | 116 | } | |
117 | 117 | |||
118 | KASSERT(unit < MAXCPUS); | 118 | KASSERT(unit < MAXCPUS); | |
119 | ci = &cpu_info_store[unit]; | 119 | ci = &cpu_info_store[unit]; | |
120 | 120 | |||
121 | KASSERT(cpu_info[unit] == NULL); | 121 | KASSERT(cpu_info[unit] == NULL); | |
122 | ci->ci_cpl = IPL_HIGH; | 122 | ci->ci_cpl = IPL_HIGH; | |
123 | ci->ci_cpuid = id; | 123 | ci->ci_cpuid = id; | |
124 | ci->ci_data.cpu_cc_freq = cpu_info_store[0].ci_data.cpu_cc_freq; | 124 | ci->ci_data.cpu_cc_freq = cpu_info_store[0].ci_data.cpu_cc_freq; | |
125 | 125 | |||
126 | ci->ci_undefsave[2] = cpu_info_store[0].ci_undefsave[2]; | 126 | ci->ci_undefsave[2] = cpu_info_store[0].ci_undefsave[2]; | |
127 | 127 | |||
128 | cpu_info[unit] = ci; | 128 | cpu_info[unit] = ci; | |
129 | if (cpu_hatched_p(unit) == false) { | 129 | if (cpu_hatched_p(unit) == false) { | |
130 | ci->ci_dev = dv; | 130 | ci->ci_dev = dv; | |
131 | dv->dv_private = ci; | 131 | device_set_private(dv, ci); | |
132 | aprint_naive(": disabled\n"); | 132 | aprint_naive(": disabled\n"); | |
133 | aprint_normal(": disabled (unresponsive)\n"); | 133 | aprint_normal(": disabled (unresponsive)\n"); | |
134 | return; | 134 | return; | |
135 | } | 135 | } | |
136 | #else | 136 | #else | |
137 | aprint_naive(": disabled\n"); | 137 | aprint_naive(": disabled\n"); | |
138 | aprint_normal(": disabled (uniprocessor kernel)\n"); | 138 | aprint_normal(": disabled (uniprocessor kernel)\n"); | |
139 | return; | 139 | return; | |
140 | #endif | 140 | #endif | |
141 | } | 141 | } | |
142 | 142 | |||
143 | ci->ci_dev = dv; | 143 | ci->ci_dev = dv; | |
144 | dv->dv_private = ci; | 144 | device_set_private(dv, ci); | |
145 | 145 | |||
146 | arm_cpu_do_topology(ci); | 146 | arm_cpu_do_topology(ci); | |
147 | 147 | |||
148 | evcnt_attach_dynamic(&ci->ci_arm700bugcount, EVCNT_TYPE_MISC, | 148 | evcnt_attach_dynamic(&ci->ci_arm700bugcount, EVCNT_TYPE_MISC, | |
149 | NULL, xname, "arm700swibug"); | 149 | NULL, xname, "arm700swibug"); | |
150 | 150 | |||
151 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_WRTBUF_0], EVCNT_TYPE_TRAP, | 151 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_WRTBUF_0], EVCNT_TYPE_TRAP, | |
152 | NULL, xname, "vector abort"); | 152 | NULL, xname, "vector abort"); | |
153 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_WRTBUF_1], EVCNT_TYPE_TRAP, | 153 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_WRTBUF_1], EVCNT_TYPE_TRAP, | |
154 | NULL, xname, "terminal abort"); | 154 | NULL, xname, "terminal abort"); | |
155 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_0], EVCNT_TYPE_TRAP, | 155 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_0], EVCNT_TYPE_TRAP, | |
156 | NULL, xname, "external linefetch abort (S)"); | 156 | NULL, xname, "external linefetch abort (S)"); | |
157 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_1], EVCNT_TYPE_TRAP, | 157 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_1], EVCNT_TYPE_TRAP, | |
158 | NULL, xname, "external linefetch abort (P)"); | 158 | NULL, xname, "external linefetch abort (P)"); | |
159 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_2], EVCNT_TYPE_TRAP, | 159 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_2], EVCNT_TYPE_TRAP, | |
160 | NULL, xname, "external non-linefetch abort (S)"); | 160 | NULL, xname, "external non-linefetch abort (S)"); | |
161 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_3], EVCNT_TYPE_TRAP, | 161 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSERR_3], EVCNT_TYPE_TRAP, | |
162 | NULL, xname, "external non-linefetch abort (P)"); | 162 | NULL, xname, "external non-linefetch abort (P)"); | |
163 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSTRNL1], EVCNT_TYPE_TRAP, | 163 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSTRNL1], EVCNT_TYPE_TRAP, | |
164 | NULL, xname, "external translation abort (L1)"); | 164 | NULL, xname, "external translation abort (L1)"); | |
165 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSTRNL2], EVCNT_TYPE_TRAP, | 165 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_BUSTRNL2], EVCNT_TYPE_TRAP, | |
166 | NULL, xname, "external translation abort (L2)"); | 166 | NULL, xname, "external translation abort (L2)"); | |
167 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_ALIGN_0], EVCNT_TYPE_TRAP, | 167 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_ALIGN_0], EVCNT_TYPE_TRAP, | |
168 | NULL, xname, "alignment abort (0)"); | 168 | NULL, xname, "alignment abort (0)"); | |
169 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_ALIGN_1], EVCNT_TYPE_TRAP, | 169 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_ALIGN_1], EVCNT_TYPE_TRAP, | |
170 | NULL, xname, "alignment abort (1)"); | 170 | NULL, xname, "alignment abort (1)"); | |
171 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_TRANS_S], EVCNT_TYPE_TRAP, | 171 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_TRANS_S], EVCNT_TYPE_TRAP, | |
172 | NULL, xname, "translation abort (S)"); | 172 | NULL, xname, "translation abort (S)"); | |
173 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_TRANS_P], EVCNT_TYPE_TRAP, | 173 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_TRANS_P], EVCNT_TYPE_TRAP, | |
174 | NULL, xname, "translation abort (P)"); | 174 | NULL, xname, "translation abort (P)"); | |
175 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_DOMAIN_S], EVCNT_TYPE_TRAP, | 175 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_DOMAIN_S], EVCNT_TYPE_TRAP, | |
176 | NULL, xname, "domain abort (S)"); | 176 | NULL, xname, "domain abort (S)"); | |
177 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_DOMAIN_P], EVCNT_TYPE_TRAP, | 177 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_DOMAIN_P], EVCNT_TYPE_TRAP, | |
178 | NULL, xname, "domain abort (P)"); | 178 | NULL, xname, "domain abort (P)"); | |
179 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_PERM_S], EVCNT_TYPE_TRAP, | 179 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_PERM_S], EVCNT_TYPE_TRAP, | |
180 | NULL, xname, "permission abort (S)"); | 180 | NULL, xname, "permission abort (S)"); | |
181 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_PERM_P], EVCNT_TYPE_TRAP, | 181 | evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_PERM_P], EVCNT_TYPE_TRAP, | |
182 | NULL, xname, "permission abort (P)"); | 182 | NULL, xname, "permission abort (P)"); | |
183 | evcnt_attach_dynamic_nozero(&ci->ci_und_ev, EVCNT_TYPE_TRAP, | 183 | evcnt_attach_dynamic_nozero(&ci->ci_und_ev, EVCNT_TYPE_TRAP, | |
184 | NULL, xname, "undefined insn traps"); | 184 | NULL, xname, "undefined insn traps"); | |
185 | evcnt_attach_dynamic_nozero(&ci->ci_und_cp15_ev, EVCNT_TYPE_TRAP, | 185 | evcnt_attach_dynamic_nozero(&ci->ci_und_cp15_ev, EVCNT_TYPE_TRAP, | |
186 | NULL, xname, "undefined cp15 insn traps"); | 186 | NULL, xname, "undefined cp15 insn traps"); | |
187 | 187 | |||
188 | ci->ci_kfpu_spl = -1; | 188 | ci->ci_kfpu_spl = -1; | |
189 | 189 | |||
190 | #ifdef MULTIPROCESSOR | 190 | #ifdef MULTIPROCESSOR | |
191 | if (unit != 0) { | 191 | if (unit != 0) { | |
192 | mi_cpu_attach(ci); | 192 | mi_cpu_attach(ci); | |
193 | #ifdef ARM_MMU_EXTENDED | 193 | #ifdef ARM_MMU_EXTENDED | |
194 | pmap_tlb_info_attach(&pmap_tlb0_info, ci); | 194 | pmap_tlb_info_attach(&pmap_tlb0_info, ci); | |
195 | #endif | 195 | #endif | |
196 | } | 196 | } | |
197 | #endif | 197 | #endif | |
198 | 198 | |||
199 | identify_arm_cpu(dv, ci); | 199 | identify_arm_cpu(dv, ci); | |
200 | 200 | |||
201 | #ifdef CPU_STRONGARM | 201 | #ifdef CPU_STRONGARM | |
202 | if (ci->ci_arm_cputype == CPU_ID_SA110 && | 202 | if (ci->ci_arm_cputype == CPU_ID_SA110 && | |
203 | ci->ci_arm_cpurev < 3) { | 203 | ci->ci_arm_cpurev < 3) { | |
204 | aprint_normal_dev(dv, "SA-110 with bugged STM^ instruction\n"); | 204 | aprint_normal_dev(dv, "SA-110 with bugged STM^ instruction\n"); | |
205 | } | 205 | } | |
206 | #endif | 206 | #endif | |
207 | 207 | |||
208 | #ifdef CPU_ARM8 | 208 | #ifdef CPU_ARM8 | |
209 | if ((ci->ci_arm_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) { | 209 | if ((ci->ci_arm_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) { | |
210 | int clock = arm8_clock_config(0, 0); | 210 | int clock = arm8_clock_config(0, 0); | |
211 | char *fclk; | 211 | char *fclk; | |
212 | aprint_normal_dev(dv, "ARM810 cp15=%02x", clock); | 212 | aprint_normal_dev(dv, "ARM810 cp15=%02x", clock); | |
213 | aprint_normal(" clock:%s", (clock & 1) ? " dynamic" : ""); | 213 | aprint_normal(" clock:%s", (clock & 1) ? " dynamic" : ""); | |
214 | aprint_normal("%s", (clock & 2) ? " sync" : ""); | 214 | aprint_normal("%s", (clock & 2) ? " sync" : ""); | |
215 | switch ((clock >> 2) & 3) { | 215 | switch ((clock >> 2) & 3) { | |
216 | case 0: | 216 | case 0: | |
217 | fclk = "bus clock"; | 217 | fclk = "bus clock"; | |
218 | break; | 218 | break; | |
219 | case 1: | 219 | case 1: | |
220 | fclk = "ref clock"; | 220 | fclk = "ref clock"; | |
221 | break; | 221 | break; | |
222 | case 3: | 222 | case 3: | |
223 | fclk = "pll"; | 223 | fclk = "pll"; | |
224 | break; | 224 | break; | |
225 | default: | 225 | default: | |
226 | fclk = "illegal"; | 226 | fclk = "illegal"; | |
227 | break; | 227 | break; | |
228 | } | 228 | } | |
229 | aprint_normal(" fclk source=%s\n", fclk); | 229 | aprint_normal(" fclk source=%s\n", fclk); | |
230 | } | 230 | } | |
231 | #endif | 231 | #endif | |
232 | 232 | |||
233 | vfp_attach(ci); | 233 | vfp_attach(ci); | |
234 | } | 234 | } | |
235 | 235 | |||
236 | enum cpu_class { | 236 | enum cpu_class { | |
237 | CPU_CLASS_NONE, | 237 | CPU_CLASS_NONE, | |
238 | CPU_CLASS_ARM2, | 238 | CPU_CLASS_ARM2, | |
239 | CPU_CLASS_ARM2AS, | 239 | CPU_CLASS_ARM2AS, | |
240 | CPU_CLASS_ARM3, | 240 | CPU_CLASS_ARM3, | |
241 | CPU_CLASS_ARM6, | 241 | CPU_CLASS_ARM6, | |
242 | CPU_CLASS_ARM7, | 242 | CPU_CLASS_ARM7, | |
243 | CPU_CLASS_ARM7TDMI, | 243 | CPU_CLASS_ARM7TDMI, | |
244 | CPU_CLASS_ARM8, | 244 | CPU_CLASS_ARM8, | |
245 | CPU_CLASS_ARM9TDMI, | 245 | CPU_CLASS_ARM9TDMI, | |
246 | CPU_CLASS_ARM9ES, | 246 | CPU_CLASS_ARM9ES, | |
247 | CPU_CLASS_ARM9EJS, | 247 | CPU_CLASS_ARM9EJS, | |
248 | CPU_CLASS_ARM10E, | 248 | CPU_CLASS_ARM10E, | |
249 | CPU_CLASS_ARM10EJ, | 249 | CPU_CLASS_ARM10EJ, | |
250 | CPU_CLASS_SA1, | 250 | CPU_CLASS_SA1, | |
251 | CPU_CLASS_XSCALE, | 251 | CPU_CLASS_XSCALE, | |
252 | CPU_CLASS_ARM11J, | 252 | CPU_CLASS_ARM11J, | |
253 | CPU_CLASS_ARMV4, | 253 | CPU_CLASS_ARMV4, | |
254 | CPU_CLASS_CORTEX, | 254 | CPU_CLASS_CORTEX, | |
255 | CPU_CLASS_PJ4B, | 255 | CPU_CLASS_PJ4B, | |
256 | }; | 256 | }; | |
257 | 257 | |||
258 | static const char * const generic_steppings[16] = { | 258 | static const char * const generic_steppings[16] = { | |
259 | "rev 0", "rev 1", "rev 2", "rev 3", | 259 | "rev 0", "rev 1", "rev 2", "rev 3", | |
260 | "rev 4", "rev 5", "rev 6", "rev 7", | 260 | "rev 4", "rev 5", "rev 6", "rev 7", | |
261 | "rev 8", "rev 9", "rev 10", "rev 11", | 261 | "rev 8", "rev 9", "rev 10", "rev 11", | |
262 | "rev 12", "rev 13", "rev 14", "rev 15", | 262 | "rev 12", "rev 13", "rev 14", "rev 15", | |
263 | }; | 263 | }; | |
264 | 264 | |||
265 | static const char * const pN_steppings[16] = { | 265 | static const char * const pN_steppings[16] = { | |
266 | "*p0", "*p1", "*p2", "*p3", "*p4", "*p5", "*p6", "*p7", | 266 | "*p0", "*p1", "*p2", "*p3", "*p4", "*p5", "*p6", "*p7", | |
267 | "*p8", "*p9", "*p10", "*p11", "*p12", "*p13", "*p14", "*p15", | 267 | "*p8", "*p9", "*p10", "*p11", "*p12", "*p13", "*p14", "*p15", | |
268 | }; | 268 | }; | |
269 | 269 | |||
270 | static const char * const sa110_steppings[16] = { | 270 | static const char * const sa110_steppings[16] = { | |
271 | "rev 0", "step J", "step K", "step S", | 271 | "rev 0", "step J", "step K", "step S", | |
272 | "step T", "rev 5", "rev 6", "rev 7", | 272 | "step T", "rev 5", "rev 6", "rev 7", | |
273 | "rev 8", "rev 9", "rev 10", "rev 11", | 273 | "rev 8", "rev 9", "rev 10", "rev 11", | |
274 | "rev 12", "rev 13", "rev 14", "rev 15", | 274 | "rev 12", "rev 13", "rev 14", "rev 15", | |
275 | }; | 275 | }; | |
276 | 276 | |||
277 | static const char * const sa1100_steppings[16] = { | 277 | static const char * const sa1100_steppings[16] = { | |
278 | "rev 0", "step B", "step C", "rev 3", | 278 | "rev 0", "step B", "step C", "rev 3", | |
279 | "rev 4", "rev 5", "rev 6", "rev 7", | 279 | "rev 4", "rev 5", "rev 6", "rev 7", | |
280 | "step D", "step E", "rev 10" "step G", | 280 | "step D", "step E", "rev 10" "step G", | |
281 | "rev 12", "rev 13", "rev 14", "rev 15", | 281 | "rev 12", "rev 13", "rev 14", "rev 15", | |
282 | }; | 282 | }; | |
283 | 283 | |||
284 | static const char * const sa1110_steppings[16] = { | 284 | static const char * const sa1110_steppings[16] = { | |
285 | "step A-0", "rev 1", "rev 2", "rev 3", | 285 | "step A-0", "rev 1", "rev 2", "rev 3", | |
286 | "step B-0", "step B-1", "step B-2", "step B-3", | 286 | "step B-0", "step B-1", "step B-2", "step B-3", | |
287 | "step B-4", "step B-5", "rev 10", "rev 11", | 287 | "step B-4", "step B-5", "rev 10", "rev 11", | |
288 | "rev 12", "rev 13", "rev 14", "rev 15", | 288 | "rev 12", "rev 13", "rev 14", "rev 15", | |
289 | }; | 289 | }; | |
290 | 290 | |||
291 | static const char * const ixp12x0_steppings[16] = { | 291 | static const char * const ixp12x0_steppings[16] = { | |
292 | "(IXP1200 step A)", "(IXP1200 step B)", | 292 | "(IXP1200 step A)", "(IXP1200 step B)", | |
293 | "rev 2", "(IXP1200 step C)", | 293 | "rev 2", "(IXP1200 step C)", | |
294 | "(IXP1200 step D)", "(IXP1240/1250 step A)", | 294 | "(IXP1200 step D)", "(IXP1240/1250 step A)", | |
295 | "(IXP1240 step B)", "(IXP1250 step B)", | 295 | "(IXP1240 step B)", "(IXP1250 step B)", | |
296 | "rev 8", "rev 9", "rev 10", "rev 11", | 296 | "rev 8", "rev 9", "rev 10", "rev 11", | |
297 | "rev 12", "rev 13", "rev 14", "rev 15", | 297 | "rev 12", "rev 13", "rev 14", "rev 15", | |
298 | }; | 298 | }; | |
299 | 299 | |||
300 | static const char * const xscale_steppings[16] = { | 300 | static const char * const xscale_steppings[16] = { | |
301 | "step A-0", "step A-1", "step B-0", "step C-0", | 301 | "step A-0", "step A-1", "step B-0", "step C-0", | |
302 | "step D-0", "rev 5", "rev 6", "rev 7", | 302 | "step D-0", "rev 5", "rev 6", "rev 7", | |
303 | "rev 8", "rev 9", "rev 10", "rev 11", | 303 | "rev 8", "rev 9", "rev 10", "rev 11", | |
304 | "rev 12", "rev 13", "rev 14", "rev 15", | 304 | "rev 12", "rev 13", "rev 14", "rev 15", | |
305 | }; | 305 | }; | |
306 | 306 | |||
307 | static const char * const i80321_steppings[16] = { | 307 | static const char * const i80321_steppings[16] = { | |
308 | "step A-0", "step B-0", "rev 2", "rev 3", | 308 | "step A-0", "step B-0", "rev 2", "rev 3", | |
309 | "rev 4", "rev 5", "rev 6", "rev 7", | 309 | "rev 4", "rev 5", "rev 6", "rev 7", | |
310 | "rev 8", "rev 9", "rev 10", "rev 11", | 310 | "rev 8", "rev 9", "rev 10", "rev 11", | |
311 | "rev 12", "rev 13", "rev 14", "rev 15", | 311 | "rev 12", "rev 13", "rev 14", "rev 15", | |
312 | }; | 312 | }; | |
313 | 313 | |||
314 | static const char * const i80219_steppings[16] = { | 314 | static const char * const i80219_steppings[16] = { | |
315 | "step A-0", "rev 1", "rev 2", "rev 3", | 315 | "step A-0", "rev 1", "rev 2", "rev 3", | |
316 | "rev 4", "rev 5", "rev 6", "rev 7", | 316 | "rev 4", "rev 5", "rev 6", "rev 7", | |
317 | "rev 8", "rev 9", "rev 10", "rev 11", | 317 | "rev 8", "rev 9", "rev 10", "rev 11", | |
318 | "rev 12", "rev 13", "rev 14", "rev 15", | 318 | "rev 12", "rev 13", "rev 14", "rev 15", | |
319 | }; | 319 | }; | |
320 | 320 | |||
321 | /* Steppings for PXA2[15]0 */ | 321 | /* Steppings for PXA2[15]0 */ | |
322 | static const char * const pxa2x0_steppings[16] = { | 322 | static const char * const pxa2x0_steppings[16] = { | |
323 | "step A-0", "step A-1", "step B-0", "step B-1", | 323 | "step A-0", "step A-1", "step B-0", "step B-1", | |
324 | "step B-2", "step C-0", "rev 6", "rev 7", | 324 | "step B-2", "step C-0", "rev 6", "rev 7", | |
325 | "rev 8", "rev 9", "rev 10", "rev 11", | 325 | "rev 8", "rev 9", "rev 10", "rev 11", | |
326 | "rev 12", "rev 13", "rev 14", "rev 15", | 326 | "rev 12", "rev 13", "rev 14", "rev 15", | |
327 | }; | 327 | }; | |
328 | 328 | |||
329 | /* Steppings for PXA255/26x. | 329 | /* Steppings for PXA255/26x. | |
330 | * rev 5: PXA26x B0, rev 6: PXA255 A0 | 330 | * rev 5: PXA26x B0, rev 6: PXA255 A0 | |
331 | */ | 331 | */ | |
332 | static const char * const pxa255_steppings[16] = { | 332 | static const char * const pxa255_steppings[16] = { | |
333 | "rev 0", "rev 1", "rev 2", "step A-0", | 333 | "rev 0", "rev 1", "rev 2", "step A-0", | |
334 | "rev 4", "step B-0", "step A-0", "rev 7", | 334 | "rev 4", "step B-0", "step A-0", "rev 7", | |
335 | "rev 8", "rev 9", "rev 10", "rev 11", | 335 | "rev 8", "rev 9", "rev 10", "rev 11", | |
336 | "rev 12", "rev 13", "rev 14", "rev 15", | 336 | "rev 12", "rev 13", "rev 14", "rev 15", | |
337 | }; | 337 | }; | |
338 | 338 | |||
339 | /* Stepping for PXA27x */ | 339 | /* Stepping for PXA27x */ | |
340 | static const char * const pxa27x_steppings[16] = { | 340 | static const char * const pxa27x_steppings[16] = { | |
341 | "step A-0", "step A-1", "step B-0", "step B-1", | 341 | "step A-0", "step A-1", "step B-0", "step B-1", | |
342 | "step C-0", "rev 5", "rev 6", "rev 7", | 342 | "step C-0", "rev 5", "rev 6", "rev 7", | |
343 | "rev 8", "rev 9", "rev 10", "rev 11", | 343 | "rev 8", "rev 9", "rev 10", "rev 11", | |
344 | "rev 12", "rev 13", "rev 14", "rev 15", | 344 | "rev 12", "rev 13", "rev 14", "rev 15", | |
345 | }; | 345 | }; | |
346 | 346 | |||
347 | static const char * const ixp425_steppings[16] = { | 347 | static const char * const ixp425_steppings[16] = { | |
348 | "step 0", "rev 1", "rev 2", "rev 3", | 348 | "step 0", "rev 1", "rev 2", "rev 3", | |
349 | "rev 4", "rev 5", "rev 6", "rev 7", | 349 | "rev 4", "rev 5", "rev 6", "rev 7", | |
350 | "rev 8", "rev 9", "rev 10", "rev 11", | 350 | "rev 8", "rev 9", "rev 10", "rev 11", | |
351 | "rev 12", "rev 13", "rev 14", "rev 15", | 351 | "rev 12", "rev 13", "rev 14", "rev 15", | |
352 | }; | 352 | }; | |
353 | 353 | |||
354 | struct cpuidtab { | 354 | struct cpuidtab { | |
355 | uint32_t cpuid; | 355 | uint32_t cpuid; | |
356 | enum cpu_class cpu_class; | 356 | enum cpu_class cpu_class; | |
357 | const char *cpu_classname; | 357 | const char *cpu_classname; | |
358 | const char * const *cpu_steppings; | 358 | const char * const *cpu_steppings; | |
359 | char cpu_arch[8]; | 359 | char cpu_arch[8]; | |
360 | }; | 360 | }; | |
361 | 361 | |||
362 | const struct cpuidtab cpuids[] = { | 362 | const struct cpuidtab cpuids[] = { | |
363 | { CPU_ID_ARM2, CPU_CLASS_ARM2, "ARM2", | 363 | { CPU_ID_ARM2, CPU_CLASS_ARM2, "ARM2", | |
364 | generic_steppings, "2" }, | 364 | generic_steppings, "2" }, | |
365 | { CPU_ID_ARM250, CPU_CLASS_ARM2AS, "ARM250", | 365 | { CPU_ID_ARM250, CPU_CLASS_ARM2AS, "ARM250", | |
366 | generic_steppings, "2" }, | 366 | generic_steppings, "2" }, | |
367 | 367 | |||
368 | { CPU_ID_ARM3, CPU_CLASS_ARM3, "ARM3", | 368 | { CPU_ID_ARM3, CPU_CLASS_ARM3, "ARM3", | |
369 | generic_steppings, "2A" }, | 369 | generic_steppings, "2A" }, | |
370 | 370 | |||
371 | { CPU_ID_ARM600, CPU_CLASS_ARM6, "ARM600", | 371 | { CPU_ID_ARM600, CPU_CLASS_ARM6, "ARM600", | |
372 | generic_steppings, "3" }, | 372 | generic_steppings, "3" }, | |
373 | { CPU_ID_ARM610, CPU_CLASS_ARM6, "ARM610", | 373 | { CPU_ID_ARM610, CPU_CLASS_ARM6, "ARM610", | |
374 | generic_steppings, "3" }, | 374 | generic_steppings, "3" }, | |
375 | { CPU_ID_ARM620, CPU_CLASS_ARM6, "ARM620", | 375 | { CPU_ID_ARM620, CPU_CLASS_ARM6, "ARM620", | |
376 | generic_steppings, "3" }, | 376 | generic_steppings, "3" }, | |
377 | 377 | |||
378 | { CPU_ID_ARM700, CPU_CLASS_ARM7, "ARM700", | 378 | { CPU_ID_ARM700, CPU_CLASS_ARM7, "ARM700", | |
379 | generic_steppings, "3" }, | 379 | generic_steppings, "3" }, | |
380 | { CPU_ID_ARM710, CPU_CLASS_ARM7, "ARM710", | 380 | { CPU_ID_ARM710, CPU_CLASS_ARM7, "ARM710", | |
381 | generic_steppings, "3" }, | 381 | generic_steppings, "3" }, | |
382 | { CPU_ID_ARM7500, CPU_CLASS_ARM7, "ARM7500", | 382 | { CPU_ID_ARM7500, CPU_CLASS_ARM7, "ARM7500", | |
383 | generic_steppings, "3" }, | 383 | generic_steppings, "3" }, | |
384 | { CPU_ID_ARM710A, CPU_CLASS_ARM7, "ARM710a", | 384 | { CPU_ID_ARM710A, CPU_CLASS_ARM7, "ARM710a", | |
385 | generic_steppings, "3" }, | 385 | generic_steppings, "3" }, | |
386 | { CPU_ID_ARM7500FE, CPU_CLASS_ARM7, "ARM7500FE", | 386 | { CPU_ID_ARM7500FE, CPU_CLASS_ARM7, "ARM7500FE", | |
387 | generic_steppings, "3" }, | 387 | generic_steppings, "3" }, | |
388 | 388 | |||
389 | { CPU_ID_ARM810, CPU_CLASS_ARM8, "ARM810", | 389 | { CPU_ID_ARM810, CPU_CLASS_ARM8, "ARM810", | |
390 | generic_steppings, "4" }, | 390 | generic_steppings, "4" }, | |
391 | 391 | |||
392 | { CPU_ID_SA110, CPU_CLASS_SA1, "SA-110", | 392 | { CPU_ID_SA110, CPU_CLASS_SA1, "SA-110", | |
393 | sa110_steppings, "4" }, | 393 | sa110_steppings, "4" }, | |
394 | { CPU_ID_SA1100, CPU_CLASS_SA1, "SA-1100", | 394 | { CPU_ID_SA1100, CPU_CLASS_SA1, "SA-1100", | |
395 | sa1100_steppings, "4" }, | 395 | sa1100_steppings, "4" }, | |
396 | { CPU_ID_SA1110, CPU_CLASS_SA1, "SA-1110", | 396 | { CPU_ID_SA1110, CPU_CLASS_SA1, "SA-1110", | |
397 | sa1110_steppings, "4" }, | 397 | sa1110_steppings, "4" }, | |
398 | 398 | |||
399 | { CPU_ID_FA526, CPU_CLASS_ARMV4, "FA526", | 399 | { CPU_ID_FA526, CPU_CLASS_ARMV4, "FA526", | |
400 | generic_steppings, "4" }, | 400 | generic_steppings, "4" }, | |
401 | 401 | |||
402 | { CPU_ID_IXP1200, CPU_CLASS_SA1, "IXP1200", | 402 | { CPU_ID_IXP1200, CPU_CLASS_SA1, "IXP1200", | |
403 | ixp12x0_steppings, "4" }, | 403 | ixp12x0_steppings, "4" }, | |
404 | 404 | |||
405 | { CPU_ID_ARM710T, CPU_CLASS_ARM7TDMI, "ARM710T", | 405 | { CPU_ID_ARM710T, CPU_CLASS_ARM7TDMI, "ARM710T", | |
406 | generic_steppings, "4T" }, | 406 | generic_steppings, "4T" }, | |
407 | { CPU_ID_ARM720T, CPU_CLASS_ARM7TDMI, "ARM720T", | 407 | { CPU_ID_ARM720T, CPU_CLASS_ARM7TDMI, "ARM720T", | |
408 | generic_steppings, "4T" }, | 408 | generic_steppings, "4T" }, | |
409 | { CPU_ID_ARM740T8K, CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)", | 409 | { CPU_ID_ARM740T8K, CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)", | |
410 | generic_steppings, "4T" }, | 410 | generic_steppings, "4T" }, | |
411 | { CPU_ID_ARM740T4K, CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)", | 411 | { CPU_ID_ARM740T4K, CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)", | |
412 | generic_steppings, "4T" }, | 412 | generic_steppings, "4T" }, | |
413 | { CPU_ID_ARM920T, CPU_CLASS_ARM9TDMI, "ARM920T", | 413 | { CPU_ID_ARM920T, CPU_CLASS_ARM9TDMI, "ARM920T", | |
414 | generic_steppings, "4T" }, | 414 | generic_steppings, "4T" }, | |
415 | { CPU_ID_ARM922T, CPU_CLASS_ARM9TDMI, "ARM922T", | 415 | { CPU_ID_ARM922T, CPU_CLASS_ARM9TDMI, "ARM922T", | |
416 | generic_steppings, "4T" }, | 416 | generic_steppings, "4T" }, | |
417 | { CPU_ID_ARM940T, CPU_CLASS_ARM9TDMI, "ARM940T", | 417 | { CPU_ID_ARM940T, CPU_CLASS_ARM9TDMI, "ARM940T", | |
418 | generic_steppings, "4T" }, | 418 | generic_steppings, "4T" }, | |
419 | { CPU_ID_TI925T, CPU_CLASS_ARM9TDMI, "TI ARM925T", | 419 | { CPU_ID_TI925T, CPU_CLASS_ARM9TDMI, "TI ARM925T", | |
420 | generic_steppings, "4T" }, | 420 | generic_steppings, "4T" }, | |
421 | 421 | |||
422 | { CPU_ID_ARM946ES, CPU_CLASS_ARM9ES, "ARM946E-S", | 422 | { CPU_ID_ARM946ES, CPU_CLASS_ARM9ES, "ARM946E-S", | |
423 | generic_steppings, "5TE" }, | 423 | generic_steppings, "5TE" }, | |
424 | { CPU_ID_ARM966ES, CPU_CLASS_ARM9ES, "ARM966E-S", | 424 | { CPU_ID_ARM966ES, CPU_CLASS_ARM9ES, "ARM966E-S", | |
425 | generic_steppings, "5TE" }, | 425 | generic_steppings, "5TE" }, | |
426 | { CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S", | 426 | { CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S", | |
427 | generic_steppings, "5TE" }, | 427 | generic_steppings, "5TE" }, | |
428 | { CPU_ID_MV88SV131, CPU_CLASS_ARM9ES, "Sheeva 88SV131", | 428 | { CPU_ID_MV88SV131, CPU_CLASS_ARM9ES, "Sheeva 88SV131", | |
429 | generic_steppings, "5TE" }, | 429 | generic_steppings, "5TE" }, | |
430 | { CPU_ID_MV88FR571_VD, CPU_CLASS_ARM9ES, "Sheeva 88FR571-vd", | 430 | { CPU_ID_MV88FR571_VD, CPU_CLASS_ARM9ES, "Sheeva 88FR571-vd", | |
431 | generic_steppings, "5TE" }, | 431 | generic_steppings, "5TE" }, | |
432 | 432 | |||
433 | { CPU_ID_80200, CPU_CLASS_XSCALE, "i80200", | 433 | { CPU_ID_80200, CPU_CLASS_XSCALE, "i80200", | |
434 | xscale_steppings, "5TE" }, | 434 | xscale_steppings, "5TE" }, | |
435 | 435 | |||
436 | { CPU_ID_80321_400, CPU_CLASS_XSCALE, "i80321 400MHz", | 436 | { CPU_ID_80321_400, CPU_CLASS_XSCALE, "i80321 400MHz", | |
437 | i80321_steppings, "5TE" }, | 437 | i80321_steppings, "5TE" }, | |
438 | { CPU_ID_80321_600, CPU_CLASS_XSCALE, "i80321 600MHz", | 438 | { CPU_ID_80321_600, CPU_CLASS_XSCALE, "i80321 600MHz", | |
439 | i80321_steppings, "5TE" }, | 439 | i80321_steppings, "5TE" }, | |
440 | { CPU_ID_80321_400_B0, CPU_CLASS_XSCALE, "i80321 400MHz", | 440 | { CPU_ID_80321_400_B0, CPU_CLASS_XSCALE, "i80321 400MHz", | |
441 | i80321_steppings, "5TE" }, | 441 | i80321_steppings, "5TE" }, | |
442 | { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz", | 442 | { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz", | |
443 | i80321_steppings, "5TE" }, | 443 | i80321_steppings, "5TE" }, | |
444 | 444 | |||
445 | { CPU_ID_80219_400, CPU_CLASS_XSCALE, "i80219 400MHz", | 445 | { CPU_ID_80219_400, CPU_CLASS_XSCALE, "i80219 400MHz", | |
446 | i80219_steppings, "5TE" }, | 446 | i80219_steppings, "5TE" }, | |
447 | { CPU_ID_80219_600, CPU_CLASS_XSCALE, "i80219 600MHz", | 447 | { CPU_ID_80219_600, CPU_CLASS_XSCALE, "i80219 600MHz", | |
448 | i80219_steppings, "5TE" }, | 448 | i80219_steppings, "5TE" }, | |
449 | 449 | |||
450 | { CPU_ID_PXA27X, CPU_CLASS_XSCALE, "PXA27x", | 450 | { CPU_ID_PXA27X, CPU_CLASS_XSCALE, "PXA27x", | |
451 | pxa27x_steppings, "5TE" }, | 451 | pxa27x_steppings, "5TE" }, | |
452 | { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250", | 452 | { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250", | |
453 | pxa2x0_steppings, "5TE" }, | 453 | pxa2x0_steppings, "5TE" }, | |
454 | { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210", | 454 | { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210", | |
455 | pxa2x0_steppings, "5TE" }, | 455 | pxa2x0_steppings, "5TE" }, | |
456 | { CPU_ID_PXA250B, CPU_CLASS_XSCALE, "PXA250", | 456 | { CPU_ID_PXA250B, CPU_CLASS_XSCALE, "PXA250", | |
457 | pxa2x0_steppings, "5TE" }, | 457 | pxa2x0_steppings, "5TE" }, | |
458 | { CPU_ID_PXA210B, CPU_CLASS_XSCALE, "PXA210", | 458 | { CPU_ID_PXA210B, CPU_CLASS_XSCALE, "PXA210", | |
459 | pxa2x0_steppings, "5TE" }, | 459 | pxa2x0_steppings, "5TE" }, | |
460 | { CPU_ID_PXA250C, CPU_CLASS_XSCALE, "PXA255/26x", | 460 | { CPU_ID_PXA250C, CPU_CLASS_XSCALE, "PXA255/26x", | |
461 | pxa255_steppings, "5TE" }, | 461 | pxa255_steppings, "5TE" }, | |
462 | { CPU_ID_PXA210C, CPU_CLASS_XSCALE, "PXA210", | 462 | { CPU_ID_PXA210C, CPU_CLASS_XSCALE, "PXA210", | |
463 | pxa2x0_steppings, "5TE" }, | 463 | pxa2x0_steppings, "5TE" }, | |
464 | 464 | |||
465 | { CPU_ID_IXP425_533, CPU_CLASS_XSCALE, "IXP425 533MHz", | 465 | { CPU_ID_IXP425_533, CPU_CLASS_XSCALE, "IXP425 533MHz", | |
466 | ixp425_steppings, "5TE" }, | 466 | ixp425_steppings, "5TE" }, | |
467 | { CPU_ID_IXP425_400, CPU_CLASS_XSCALE, "IXP425 400MHz", | 467 | { CPU_ID_IXP425_400, CPU_CLASS_XSCALE, "IXP425 400MHz", | |
468 | ixp425_steppings, "5TE" }, | 468 | ixp425_steppings, "5TE" }, | |
469 | { CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz", | 469 | { CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz", | |
470 | ixp425_steppings, "5TE" }, | 470 | ixp425_steppings, "5TE" }, | |
471 | 471 | |||
472 | { CPU_ID_ARM1020E, CPU_CLASS_ARM10E, "ARM1020E", | 472 | { CPU_ID_ARM1020E, CPU_CLASS_ARM10E, "ARM1020E", | |
473 | generic_steppings, "5TE" }, | 473 | generic_steppings, "5TE" }, | |
474 | { CPU_ID_ARM1022ES, CPU_CLASS_ARM10E, "ARM1022E-S", | 474 | { CPU_ID_ARM1022ES, CPU_CLASS_ARM10E, "ARM1022E-S", | |
475 | generic_steppings, "5TE" }, | 475 | generic_steppings, "5TE" }, | |
476 | 476 | |||
477 | { CPU_ID_ARM1026EJS, CPU_CLASS_ARM10EJ, "ARM1026EJ-S", | 477 | { CPU_ID_ARM1026EJS, CPU_CLASS_ARM10EJ, "ARM1026EJ-S", | |
478 | generic_steppings, "5TEJ" }, | 478 | generic_steppings, "5TEJ" }, | |
479 | { CPU_ID_ARM926EJS, CPU_CLASS_ARM9EJS, "ARM926EJ-S r0", | 479 | { CPU_ID_ARM926EJS, CPU_CLASS_ARM9EJS, "ARM926EJ-S r0", | |
480 | pN_steppings, "5TEJ" }, | 480 | pN_steppings, "5TEJ" }, | |
481 | 481 | |||
482 | { CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S r0", | 482 | { CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S r0", | |
483 | pN_steppings, "6J" }, | 483 | pN_steppings, "6J" }, | |
484 | { CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S r1", | 484 | { CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S r1", | |
485 | pN_steppings, "6J" }, | 485 | pN_steppings, "6J" }, | |
486 | #if 0 | 486 | #if 0 | |
487 | /* The ARM1156T2-S only has a memory protection unit */ | 487 | /* The ARM1156T2-S only has a memory protection unit */ | |
488 | { CPU_ID_ARM1156T2S, CPU_CLASS_ARM11J, "ARM1156T2-S r0", | 488 | { CPU_ID_ARM1156T2S, CPU_CLASS_ARM11J, "ARM1156T2-S r0", | |
489 | pN_steppings, "6T2" }, | 489 | pN_steppings, "6T2" }, | |
490 | #endif | 490 | #endif | |
491 | { CPU_ID_ARM1176JZS, CPU_CLASS_ARM11J, "ARM1176JZ-S r0", | 491 | { CPU_ID_ARM1176JZS, CPU_CLASS_ARM11J, "ARM1176JZ-S r0", | |
492 | pN_steppings, "6ZK" }, | 492 | pN_steppings, "6ZK" }, | |
493 | 493 | |||
494 | { CPU_ID_ARM11MPCORE, CPU_CLASS_ARM11J, "ARM11 MPCore", | 494 | { CPU_ID_ARM11MPCORE, CPU_CLASS_ARM11J, "ARM11 MPCore", | |
495 | generic_steppings, "6K" }, | 495 | generic_steppings, "6K" }, | |
496 | 496 | |||
497 | { CPU_ID_CORTEXA5R0, CPU_CLASS_CORTEX, "Cortex-A5 r0", | 497 | { CPU_ID_CORTEXA5R0, CPU_CLASS_CORTEX, "Cortex-A5 r0", | |
498 | pN_steppings, "7A" }, | 498 | pN_steppings, "7A" }, | |
499 | { CPU_ID_CORTEXA7R0, CPU_CLASS_CORTEX, "Cortex-A7 r0", | 499 | { CPU_ID_CORTEXA7R0, CPU_CLASS_CORTEX, "Cortex-A7 r0", | |
500 | pN_steppings, "7A" }, | 500 | pN_steppings, "7A" }, | |
501 | { CPU_ID_CORTEXA8R1, CPU_CLASS_CORTEX, "Cortex-A8 r1", | 501 | { CPU_ID_CORTEXA8R1, CPU_CLASS_CORTEX, "Cortex-A8 r1", | |
502 | pN_steppings, "7A" }, | 502 | pN_steppings, "7A" }, | |
503 | { CPU_ID_CORTEXA8R2, CPU_CLASS_CORTEX, "Cortex-A8 r2", | 503 | { CPU_ID_CORTEXA8R2, CPU_CLASS_CORTEX, "Cortex-A8 r2", | |
504 | pN_steppings, "7A" }, | 504 | pN_steppings, "7A" }, | |
505 | { CPU_ID_CORTEXA8R3, CPU_CLASS_CORTEX, "Cortex-A8 r3", | 505 | { CPU_ID_CORTEXA8R3, CPU_CLASS_CORTEX, "Cortex-A8 r3", | |
506 | pN_steppings, "7A" }, | 506 | pN_steppings, "7A" }, | |
507 | { CPU_ID_CORTEXA9R1, CPU_CLASS_CORTEX, "Cortex-A9 r1", | 507 | { CPU_ID_CORTEXA9R1, CPU_CLASS_CORTEX, "Cortex-A9 r1", | |
508 | pN_steppings, "7A" }, | 508 | pN_steppings, "7A" }, | |
509 | { CPU_ID_CORTEXA9R2, CPU_CLASS_CORTEX, "Cortex-A9 r2", | 509 | { CPU_ID_CORTEXA9R2, CPU_CLASS_CORTEX, "Cortex-A9 r2", | |
510 | pN_steppings, "7A" }, | 510 | pN_steppings, "7A" }, | |
511 | { CPU_ID_CORTEXA9R3, CPU_CLASS_CORTEX, "Cortex-A9 r3", | 511 | { CPU_ID_CORTEXA9R3, CPU_CLASS_CORTEX, "Cortex-A9 r3", | |
512 | pN_steppings, "7A" }, | 512 | pN_steppings, "7A" }, | |
513 | { CPU_ID_CORTEXA9R4, CPU_CLASS_CORTEX, "Cortex-A9 r4", | 513 | { CPU_ID_CORTEXA9R4, CPU_CLASS_CORTEX, "Cortex-A9 r4", | |
514 | pN_steppings, "7A" }, | 514 | pN_steppings, "7A" }, | |
515 | { CPU_ID_CORTEXA12R0, CPU_CLASS_CORTEX, "Cortex-A17(A12) r0", /* A12 was rebranded A17 */ | 515 | { CPU_ID_CORTEXA12R0, CPU_CLASS_CORTEX, "Cortex-A17(A12) r0", /* A12 was rebranded A17 */ | |
516 | pN_steppings, "7A" }, | 516 | pN_steppings, "7A" }, | |
517 | { CPU_ID_CORTEXA15R2, CPU_CLASS_CORTEX, "Cortex-A15 r2", | 517 | { CPU_ID_CORTEXA15R2, CPU_CLASS_CORTEX, "Cortex-A15 r2", | |
518 | pN_steppings, "7A" }, | 518 | pN_steppings, "7A" }, | |
519 | { CPU_ID_CORTEXA15R3, CPU_CLASS_CORTEX, "Cortex-A15 r3", | 519 | { CPU_ID_CORTEXA15R3, CPU_CLASS_CORTEX, "Cortex-A15 r3", | |
520 | pN_steppings, "7A" }, | 520 | pN_steppings, "7A" }, | |
521 | { CPU_ID_CORTEXA15R4, CPU_CLASS_CORTEX, "Cortex-A15 r4", | 521 | { CPU_ID_CORTEXA15R4, CPU_CLASS_CORTEX, "Cortex-A15 r4", | |
522 | pN_steppings, "7A" }, | 522 | pN_steppings, "7A" }, | |
523 | { CPU_ID_CORTEXA17R1, CPU_CLASS_CORTEX, "Cortex-A17 r1", | 523 | { CPU_ID_CORTEXA17R1, CPU_CLASS_CORTEX, "Cortex-A17 r1", | |
524 | pN_steppings, "7A" }, | 524 | pN_steppings, "7A" }, | |
525 | { CPU_ID_CORTEXA35R0, CPU_CLASS_CORTEX, "Cortex-A35 r0", | 525 | { CPU_ID_CORTEXA35R0, CPU_CLASS_CORTEX, "Cortex-A35 r0", | |
526 | pN_steppings, "8A" }, | 526 | pN_steppings, "8A" }, | |
527 | { CPU_ID_CORTEXA53R0, CPU_CLASS_CORTEX, "Cortex-A53 r0", | 527 | { CPU_ID_CORTEXA53R0, CPU_CLASS_CORTEX, "Cortex-A53 r0", | |
528 | pN_steppings, "8A" }, | 528 | pN_steppings, "8A" }, | |
529 | { CPU_ID_CORTEXA57R0, CPU_CLASS_CORTEX, "Cortex-A57 r0", | 529 | { CPU_ID_CORTEXA57R0, CPU_CLASS_CORTEX, "Cortex-A57 r0", | |
530 | pN_steppings, "8A" }, | 530 | pN_steppings, "8A" }, | |
531 | { CPU_ID_CORTEXA57R1, CPU_CLASS_CORTEX, "Cortex-A57 r1", | 531 | { CPU_ID_CORTEXA57R1, CPU_CLASS_CORTEX, "Cortex-A57 r1", | |
532 | pN_steppings, "8A" }, | 532 | pN_steppings, "8A" }, | |
533 | { CPU_ID_CORTEXA72R0, CPU_CLASS_CORTEX, "Cortex-A72 r0", | 533 | { CPU_ID_CORTEXA72R0, CPU_CLASS_CORTEX, "Cortex-A72 r0", | |
534 | pN_steppings, "8A" }, | 534 | pN_steppings, "8A" }, | |
535 | 535 | |||
536 | { CPU_ID_MV88SV581X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | 536 | { CPU_ID_MV88SV581X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | |
537 | generic_steppings }, | 537 | generic_steppings }, | |
538 | { CPU_ID_ARM_88SV581X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | 538 | { CPU_ID_ARM_88SV581X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | |
539 | generic_steppings }, | 539 | generic_steppings }, | |
540 | { CPU_ID_MV88SV581X_V7, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | 540 | { CPU_ID_MV88SV581X_V7, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | |
541 | generic_steppings }, | 541 | generic_steppings }, | |
542 | { CPU_ID_ARM_88SV581X_V7, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | 542 | { CPU_ID_ARM_88SV581X_V7, CPU_CLASS_PJ4B, "Sheeva 88SV581x", | |
543 | generic_steppings }, | 543 | generic_steppings }, | |
544 | { CPU_ID_MV88SV584X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV584x", | 544 | { CPU_ID_MV88SV584X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV584x", | |
545 | generic_steppings }, | 545 | generic_steppings }, | |
546 | { CPU_ID_ARM_88SV584X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV584x", | 546 | { CPU_ID_ARM_88SV584X_V6, CPU_CLASS_PJ4B, "Sheeva 88SV584x", | |
547 | generic_steppings }, | 547 | generic_steppings }, | |
548 | { CPU_ID_MV88SV584X_V7, CPU_CLASS_PJ4B, "Sheeva 88SV584x", | 548 | { CPU_ID_MV88SV584X_V7, CPU_CLASS_PJ4B, "Sheeva 88SV584x", | |
549 | generic_steppings }, | 549 | generic_steppings }, | |
550 | 550 | |||
551 | 551 | |||
552 | { 0, CPU_CLASS_NONE, NULL, NULL, "" } | 552 | { 0, CPU_CLASS_NONE, NULL, NULL, "" } | |
553 | }; | 553 | }; | |
554 | 554 | |||
555 | struct cpu_classtab { | 555 | struct cpu_classtab { | |
556 | const char *class_name; | 556 | const char *class_name; | |
557 | const char *class_option; | 557 | const char *class_option; | |
558 | }; | 558 | }; | |
559 | 559 | |||
560 | const struct cpu_classtab cpu_classes[] = { | 560 | const struct cpu_classtab cpu_classes[] = { | |
561 | [CPU_CLASS_NONE] = { "unknown", NULL }, | 561 | [CPU_CLASS_NONE] = { "unknown", NULL }, | |
562 | [CPU_CLASS_ARM2] = { "ARM2", "CPU_ARM2" }, | 562 | [CPU_CLASS_ARM2] = { "ARM2", "CPU_ARM2" }, | |
563 | [CPU_CLASS_ARM2AS] = { "ARM2as", "CPU_ARM250" }, | 563 | [CPU_CLASS_ARM2AS] = { "ARM2as", "CPU_ARM250" }, | |
564 | [CPU_CLASS_ARM3] = { "ARM3", "CPU_ARM3" }, | 564 | [CPU_CLASS_ARM3] = { "ARM3", "CPU_ARM3" }, | |
565 | [CPU_CLASS_ARM6] = { "ARM6", "CPU_ARM6" }, | 565 | [CPU_CLASS_ARM6] = { "ARM6", "CPU_ARM6" }, | |
566 | [CPU_CLASS_ARM7] = { "ARM7", "CPU_ARM7" }, | 566 | [CPU_CLASS_ARM7] = { "ARM7", "CPU_ARM7" }, | |
567 | [CPU_CLASS_ARM7TDMI] = { "ARM7TDMI", "CPU_ARM7TDMI" }, | 567 | [CPU_CLASS_ARM7TDMI] = { "ARM7TDMI", "CPU_ARM7TDMI" }, | |
568 | [CPU_CLASS_ARM8] = { "ARM8", "CPU_ARM8" }, | 568 | [CPU_CLASS_ARM8] = { "ARM8", "CPU_ARM8" }, | |
569 | [CPU_CLASS_ARM9TDMI] = { "ARM9TDMI", NULL }, | 569 | [CPU_CLASS_ARM9TDMI] = { "ARM9TDMI", NULL }, | |
570 | [CPU_CLASS_ARM9ES] = { "ARM9E-S", "CPU_ARM9E" }, | 570 | [CPU_CLASS_ARM9ES] = { "ARM9E-S", "CPU_ARM9E" }, | |
571 | [CPU_CLASS_ARM9EJS] = { "ARM9EJ-S", "CPU_ARM9E" }, | 571 | [CPU_CLASS_ARM9EJS] = { "ARM9EJ-S", "CPU_ARM9E" }, | |
572 | [CPU_CLASS_ARM10E] = { "ARM10E", "CPU_ARM10" }, | 572 | [CPU_CLASS_ARM10E] = { "ARM10E", "CPU_ARM10" }, | |
573 | [CPU_CLASS_ARM10EJ] = { "ARM10EJ", "CPU_ARM10" }, | 573 | [CPU_CLASS_ARM10EJ] = { "ARM10EJ", "CPU_ARM10" }, | |
574 | [CPU_CLASS_SA1] = { "SA-1", "CPU_SA110" }, | 574 | [CPU_CLASS_SA1] = { "SA-1", "CPU_SA110" }, | |
575 | [CPU_CLASS_XSCALE] = { "XScale", "CPU_XSCALE_..." }, | 575 | [CPU_CLASS_XSCALE] = { "XScale", "CPU_XSCALE_..." }, | |
576 | [CPU_CLASS_ARM11J] = { "ARM11J", "CPU_ARM11" }, | 576 | [CPU_CLASS_ARM11J] = { "ARM11J", "CPU_ARM11" }, | |
577 | [CPU_CLASS_ARMV4] = { "ARMv4", "CPU_ARMV4" }, | 577 | [CPU_CLASS_ARMV4] = { "ARMv4", "CPU_ARMV4" }, | |
578 | [CPU_CLASS_CORTEX] = { "Cortex", "CPU_CORTEX" }, | 578 | [CPU_CLASS_CORTEX] = { "Cortex", "CPU_CORTEX" }, | |
579 | [CPU_CLASS_PJ4B] = { "Marvell", "CPU_PJ4B" }, | 579 | [CPU_CLASS_PJ4B] = { "Marvell", "CPU_PJ4B" }, | |
580 | }; | 580 | }; | |
581 | 581 | |||
582 | /* | 582 | /* | |
583 | * Report the type of the specified arm processor. This uses the generic and | 583 | * Report the type of the specified arm processor. This uses the generic and | |
584 | * arm specific information in the CPU structure to identify the processor. | 584 | * arm specific information in the CPU structure to identify the processor. | |
585 | * The remaining fields in the CPU structure are filled in appropriately. | 585 | * The remaining fields in the CPU structure are filled in appropriately. | |
586 | */ | 586 | */ | |
587 | 587 | |||
588 | static const char * const wtnames[] = { | 588 | static const char * const wtnames[] = { | |
589 | "write-through", | 589 | "write-through", | |
590 | "write-back", | 590 | "write-back", | |
591 | "write-back", | 591 | "write-back", | |
592 | "**unknown 3**", | 592 | "**unknown 3**", | |
593 | "**unknown 4**", | 593 | "**unknown 4**", | |
594 | "write-back-locking", /* XXX XScale-specific? */ | 594 | "write-back-locking", /* XXX XScale-specific? */ | |
595 | "write-back-locking-A", | 595 | "write-back-locking-A", | |
596 | "write-back-locking-B", | 596 | "write-back-locking-B", | |
597 | "**unknown 8**", | 597 | "**unknown 8**", | |
598 | "**unknown 9**", | 598 | "**unknown 9**", | |
599 | "**unknown 10**", | 599 | "**unknown 10**", | |
600 | "**unknown 11**", | 600 | "**unknown 11**", | |
601 | "write-back", | 601 | "write-back", | |
602 | "write-back-locking-line", | 602 | "write-back-locking-line", | |
603 | "write-back-locking-C", | 603 | "write-back-locking-C", | |
604 | "write-back-locking-D", | 604 | "write-back-locking-D", | |
605 | }; | 605 | }; | |
606 | 606 | |||
607 | static void | 607 | static void | |
608 | print_cache_info(device_t dv, struct arm_cache_info *info, u_int level) | 608 | print_cache_info(device_t dv, struct arm_cache_info *info, u_int level) | |
609 | { | 609 | { | |
610 | if (info->cache_unified) { | 610 | if (info->cache_unified) { | |
611 | aprint_normal_dev(dv, "L%u %dKB/%dB %d-way (%u set) %s %cI%cT Unified cache\n", | 611 | aprint_normal_dev(dv, "L%u %dKB/%dB %d-way (%u set) %s %cI%cT Unified cache\n", | |
612 | level + 1, | 612 | level + 1, | |
613 | info->dcache_size / 1024, | 613 | info->dcache_size / 1024, | |
614 | info->dcache_line_size, info->dcache_ways, | 614 | info->dcache_line_size, info->dcache_ways, | |
615 | info->dcache_sets ? info->dcache_sets : | 615 | info->dcache_sets ? info->dcache_sets : | |
616 | info->dcache_size / | 616 | info->dcache_size / | |
617 | (info->dcache_line_size * info->dcache_ways), | 617 | (info->dcache_line_size * info->dcache_ways), | |
618 | wtnames[info->cache_type], | 618 | wtnames[info->cache_type], | |
619 | info->dcache_type & CACHE_TYPE_PIxx ? 'P' : 'V', | 619 | info->dcache_type & CACHE_TYPE_PIxx ? 'P' : 'V', | |
620 | info->dcache_type & CACHE_TYPE_xxPT ? 'P' : 'V'); | 620 | info->dcache_type & CACHE_TYPE_xxPT ? 'P' : 'V'); | |
621 | } else { | 621 | } else { | |
622 | aprint_normal_dev(dv, "L%u %dKB/%dB %d-way (%u set) %cI%cT Instruction cache\n", | 622 | aprint_normal_dev(dv, "L%u %dKB/%dB %d-way (%u set) %cI%cT Instruction cache\n", | |
623 | level + 1, | 623 | level + 1, | |
624 | info->icache_size / 1024, | 624 | info->icache_size / 1024, | |
625 | info->icache_line_size, info->icache_ways, | 625 | info->icache_line_size, info->icache_ways, | |
626 | info->icache_sets ? info->icache_sets : | 626 | info->icache_sets ? info->icache_sets : | |
627 | info->icache_size / | 627 | info->icache_size / | |
628 | (info->icache_line_size * info->icache_ways), | 628 | (info->icache_line_size * info->icache_ways), | |
629 | info->icache_type & CACHE_TYPE_PIxx ? 'P' : 'V', | 629 | info->icache_type & CACHE_TYPE_PIxx ? 'P' : 'V', | |
630 | info->icache_type & CACHE_TYPE_xxPT ? 'P' : 'V'); | 630 | info->icache_type & CACHE_TYPE_xxPT ? 'P' : 'V'); | |
631 | aprint_normal_dev(dv, "L%u %dKB/%dB %d-way (%u set) %s %cI%cT Data cache\n", | 631 | aprint_normal_dev(dv, "L%u %dKB/%dB %d-way (%u set) %s %cI%cT Data cache\n", | |
632 | level + 1, | 632 | level + 1, | |
633 | info->dcache_size / 1024, | 633 | info->dcache_size / 1024, | |
634 | info->dcache_line_size, info->dcache_ways, | 634 | info->dcache_line_size, info->dcache_ways, | |
635 | info->dcache_sets ? info->dcache_sets : | 635 | info->dcache_sets ? info->dcache_sets : | |
636 | info->dcache_size / | 636 | info->dcache_size / | |
637 | (info->dcache_line_size * info->dcache_ways), | 637 | (info->dcache_line_size * info->dcache_ways), | |
638 | wtnames[info->cache_type], | 638 | wtnames[info->cache_type], | |
639 | info->dcache_type & CACHE_TYPE_PIxx ? 'P' : 'V', | 639 | info->dcache_type & CACHE_TYPE_PIxx ? 'P' : 'V', | |
640 | info->dcache_type & CACHE_TYPE_xxPT ? 'P' : 'V'); | 640 | info->dcache_type & CACHE_TYPE_xxPT ? 'P' : 'V'); | |
641 | } | 641 | } | |
642 | } | 642 | } | |
643 | 643 | |||
644 | static enum cpu_class | 644 | static enum cpu_class | |
645 | identify_arm_model(uint32_t cpuid, char *buf, size_t len) | 645 | identify_arm_model(uint32_t cpuid, char *buf, size_t len) | |
646 | { | 646 | { | |
647 | enum cpu_class cpu_class = CPU_CLASS_NONE; | 647 | enum cpu_class cpu_class = CPU_CLASS_NONE; | |
648 | for (const struct cpuidtab *id = cpuids; id->cpuid != 0; id++) { | 648 | for (const struct cpuidtab *id = cpuids; id->cpuid != 0; id++) { | |
649 | if (id->cpuid == (cpuid & CPU_ID_CPU_MASK)) { | 649 | if (id->cpuid == (cpuid & CPU_ID_CPU_MASK)) { | |
650 | const char *steppingstr = | 650 | const char *steppingstr = | |
651 | id->cpu_steppings[cpuid & CPU_ID_REVISION_MASK]; | 651 | id->cpu_steppings[cpuid & CPU_ID_REVISION_MASK]; | |
652 | cpu_arch = id->cpu_arch; | 652 | cpu_arch = id->cpu_arch; | |
653 | cpu_class = id->cpu_class; | 653 | cpu_class = id->cpu_class; | |
654 | snprintf(buf, len, "%s%s%s (%s V%s core)", | 654 | snprintf(buf, len, "%s%s%s (%s V%s core)", | |
655 | id->cpu_classname, | 655 | id->cpu_classname, | |
656 | steppingstr[0] == '*' ? "" : " ", | 656 | steppingstr[0] == '*' ? "" : " ", | |
657 | &steppingstr[steppingstr[0] == '*'], | 657 | &steppingstr[steppingstr[0] == '*'], | |
658 | cpu_classes[cpu_class].class_name, | 658 | cpu_classes[cpu_class].class_name, | |
659 | cpu_arch); | 659 | cpu_arch); | |
660 | return cpu_class; | 660 | return cpu_class; | |
661 | } | 661 | } | |
662 | } | 662 | } | |
663 | 663 | |||
664 | snprintf(buf, len, "unknown CPU (ID = 0x%x)", cpuid); | 664 | snprintf(buf, len, "unknown CPU (ID = 0x%x)", cpuid); | |
665 | return cpu_class; | 665 | return cpu_class; | |
666 | } | 666 | } | |
667 | 667 | |||
668 | void | 668 | void | |
669 | identify_arm_cpu(device_t dv, struct cpu_info *ci) | 669 | identify_arm_cpu(device_t dv, struct cpu_info *ci) | |
670 | { | 670 | { | |
671 | const uint32_t arm_cpuid = ci->ci_arm_cpuid; | 671 | const uint32_t arm_cpuid = ci->ci_arm_cpuid; | |
672 | const char * const xname = device_xname(dv); | 672 | const char * const xname = device_xname(dv); | |
673 | char model[128]; | 673 | char model[128]; | |
674 | const char *m; | 674 | const char *m; | |
675 | 675 | |||
676 | if (arm_cpuid == 0) { | 676 | if (arm_cpuid == 0) { | |
677 | aprint_error("Processor failed probe - no CPU ID\n"); | 677 | aprint_error("Processor failed probe - no CPU ID\n"); | |
678 | return; | 678 | return; | |
679 | } | 679 | } | |
680 | 680 | |||
681 | const enum cpu_class cpu_class = identify_arm_model(arm_cpuid, | 681 | const enum cpu_class cpu_class = identify_arm_model(arm_cpuid, | |
682 | model, sizeof(model)); | 682 | model, sizeof(model)); | |
683 | if (ci->ci_cpuid == 0) { | 683 | if (ci->ci_cpuid == 0) { | |
684 | m = cpu_getmodel(); | 684 | m = cpu_getmodel(); | |
685 | if (m == NULL || *m == 0) | 685 | if (m == NULL || *m == 0) | |
686 | cpu_setmodel("%s", model); | 686 | cpu_setmodel("%s", model); | |
687 | } | 687 | } | |
688 | 688 | |||
689 | if (ci->ci_data.cpu_cc_freq != 0) { | 689 | if (ci->ci_data.cpu_cc_freq != 0) { | |
690 | char freqbuf[10]; | 690 | char freqbuf[10]; | |
691 | humanize_number(freqbuf, sizeof(freqbuf), ci->ci_data.cpu_cc_freq, | 691 | humanize_number(freqbuf, sizeof(freqbuf), ci->ci_data.cpu_cc_freq, | |
692 | "Hz", 1000); | 692 | "Hz", 1000); | |
693 | 693 | |||
694 | aprint_naive(": %s %s\n", freqbuf, model); | 694 | aprint_naive(": %s %s\n", freqbuf, model); | |
695 | aprint_normal(": %s %s\n", freqbuf, model); | 695 | aprint_normal(": %s %s\n", freqbuf, model); | |
696 | } else { | 696 | } else { | |
697 | aprint_naive(": %s\n", model); | 697 | aprint_naive(": %s\n", model); | |
698 | aprint_normal(": %s\n", model); | 698 | aprint_normal(": %s\n", model); | |
699 | } | 699 | } | |
700 | 700 | |||
701 | aprint_debug_dev(dv, "midr: %#x\n", arm_cpuid); | 701 | aprint_debug_dev(dv, "midr: %#x\n", arm_cpuid); | |
702 | 702 | |||
703 | aprint_normal("%s:", xname); | 703 | aprint_normal("%s:", xname); | |
704 | 704 | |||
705 | switch (cpu_class) { | 705 | switch (cpu_class) { | |
706 | case CPU_CLASS_ARM6: | 706 | case CPU_CLASS_ARM6: | |
707 | case CPU_CLASS_ARM7: | 707 | case CPU_CLASS_ARM7: | |
708 | case CPU_CLASS_ARM7TDMI: | 708 | case CPU_CLASS_ARM7TDMI: | |
709 | case CPU_CLASS_ARM8: | 709 | case CPU_CLASS_ARM8: | |
710 | if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0) | 710 | if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0) | |
711 | aprint_normal(" IDC disabled"); | 711 | aprint_normal(" IDC disabled"); | |
712 | else | 712 | else | |
713 | aprint_normal(" IDC enabled"); | 713 | aprint_normal(" IDC enabled"); | |
714 | break; | 714 | break; | |
715 | case CPU_CLASS_ARM9TDMI: | 715 | case CPU_CLASS_ARM9TDMI: | |
716 | case CPU_CLASS_ARM9ES: | 716 | case CPU_CLASS_ARM9ES: | |
717 | case CPU_CLASS_ARM9EJS: | 717 | case CPU_CLASS_ARM9EJS: | |
718 | case CPU_CLASS_ARM10E: | 718 | case CPU_CLASS_ARM10E: | |
719 | case CPU_CLASS_ARM10EJ: | 719 | case CPU_CLASS_ARM10EJ: | |
720 | case CPU_CLASS_SA1: | 720 | case CPU_CLASS_SA1: | |
721 | case CPU_CLASS_XSCALE: | 721 | case CPU_CLASS_XSCALE: | |
722 | case CPU_CLASS_ARM11J: | 722 | case CPU_CLASS_ARM11J: | |
723 | case CPU_CLASS_ARMV4: | 723 | case CPU_CLASS_ARMV4: | |
724 | case CPU_CLASS_CORTEX: | 724 | case CPU_CLASS_CORTEX: | |
725 | case CPU_CLASS_PJ4B: | 725 | case CPU_CLASS_PJ4B: | |
726 | if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0) | 726 | if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0) | |
727 | aprint_normal(" DC disabled"); | 727 | aprint_normal(" DC disabled"); | |
728 | else | 728 | else | |
729 | aprint_normal(" DC enabled"); | 729 | aprint_normal(" DC enabled"); | |
730 | if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0) | 730 | if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0) | |
731 | aprint_normal(" IC disabled"); | 731 | aprint_normal(" IC disabled"); | |
732 | else | 732 | else | |
733 | aprint_normal(" IC enabled"); | 733 | aprint_normal(" IC enabled"); | |
734 | break; | 734 | break; | |
735 | default: | 735 | default: | |
736 | break; | 736 | break; | |
737 | } | 737 | } | |
738 | if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0) | 738 | if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0) | |
739 | aprint_normal(" WB disabled"); | 739 | aprint_normal(" WB disabled"); | |
740 | else | 740 | else | |
741 | aprint_normal(" WB enabled"); | 741 | aprint_normal(" WB enabled"); | |
742 | 742 | |||
743 | if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE) | 743 | if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE) | |
744 | aprint_normal(" LABT"); | 744 | aprint_normal(" LABT"); | |
745 | else | 745 | else | |
746 | aprint_normal(" EABT"); | 746 | aprint_normal(" EABT"); | |
747 | 747 | |||
748 | if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE) | 748 | if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE) | |
749 | aprint_normal(" branch prediction enabled"); | 749 | aprint_normal(" branch prediction enabled"); | |
750 | 750 | |||
751 | aprint_normal("\n"); | 751 | aprint_normal("\n"); | |
752 | 752 | |||
753 | if (CPU_ID_CORTEX_P(arm_cpuid) || | 753 | if (CPU_ID_CORTEX_P(arm_cpuid) || | |
754 | CPU_ID_ARM11_P(arm_cpuid) || | 754 | CPU_ID_ARM11_P(arm_cpuid) || | |
755 | CPU_ID_MV88SV58XX_P(arm_cpuid)) { | 755 | CPU_ID_MV88SV58XX_P(arm_cpuid)) { | |
756 | if ((arm_cpuid & CPU_ID_CPU_MASK) != CPU_ID_ARM1136JS && | 756 | if ((arm_cpuid & CPU_ID_CPU_MASK) != CPU_ID_ARM1136JS && | |
757 | (arm_cpuid & CPU_ID_CPU_MASK) != CPU_ID_ARM1176JZS) { | 757 | (arm_cpuid & CPU_ID_CPU_MASK) != CPU_ID_ARM1176JZS) { | |
758 | identify_features(dv, ci); | 758 | identify_features(dv, ci); | |
759 | } | 759 | } | |
760 | } | 760 | } | |
761 | 761 | |||
762 | /* Print cache info. */ | 762 | /* Print cache info. */ | |
763 | if (arm_pcache.icache_line_size != 0 || arm_pcache.dcache_line_size != 0) { | 763 | if (arm_pcache.icache_line_size != 0 || arm_pcache.dcache_line_size != 0) { | |
764 | print_cache_info(dv, &arm_pcache, 0); | 764 | print_cache_info(dv, &arm_pcache, 0); | |
765 | } | 765 | } | |
766 | if (arm_scache.icache_line_size != 0 || arm_scache.dcache_line_size != 0) { | 766 | if (arm_scache.icache_line_size != 0 || arm_scache.dcache_line_size != 0) { | |
767 | print_cache_info(dv, &arm_scache, 1); | 767 | print_cache_info(dv, &arm_scache, 1); | |
768 | } | 768 | } | |
769 | 769 | |||
770 | 770 | |||
771 | switch (cpu_class) { | 771 | switch (cpu_class) { | |
772 | #ifdef CPU_ARM6 | 772 | #ifdef CPU_ARM6 | |
773 | case CPU_CLASS_ARM6: | 773 | case CPU_CLASS_ARM6: | |
774 | #endif | 774 | #endif | |
775 | #ifdef CPU_ARM7 | 775 | #ifdef CPU_ARM7 | |
776 | case CPU_CLASS_ARM7: | 776 | case CPU_CLASS_ARM7: | |
777 | #endif | 777 | #endif | |
778 | #ifdef CPU_ARM7TDMI | 778 | #ifdef CPU_ARM7TDMI | |
779 | case CPU_CLASS_ARM7TDMI: | 779 | case CPU_CLASS_ARM7TDMI: | |
780 | #endif | 780 | #endif | |
781 | #ifdef CPU_ARM8 | 781 | #ifdef CPU_ARM8 | |
782 | case CPU_CLASS_ARM8: | 782 | case CPU_CLASS_ARM8: | |
783 | #endif | 783 | #endif | |
784 | #ifdef CPU_ARM9 | 784 | #ifdef CPU_ARM9 | |
785 | case CPU_CLASS_ARM9TDMI: | 785 | case CPU_CLASS_ARM9TDMI: | |
786 | #endif | 786 | #endif | |
787 | #if defined(CPU_ARM9E) || defined(CPU_SHEEVA) | 787 | #if defined(CPU_ARM9E) || defined(CPU_SHEEVA) | |
788 | case CPU_CLASS_ARM9ES: | 788 | case CPU_CLASS_ARM9ES: | |
789 | case CPU_CLASS_ARM9EJS: | 789 | case CPU_CLASS_ARM9EJS: | |
790 | #endif | 790 | #endif | |
791 | #ifdef CPU_ARM10 | 791 | #ifdef CPU_ARM10 | |
792 | case CPU_CLASS_ARM10E: | 792 | case CPU_CLASS_ARM10E: | |
793 | case CPU_CLASS_ARM10EJ: | 793 | case CPU_CLASS_ARM10EJ: | |
794 | #endif | 794 | #endif | |
795 | #if defined(CPU_SA110) || defined(CPU_SA1100) || \ | 795 | #if defined(CPU_SA110) || defined(CPU_SA1100) || \ | |
796 | defined(CPU_SA1110) || defined(CPU_IXP12X0) | 796 | defined(CPU_SA1110) || defined(CPU_IXP12X0) | |
797 | case CPU_CLASS_SA1: | 797 | case CPU_CLASS_SA1: | |
798 | #endif | 798 | #endif | |
799 | #if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \ | 799 | #if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \ | |
800 | defined(__CPU_XSCALE_PXA2XX) || defined(CPU_XSCALE_IXP425) | 800 | defined(__CPU_XSCALE_PXA2XX) || defined(CPU_XSCALE_IXP425) | |
801 | case CPU_CLASS_XSCALE: | 801 | case CPU_CLASS_XSCALE: | |
802 | #endif | 802 | #endif | |
803 | #if defined(CPU_ARM11) | 803 | #if defined(CPU_ARM11) | |
804 | case CPU_CLASS_ARM11J: | 804 | case CPU_CLASS_ARM11J: | |
805 | #endif | 805 | #endif | |
806 | #if defined(CPU_CORTEX) | 806 | #if defined(CPU_CORTEX) | |
807 | case CPU_CLASS_CORTEX: | 807 | case CPU_CLASS_CORTEX: | |
808 | #endif | 808 | #endif | |
809 | #if defined(CPU_PJ4B) | 809 | #if defined(CPU_PJ4B) | |
810 | case CPU_CLASS_PJ4B: | 810 | case CPU_CLASS_PJ4B: | |
811 | #endif | 811 | #endif | |
812 | #if defined(CPU_FA526) | 812 | #if defined(CPU_FA526) | |
813 | case CPU_CLASS_ARMV4: | 813 | case CPU_CLASS_ARMV4: | |
814 | #endif | 814 | #endif | |
815 | break; | 815 | break; | |
816 | default: | 816 | default: | |
817 | if (cpu_classes[cpu_class].class_option == NULL) { | 817 | if (cpu_classes[cpu_class].class_option == NULL) { | |
818 | aprint_error_dev(dv, "%s does not fully support this CPU.\n", | 818 | aprint_error_dev(dv, "%s does not fully support this CPU.\n", | |
819 | ostype); | 819 | ostype); | |
820 | } else { | 820 | } else { | |
821 | aprint_error_dev(dv, "This kernel does not fully support " | 821 | aprint_error_dev(dv, "This kernel does not fully support " | |
822 | "this CPU.\n"); | 822 | "this CPU.\n"); | |
823 | aprint_normal_dev(dv, "Recompile with \"options %s\" to " | 823 | aprint_normal_dev(dv, "Recompile with \"options %s\" to " | |
824 | "correct this.\n", cpu_classes[cpu_class].class_option); | 824 | "correct this.\n", cpu_classes[cpu_class].class_option); | |
825 | } | 825 | } | |
826 | break; | 826 | break; | |
827 | } | 827 | } | |
828 | } | 828 | } | |
829 | 829 | |||
830 | extern int cpu_instruction_set_attributes[6]; | 830 | extern int cpu_instruction_set_attributes[6]; | |
831 | extern int cpu_memory_model_features[4]; | 831 | extern int cpu_memory_model_features[4]; | |
832 | extern int cpu_processor_features[2]; | 832 | extern int cpu_processor_features[2]; | |
833 | extern int cpu_simd_present; | 833 | extern int cpu_simd_present; | |
834 | extern int cpu_simdex_present; | 834 | extern int cpu_simdex_present; | |
835 | 835 | |||
836 | void | 836 | void | |
837 | identify_features(device_t dv, struct cpu_info *ci) | 837 | identify_features(device_t dv, struct cpu_info *ci) | |
838 | { | 838 | { | |
839 | const int unit = device_unit(dv); | 839 | const int unit = device_unit(dv); | |
840 | 840 | |||
841 | aprint_debug_dev(dv, "sctlr: %#x\n", ci->ci_ctrl); | 841 | aprint_debug_dev(dv, "sctlr: %#x\n", ci->ci_ctrl); | |
842 | aprint_debug_dev(dv, "actlr: %#x\n", ci->ci_actlr); | 842 | aprint_debug_dev(dv, "actlr: %#x\n", ci->ci_actlr); | |
843 | aprint_debug_dev(dv, "revidr: %#x\n", ci->ci_revidr); | 843 | aprint_debug_dev(dv, "revidr: %#x\n", ci->ci_revidr); | |
844 | #ifdef MULTIPROCESSOR | 844 | #ifdef MULTIPROCESSOR | |
845 | aprint_debug_dev(dv, "mpidr: %#x\n", ci->ci_mpidr); | 845 | aprint_debug_dev(dv, "mpidr: %#x\n", ci->ci_mpidr); | |
846 | #endif | 846 | #endif | |
847 | 847 | |||
848 | if (unit != 0) | 848 | if (unit != 0) | |
849 | return; | 849 | return; | |
850 | 850 | |||
851 | cpu_instruction_set_attributes[0] = armreg_isar0_read(); | 851 | cpu_instruction_set_attributes[0] = armreg_isar0_read(); | |
852 | cpu_instruction_set_attributes[1] = armreg_isar1_read(); | 852 | cpu_instruction_set_attributes[1] = armreg_isar1_read(); | |
853 | cpu_instruction_set_attributes[2] = armreg_isar2_read(); | 853 | cpu_instruction_set_attributes[2] = armreg_isar2_read(); | |
854 | cpu_instruction_set_attributes[3] = armreg_isar3_read(); | 854 | cpu_instruction_set_attributes[3] = armreg_isar3_read(); | |
855 | cpu_instruction_set_attributes[4] = armreg_isar4_read(); | 855 | cpu_instruction_set_attributes[4] = armreg_isar4_read(); | |
856 | cpu_instruction_set_attributes[5] = armreg_isar5_read(); | 856 | cpu_instruction_set_attributes[5] = armreg_isar5_read(); | |
857 | 857 | |||
858 | cpu_hwdiv_present = | 858 | cpu_hwdiv_present = | |
859 | ((cpu_instruction_set_attributes[0] >> 24) & 0x0f) >= 2; | 859 | ((cpu_instruction_set_attributes[0] >> 24) & 0x0f) >= 2; | |
860 | cpu_simd_present = | 860 | cpu_simd_present = | |
861 | ((cpu_instruction_set_attributes[3] >> 4) & 0x0f) >= 3; | 861 | ((cpu_instruction_set_attributes[3] >> 4) & 0x0f) >= 3; | |
862 | cpu_simdex_present = cpu_simd_present | 862 | cpu_simdex_present = cpu_simd_present | |
863 | && ((cpu_instruction_set_attributes[1] >> 12) & 0x0f) >= 2; | 863 | && ((cpu_instruction_set_attributes[1] >> 12) & 0x0f) >= 2; | |
864 | cpu_synchprim_present = | 864 | cpu_synchprim_present = | |
865 | ((cpu_instruction_set_attributes[3] >> 8) & 0xf0) | 865 | ((cpu_instruction_set_attributes[3] >> 8) & 0xf0) | |
866 | | ((cpu_instruction_set_attributes[4] >> 20) & 0x0f); | 866 | | ((cpu_instruction_set_attributes[4] >> 20) & 0x0f); | |
867 | 867 | |||
868 | cpu_memory_model_features[0] = armreg_mmfr0_read(); | 868 | cpu_memory_model_features[0] = armreg_mmfr0_read(); | |
869 | cpu_memory_model_features[1] = armreg_mmfr1_read(); | 869 | cpu_memory_model_features[1] = armreg_mmfr1_read(); | |
870 | cpu_memory_model_features[2] = armreg_mmfr2_read(); | 870 | cpu_memory_model_features[2] = armreg_mmfr2_read(); | |
871 | cpu_memory_model_features[3] = armreg_mmfr3_read(); | 871 | cpu_memory_model_features[3] = armreg_mmfr3_read(); | |
872 | 872 | |||
873 | #if 0 | 873 | #if 0 | |
874 | if (__SHIFTOUT(cpu_memory_model_features[3], __BITS(23,20))) { | 874 | if (__SHIFTOUT(cpu_memory_model_features[3], __BITS(23,20))) { | |
875 | /* | 875 | /* | |
876 | * Updates to the translation tables do not require a clean | 876 | * Updates to the translation tables do not require a clean | |
877 | * to the point of unification to ensure visibility by | 877 | * to the point of unification to ensure visibility by | |
878 | * subsequent translation table walks. | 878 | * subsequent translation table walks. | |
879 | */ | 879 | */ | |
880 | pmap_needs_pte_sync = 0; | 880 | pmap_needs_pte_sync = 0; | |
881 | } | 881 | } | |
882 | #endif | 882 | #endif | |
883 | 883 | |||
884 | cpu_processor_features[0] = armreg_pfr0_read(); | 884 | cpu_processor_features[0] = armreg_pfr0_read(); | |
885 | cpu_processor_features[1] = armreg_pfr1_read(); | 885 | cpu_processor_features[1] = armreg_pfr1_read(); | |
886 | 886 | |||
887 | aprint_debug_dev(dv, | 887 | aprint_debug_dev(dv, | |
888 | "isar: [0]=%#x [1]=%#x [2]=%#x [3]=%#x, [4]=%#x, [5]=%#x\n", | 888 | "isar: [0]=%#x [1]=%#x [2]=%#x [3]=%#x, [4]=%#x, [5]=%#x\n", | |
889 | cpu_instruction_set_attributes[0], | 889 | cpu_instruction_set_attributes[0], | |
890 | cpu_instruction_set_attributes[1], | 890 | cpu_instruction_set_attributes[1], | |
891 | cpu_instruction_set_attributes[2], | 891 | cpu_instruction_set_attributes[2], | |
892 | cpu_instruction_set_attributes[3], | 892 | cpu_instruction_set_attributes[3], | |
893 | cpu_instruction_set_attributes[4], | 893 | cpu_instruction_set_attributes[4], | |
894 | cpu_instruction_set_attributes[5]); | 894 | cpu_instruction_set_attributes[5]); | |
895 | aprint_debug_dev(dv, | 895 | aprint_debug_dev(dv, | |
896 | "mmfr: [0]=%#x [1]=%#x [2]=%#x [3]=%#x\n", | 896 | "mmfr: [0]=%#x [1]=%#x [2]=%#x [3]=%#x\n", | |
897 | cpu_memory_model_features[0], cpu_memory_model_features[1], | 897 | cpu_memory_model_features[0], cpu_memory_model_features[1], | |
898 | cpu_memory_model_features[2], cpu_memory_model_features[3]); | 898 | cpu_memory_model_features[2], cpu_memory_model_features[3]); | |
899 | aprint_debug_dev(dv, | 899 | aprint_debug_dev(dv, | |
900 | "pfr: [0]=%#x [1]=%#x\n", | 900 | "pfr: [0]=%#x [1]=%#x\n", | |
901 | cpu_processor_features[0], cpu_processor_features[1]); | 901 | cpu_processor_features[0], cpu_processor_features[1]); | |
902 | } | 902 | } | |
903 | 903 | |||
904 | #ifdef _ARM_ARCH_6 | 904 | #ifdef _ARM_ARCH_6 | |
905 | int | 905 | int | |
906 | cpu_maxproc_hook(int nmaxproc) | 906 | cpu_maxproc_hook(int nmaxproc) | |
907 | { | 907 | { | |
908 | 908 | |||
909 | #ifdef ARM_MMU_EXTENDED | 909 | #ifdef ARM_MMU_EXTENDED | |
910 | return pmap_maxproc_set(nmaxproc); | 910 | return pmap_maxproc_set(nmaxproc); | |
911 | #else | 911 | #else | |
912 | return 0; | 912 | return 0; | |
913 | #endif | 913 | #endif | |
914 | } | 914 | } | |
915 | #endif | 915 | #endif |
--- src/sys/arch/arm/fdt/cpu_fdt.c 2021/08/30 23:16:17 1.41
+++ src/sys/arch/arm/fdt/cpu_fdt.c 2022/03/03 06:26:05 1.42
@@ -1,387 +1,378 @@ | @@ -1,387 +1,378 @@ | |||
1 | /* $NetBSD: cpu_fdt.c,v 1.41 2021/08/30 23:16:17 jmcneill Exp $ */ | 1 | /* $NetBSD: cpu_fdt.c,v 1.42 2022/03/03 06:26:05 riastradh Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include "opt_multiprocessor.h" | 29 | #include "opt_multiprocessor.h" | |
30 | #include "psci_fdt.h" | 30 | #include "psci_fdt.h" | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | __KERNEL_RCSID(0, "$NetBSD: cpu_fdt.c,v 1.41 2021/08/30 23:16:17 jmcneill Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: cpu_fdt.c,v 1.42 2022/03/03 06:26:05 riastradh Exp $"); | |
34 | 34 | |||
35 | #include <sys/param.h> | 35 | #include <sys/param.h> | |
36 | #include <sys/atomic.h> | 36 | #include <sys/atomic.h> | |
37 | #include <sys/bus.h> | 37 | #include <sys/bus.h> | |
38 | #include <sys/device.h> | 38 | #include <sys/device.h> | |
39 | #include <sys/lwp.h> | 39 | #include <sys/lwp.h> | |
40 | #include <sys/systm.h> | 40 | #include <sys/systm.h> | |
41 | #include <sys/kernel.h> | 41 | #include <sys/kernel.h> | |
42 | 42 | |||
43 | #include <dev/fdt/fdtvar.h> | 43 | #include <dev/fdt/fdtvar.h> | |
44 | 44 | |||
45 | #include <arm/armreg.h> | 45 | #include <arm/armreg.h> | |
46 | #include <arm/cpu.h> | 46 | #include <arm/cpu.h> | |
47 | #include <arm/cpufunc.h> | 47 | #include <arm/cpufunc.h> | |
48 | #include <arm/cpuvar.h> | 48 | #include <arm/cpuvar.h> | |
49 | #include <arm/locore.h> | 49 | #include <arm/locore.h> | |
50 | 50 | |||
51 | #include <arm/arm/psci.h> | 51 | #include <arm/arm/psci.h> | |
52 | #include <arm/fdt/arm_fdtvar.h> | 52 | #include <arm/fdt/arm_fdtvar.h> | |
53 | #include <arm/fdt/psci_fdtvar.h> | 53 | #include <arm/fdt/psci_fdtvar.h> | |
54 | 54 | |||
55 | #include <uvm/uvm_extern.h> | 55 | #include <uvm/uvm_extern.h> | |
56 | 56 | |||
57 | static int cpu_fdt_match(device_t, cfdata_t, void *); | 57 | static int cpu_fdt_match(device_t, cfdata_t, void *); | |
58 | static void cpu_fdt_attach(device_t, device_t, void *); | 58 | static void cpu_fdt_attach(device_t, device_t, void *); | |
59 | 59 | |||
60 | struct cpu_fdt_softc { | 60 | CFATTACH_DECL_NEW(cpu_fdt, 0, | |
61 | device_t sc_dev; | |||
62 | int sc_phandle; | |||
63 | }; | |||
64 | ||||
65 | CFATTACH_DECL_NEW(cpu_fdt, sizeof(struct cpu_fdt_softc), | |||
66 | cpu_fdt_match, cpu_fdt_attach, NULL, NULL); | 61 | cpu_fdt_match, cpu_fdt_attach, NULL, NULL); | |
67 | 62 | |||
68 | static int | 63 | static int | |
69 | cpu_fdt_match(device_t parent, cfdata_t cf, void *aux) | 64 | cpu_fdt_match(device_t parent, cfdata_t cf, void *aux) | |
70 | { | 65 | { | |
71 | struct fdt_attach_args * const faa = aux; | 66 | struct fdt_attach_args * const faa = aux; | |
72 | const int phandle = faa->faa_phandle; | 67 | const int phandle = faa->faa_phandle; | |
73 | const char *device_type; | 68 | const char *device_type; | |
74 | 69 | |||
75 | device_type = fdtbus_get_string(phandle, "device_type"); | 70 | device_type = fdtbus_get_string(phandle, "device_type"); | |
76 | 71 | |||
77 | return device_type != NULL && strcmp(device_type, "cpu") == 0; | 72 | return device_type != NULL && strcmp(device_type, "cpu") == 0; | |
78 | } | 73 | } | |
79 | 74 | |||
80 | static void | 75 | static void | |
81 | cpu_fdt_attach(device_t parent, device_t self, void *aux) | 76 | cpu_fdt_attach(device_t parent, device_t self, void *aux) | |
82 | { | 77 | { | |
83 | struct cpu_fdt_softc * const sc = device_private(self); | |||
84 | struct fdt_attach_args * const faa = aux; | 78 | struct fdt_attach_args * const faa = aux; | |
85 | const int phandle = faa->faa_phandle; | 79 | const int phandle = faa->faa_phandle; | |
86 | bus_addr_t cpuid; | 80 | bus_addr_t cpuid; | |
87 | const uint32_t *cap_ptr; | 81 | const uint32_t *cap_ptr; | |
88 | int len; | 82 | int len; | |
89 | 83 | |||
90 | sc->sc_dev = self; | |||
91 | sc->sc_phandle = phandle; | |||
92 | ||||
93 | cap_ptr = fdtbus_get_prop(phandle, "capacity-dmips-mhz", &len); | 84 | cap_ptr = fdtbus_get_prop(phandle, "capacity-dmips-mhz", &len); | |
94 | if (cap_ptr && len == 4) { | 85 | if (cap_ptr && len == 4) { | |
95 | prop_dictionary_t dict = device_properties(self); | 86 | prop_dictionary_t dict = device_properties(self); | |
96 | uint32_t capacity_dmips_mhz = be32toh(*cap_ptr); | 87 | uint32_t capacity_dmips_mhz = be32toh(*cap_ptr); | |
97 | 88 | |||
98 | prop_dictionary_set_uint32(dict, "capacity_dmips_mhz", | 89 | prop_dictionary_set_uint32(dict, "capacity_dmips_mhz", | |
99 | capacity_dmips_mhz); | 90 | capacity_dmips_mhz); | |
100 | } | 91 | } | |
101 | 92 | |||
102 | if (fdtbus_get_reg(phandle, 0, &cpuid, NULL) != 0) | 93 | if (fdtbus_get_reg(phandle, 0, &cpuid, NULL) != 0) | |
103 | cpuid = 0; | 94 | cpuid = 0; | |
104 | 95 | |||
105 | /* Attach the CPU */ | 96 | /* Attach the CPU */ | |
106 | cpu_attach(self, cpuid); | 97 | cpu_attach(self, cpuid); | |
107 | 98 | |||
108 | /* Attach CPU frequency scaling provider */ | 99 | /* Attach CPU frequency scaling provider */ | |
109 | config_found(self, faa, NULL, CFARGS_NONE); | 100 | config_found(self, faa, NULL, CFARGS_NONE); | |
110 | } | 101 | } | |
111 | 102 | |||
112 | #if defined(MULTIPROCESSOR) && (NPSCI_FDT > 0 || defined(__aarch64__)) | 103 | #if defined(MULTIPROCESSOR) && (NPSCI_FDT > 0 || defined(__aarch64__)) | |
113 | static register_t | 104 | static register_t | |
114 | cpu_fdt_mpstart_pa(void) | 105 | cpu_fdt_mpstart_pa(void) | |
115 | { | 106 | { | |
116 | bool ok __diagused; | 107 | bool ok __diagused; | |
117 | paddr_t pa; | 108 | paddr_t pa; | |
118 | 109 | |||
119 | ok = pmap_extract(pmap_kernel(), (vaddr_t)cpu_mpstart, &pa); | 110 | ok = pmap_extract(pmap_kernel(), (vaddr_t)cpu_mpstart, &pa); | |
120 | KASSERT(ok); | 111 | KASSERT(ok); | |
121 | 112 | |||
122 | return pa; | 113 | return pa; | |
123 | } | 114 | } | |
124 | #endif | 115 | #endif | |
125 | 116 | |||
126 | #ifdef MULTIPROCESSOR | 117 | #ifdef MULTIPROCESSOR | |
127 | static bool | 118 | static bool | |
128 | arm_fdt_cpu_okay(const int child) | 119 | arm_fdt_cpu_okay(const int child) | |
129 | { | 120 | { | |
130 | const char *s; | 121 | const char *s; | |
131 | 122 | |||
132 | s = fdtbus_get_string(child, "device_type"); | 123 | s = fdtbus_get_string(child, "device_type"); | |
133 | if (!s || strcmp(s, "cpu") != 0) | 124 | if (!s || strcmp(s, "cpu") != 0) | |
134 | return false; | 125 | return false; | |
135 | 126 | |||
136 | s = fdtbus_get_string(child, "status"); | 127 | s = fdtbus_get_string(child, "status"); | |
137 | if (s) { | 128 | if (s) { | |
138 | if (strcmp(s, "okay") == 0) | 129 | if (strcmp(s, "okay") == 0) | |
139 | return false; | 130 | return false; | |
140 | if (strcmp(s, "disabled") == 0) | 131 | if (strcmp(s, "disabled") == 0) | |
141 | return of_hasprop(child, "enable-method"); | 132 | return of_hasprop(child, "enable-method"); | |
142 | return false; | 133 | return false; | |
143 | } else { | 134 | } else { | |
144 | return true; | 135 | return true; | |
145 | } | 136 | } | |
146 | } | 137 | } | |
147 | #endif /* MULTIPROCESSOR */ | 138 | #endif /* MULTIPROCESSOR */ | |
148 | 139 | |||
149 | void | 140 | void | |
150 | arm_fdt_cpu_bootstrap(void) | 141 | arm_fdt_cpu_bootstrap(void) | |
151 | { | 142 | { | |
152 | #ifdef MULTIPROCESSOR | 143 | #ifdef MULTIPROCESSOR | |
153 | uint64_t mpidr, bp_mpidr; | 144 | uint64_t mpidr, bp_mpidr; | |
154 | u_int cpuindex; | 145 | u_int cpuindex; | |
155 | int child; | 146 | int child; | |
156 | 147 | |||
157 | const int cpus = OF_finddevice("/cpus"); | 148 | const int cpus = OF_finddevice("/cpus"); | |
158 | if (cpus == -1) { | 149 | if (cpus == -1) { | |
159 | aprint_error("%s: no /cpus node found\n", __func__); | 150 | aprint_error("%s: no /cpus node found\n", __func__); | |
160 | arm_cpu_max = 1; | 151 | arm_cpu_max = 1; | |
161 | return; | 152 | return; | |
162 | } | 153 | } | |
163 | 154 | |||
164 | /* Count CPUs */ | 155 | /* Count CPUs */ | |
165 | arm_cpu_max = 0; | 156 | arm_cpu_max = 0; | |
166 | 157 | |||
167 | /* MPIDR affinity levels of boot processor. */ | 158 | /* MPIDR affinity levels of boot processor. */ | |
168 | bp_mpidr = cpu_mpidr_aff_read(); | 159 | bp_mpidr = cpu_mpidr_aff_read(); | |
169 | 160 | |||
170 | /* Add APs to cpu_mpidr array */ | 161 | /* Add APs to cpu_mpidr array */ | |
171 | cpuindex = 1; | 162 | cpuindex = 1; | |
172 | for (child = OF_child(cpus); child; child = OF_peer(child)) { | 163 | for (child = OF_child(cpus); child; child = OF_peer(child)) { | |
173 | if (!arm_fdt_cpu_okay(child)) | 164 | if (!arm_fdt_cpu_okay(child)) | |
174 | continue; | 165 | continue; | |
175 | 166 | |||
176 | arm_cpu_max++; | 167 | arm_cpu_max++; | |
177 | if (fdtbus_get_reg64(child, 0, &mpidr, NULL) != 0) | 168 | if (fdtbus_get_reg64(child, 0, &mpidr, NULL) != 0) | |
178 | continue; | 169 | continue; | |
179 | if (mpidr == bp_mpidr) | 170 | if (mpidr == bp_mpidr) | |
180 | continue; /* BP already started */ | 171 | continue; /* BP already started */ | |
181 | 172 | |||
182 | KASSERT(cpuindex < MAXCPUS); | 173 | KASSERT(cpuindex < MAXCPUS); | |
183 | cpu_mpidr[cpuindex] = mpidr; | 174 | cpu_mpidr[cpuindex] = mpidr; | |
184 | cpu_dcache_wb_range((vaddr_t)&cpu_mpidr[cpuindex], | 175 | cpu_dcache_wb_range((vaddr_t)&cpu_mpidr[cpuindex], | |
185 | sizeof(cpu_mpidr[cpuindex])); | 176 | sizeof(cpu_mpidr[cpuindex])); | |
186 | 177 | |||
187 | cpuindex++; | 178 | cpuindex++; | |
188 | } | 179 | } | |
189 | #endif | 180 | #endif | |
190 | } | 181 | } | |
191 | 182 | |||
192 | #ifdef MULTIPROCESSOR | 183 | #ifdef MULTIPROCESSOR | |
193 | static struct arm_cpu_method * | 184 | static struct arm_cpu_method * | |
194 | arm_fdt_cpu_enable_method_byname(const char *method) | 185 | arm_fdt_cpu_enable_method_byname(const char *method) | |
195 | { | 186 | { | |
196 | __link_set_decl(arm_cpu_methods, struct arm_cpu_method); | 187 | __link_set_decl(arm_cpu_methods, struct arm_cpu_method); | |
197 | struct arm_cpu_method * const *acmp; | 188 | struct arm_cpu_method * const *acmp; | |
198 | 189 | |||
199 | __link_set_foreach(acmp, arm_cpu_methods) { | 190 | __link_set_foreach(acmp, arm_cpu_methods) { | |
200 | if (strcmp(method, (*acmp)->acm_compat) == 0) | 191 | if (strcmp(method, (*acmp)->acm_compat) == 0) | |
201 | return *acmp; | 192 | return *acmp; | |
202 | } | 193 | } | |
203 | 194 | |||
204 | return NULL; | 195 | return NULL; | |
205 | } | 196 | } | |
206 | 197 | |||
207 | static struct arm_cpu_method * | 198 | static struct arm_cpu_method * | |
208 | arm_fdt_cpu_enable_method(int phandle) | 199 | arm_fdt_cpu_enable_method(int phandle) | |
209 | { | 200 | { | |
210 | const char *method; | 201 | const char *method; | |
211 | 202 | |||
212 | method = fdtbus_get_string(phandle, "enable-method"); | 203 | method = fdtbus_get_string(phandle, "enable-method"); | |
213 | if (method == NULL) | 204 | if (method == NULL) | |
214 | return NULL; | 205 | return NULL; | |
215 | 206 | |||
216 | return arm_fdt_cpu_enable_method_byname(method); | 207 | return arm_fdt_cpu_enable_method_byname(method); | |
217 | } | 208 | } | |
218 | 209 | |||
219 | static int | 210 | static int | |
220 | arm_fdt_cpu_enable(int phandle, struct arm_cpu_method *acm) | 211 | arm_fdt_cpu_enable(int phandle, struct arm_cpu_method *acm) | |
221 | { | 212 | { | |
222 | return acm->acm_enable(phandle); | 213 | return acm->acm_enable(phandle); | |
223 | } | 214 | } | |
224 | #endif | 215 | #endif | |
225 | 216 | |||
226 | int | 217 | int | |
227 | arm_fdt_cpu_mpstart(void) | 218 | arm_fdt_cpu_mpstart(void) | |
228 | { | 219 | { | |
229 | int ret = 0; | 220 | int ret = 0; | |
230 | #ifdef MULTIPROCESSOR | 221 | #ifdef MULTIPROCESSOR | |
231 | uint64_t mpidr, bp_mpidr; | 222 | uint64_t mpidr, bp_mpidr; | |
232 | u_int cpuindex, i; | 223 | u_int cpuindex, i; | |
233 | int child, error; | 224 | int child, error; | |
234 | struct arm_cpu_method *acm; | 225 | struct arm_cpu_method *acm; | |
235 | 226 | |||
236 | const int cpus = OF_finddevice("/cpus"); | 227 | const int cpus = OF_finddevice("/cpus"); | |
237 | if (cpus == -1) { | 228 | if (cpus == -1) { | |
238 | aprint_error("%s: no /cpus node found\n", __func__); | 229 | aprint_error("%s: no /cpus node found\n", __func__); | |
239 | return 0; | 230 | return 0; | |
240 | } | 231 | } | |
241 | 232 | |||
242 | /* MPIDR affinity levels of boot processor. */ | 233 | /* MPIDR affinity levels of boot processor. */ | |
243 | bp_mpidr = cpu_mpidr_aff_read(); | 234 | bp_mpidr = cpu_mpidr_aff_read(); | |
244 | 235 | |||
245 | /* Boot APs */ | 236 | /* Boot APs */ | |
246 | cpuindex = 1; | 237 | cpuindex = 1; | |
247 | for (child = OF_child(cpus); child; child = OF_peer(child)) { | 238 | for (child = OF_child(cpus); child; child = OF_peer(child)) { | |
248 | if (!arm_fdt_cpu_okay(child)) | 239 | if (!arm_fdt_cpu_okay(child)) | |
249 | continue; | 240 | continue; | |
250 | 241 | |||
251 | if (fdtbus_get_reg64(child, 0, &mpidr, NULL) != 0) | 242 | if (fdtbus_get_reg64(child, 0, &mpidr, NULL) != 0) | |
252 | continue; | 243 | continue; | |
253 | 244 | |||
254 | if (mpidr == bp_mpidr) | 245 | if (mpidr == bp_mpidr) | |
255 | continue; /* BP already started */ | 246 | continue; /* BP already started */ | |
256 | 247 | |||
257 | acm = arm_fdt_cpu_enable_method(child); | 248 | acm = arm_fdt_cpu_enable_method(child); | |
258 | if (acm == NULL) | 249 | if (acm == NULL) | |
259 | acm = arm_fdt_cpu_enable_method(cpus); | 250 | acm = arm_fdt_cpu_enable_method(cpus); | |
260 | if (acm == NULL) | 251 | if (acm == NULL) | |
261 | acm = arm_fdt_cpu_enable_method_byname("psci"); | 252 | acm = arm_fdt_cpu_enable_method_byname("psci"); | |
262 | if (acm == NULL) | 253 | if (acm == NULL) | |
263 | continue; | 254 | continue; | |
264 | 255 | |||
265 | error = arm_fdt_cpu_enable(child, acm); | 256 | error = arm_fdt_cpu_enable(child, acm); | |
266 | if (error != 0) { | 257 | if (error != 0) { | |
267 | aprint_error("%s: failed to enable CPU %#" PRIx64 "\n", | 258 | aprint_error("%s: failed to enable CPU %#" PRIx64 "\n", | |
268 | __func__, mpidr); | 259 | __func__, mpidr); | |
269 | continue; | 260 | continue; | |
270 | } | 261 | } | |
271 | 262 | |||
272 | /* Wake up AP in case firmware has placed it in WFE state */ | 263 | /* Wake up AP in case firmware has placed it in WFE state */ | |
273 | sev(); | 264 | sev(); | |
274 | 265 | |||
275 | /* Wait for AP to start */ | 266 | /* Wait for AP to start */ | |
276 | for (i = 0x10000000; i > 0; i--) { | 267 | for (i = 0x10000000; i > 0; i--) { | |
277 | if (cpu_hatched_p(cpuindex)) | 268 | if (cpu_hatched_p(cpuindex)) | |
278 | break; | 269 | break; | |
279 | } | 270 | } | |
280 | 271 | |||
281 | if (i == 0) { | 272 | if (i == 0) { | |
282 | ret++; | 273 | ret++; | |
283 | aprint_error("cpu%d: WARNING: AP failed to start\n", cpuindex); | 274 | aprint_error("cpu%d: WARNING: AP failed to start\n", cpuindex); | |
284 | } | 275 | } | |
285 | 276 | |||
286 | cpuindex++; | 277 | cpuindex++; | |
287 | } | 278 | } | |
288 | #endif /* MULTIPROCESSOR */ | 279 | #endif /* MULTIPROCESSOR */ | |
289 | return ret; | 280 | return ret; | |
290 | } | 281 | } | |
291 | 282 | |||
292 | static int | 283 | static int | |
293 | cpu_enable_nullop(int phandle) | 284 | cpu_enable_nullop(int phandle) | |
294 | { | 285 | { | |
295 | return ENXIO; | 286 | return ENXIO; | |
296 | } | 287 | } | |
297 | ARM_CPU_METHOD(default, "", cpu_enable_nullop); | 288 | ARM_CPU_METHOD(default, "", cpu_enable_nullop); | |
298 | 289 | |||
299 | #if defined(MULTIPROCESSOR) && NPSCI_FDT > 0 | 290 | #if defined(MULTIPROCESSOR) && NPSCI_FDT > 0 | |
300 | static int | 291 | static int | |
301 | cpu_enable_psci(int phandle) | 292 | cpu_enable_psci(int phandle) | |
302 | { | 293 | { | |
303 | static bool psci_probed, psci_p; | 294 | static bool psci_probed, psci_p; | |
304 | uint64_t mpidr; | 295 | uint64_t mpidr; | |
305 | int ret; | 296 | int ret; | |
306 | 297 | |||
307 | if (!psci_probed) { | 298 | if (!psci_probed) { | |
308 | psci_probed = true; | 299 | psci_probed = true; | |
309 | psci_p = psci_fdt_preinit() == 0; | 300 | psci_p = psci_fdt_preinit() == 0; | |
310 | } | 301 | } | |
311 | if (!psci_p) | 302 | if (!psci_p) | |
312 | return ENXIO; | 303 | return ENXIO; | |
313 | 304 | |||
314 | fdtbus_get_reg64(phandle, 0, &mpidr, NULL); | 305 | fdtbus_get_reg64(phandle, 0, &mpidr, NULL); | |
315 | 306 | |||
316 | #if !defined(AARCH64) | 307 | #if !defined(AARCH64) | |
317 | /* | 308 | /* | |
318 | * not necessary on AARCH64. beside there it hangs the system | 309 | * not necessary on AARCH64. beside there it hangs the system | |
319 | * because cache ops are only functional after cpu_attach() | 310 | * because cache ops are only functional after cpu_attach() | |
320 | * was called. | 311 | * was called. | |
321 | */ | 312 | */ | |
322 | cpu_dcache_wbinv_all(); | 313 | cpu_dcache_wbinv_all(); | |
323 | #endif | 314 | #endif | |
324 | ret = psci_cpu_on(mpidr, cpu_fdt_mpstart_pa(), 0); | 315 | ret = psci_cpu_on(mpidr, cpu_fdt_mpstart_pa(), 0); | |
325 | if (ret != PSCI_SUCCESS) | 316 | if (ret != PSCI_SUCCESS) | |
326 | return EIO; | 317 | return EIO; | |
327 | 318 | |||
328 | return 0; | 319 | return 0; | |
329 | } | 320 | } | |
330 | ARM_CPU_METHOD(psci, "psci", cpu_enable_psci); | 321 | ARM_CPU_METHOD(psci, "psci", cpu_enable_psci); | |
331 | #endif | 322 | #endif | |
332 | 323 | |||
333 | #if defined(MULTIPROCESSOR) && defined(__aarch64__) | 324 | #if defined(MULTIPROCESSOR) && defined(__aarch64__) | |
334 | static int | 325 | static int | |
335 | spintable_cpu_on(const int phandle, u_int cpuindex, | 326 | spintable_cpu_on(const int phandle, u_int cpuindex, | |
336 | paddr_t entry_point_address, paddr_t cpu_release_addr) | 327 | paddr_t entry_point_address, paddr_t cpu_release_addr) | |
337 | { | 328 | { | |
338 | /* | 329 | /* | |
339 | * we need devmap for cpu-release-addr in advance. | 330 | * we need devmap for cpu-release-addr in advance. | |
340 | * __HAVE_MM_MD_DIRECT_MAPPED_PHYS nor pmap work at this point. | 331 | * __HAVE_MM_MD_DIRECT_MAPPED_PHYS nor pmap work at this point. | |
341 | */ | 332 | */ | |
342 | if (pmap_devmap_find_pa(cpu_release_addr, sizeof(paddr_t)) == NULL) { | 333 | if (pmap_devmap_find_pa(cpu_release_addr, sizeof(paddr_t)) == NULL) { | |
343 | aprint_error("%s: devmap for cpu-release-addr" | 334 | aprint_error("%s: devmap for cpu-release-addr" | |
344 | " 0x%08"PRIxPADDR" required\n", __func__, cpu_release_addr); | 335 | " 0x%08"PRIxPADDR" required\n", __func__, cpu_release_addr); | |
345 | return -1; | 336 | return -1; | |
346 | } else { | 337 | } else { | |
347 | extern struct bus_space arm_generic_bs_tag; | 338 | extern struct bus_space arm_generic_bs_tag; | |
348 | bus_space_handle_t ioh; | 339 | bus_space_handle_t ioh; | |
349 | 340 | |||
350 | const int parent = OF_parent(phandle); | 341 | const int parent = OF_parent(phandle); | |
351 | const int addr_cells = fdtbus_get_addr_cells(parent); | 342 | const int addr_cells = fdtbus_get_addr_cells(parent); | |
352 | 343 | |||
353 | bus_space_map(&arm_generic_bs_tag, cpu_release_addr, | 344 | bus_space_map(&arm_generic_bs_tag, cpu_release_addr, | |
354 | sizeof(paddr_t), 0, &ioh); | 345 | sizeof(paddr_t), 0, &ioh); | |
355 | if (addr_cells == 1) { | 346 | if (addr_cells == 1) { | |
356 | bus_space_write_4(&arm_generic_bs_tag, ioh, 0, | 347 | bus_space_write_4(&arm_generic_bs_tag, ioh, 0, | |
357 | entry_point_address); | 348 | entry_point_address); | |
358 | } else { | 349 | } else { | |
359 | bus_space_write_8(&arm_generic_bs_tag, ioh, 0, | 350 | bus_space_write_8(&arm_generic_bs_tag, ioh, 0, | |
360 | entry_point_address); | 351 | entry_point_address); | |
361 | } | 352 | } | |
362 | bus_space_unmap(&arm_generic_bs_tag, ioh, sizeof(paddr_t)); | 353 | bus_space_unmap(&arm_generic_bs_tag, ioh, sizeof(paddr_t)); | |
363 | } | 354 | } | |
364 | 355 | |||
365 | return 0; | 356 | return 0; | |
366 | } | 357 | } | |
367 | 358 | |||
368 | static int | 359 | static int | |
369 | cpu_enable_spin_table(int phandle) | 360 | cpu_enable_spin_table(int phandle) | |
370 | { | 361 | { | |
371 | uint64_t mpidr, addr; | 362 | uint64_t mpidr, addr; | |
372 | int ret; | 363 | int ret; | |
373 | 364 | |||
374 | fdtbus_get_reg64(phandle, 0, &mpidr, NULL); | 365 | fdtbus_get_reg64(phandle, 0, &mpidr, NULL); | |
375 | 366 | |||
376 | if (of_getprop_uint64(phandle, "cpu-release-addr", &addr) != 0) | 367 | if (of_getprop_uint64(phandle, "cpu-release-addr", &addr) != 0) | |
377 | return ENXIO; | 368 | return ENXIO; | |
378 | 369 | |||
379 | ret = spintable_cpu_on(phandle, mpidr, cpu_fdt_mpstart_pa(), | 370 | ret = spintable_cpu_on(phandle, mpidr, cpu_fdt_mpstart_pa(), | |
380 | (paddr_t)addr); | 371 | (paddr_t)addr); | |
381 | if (ret != 0) | 372 | if (ret != 0) | |
382 | return EIO; | 373 | return EIO; | |
383 | 374 | |||
384 | return 0; | 375 | return 0; | |
385 | } | 376 | } | |
386 | ARM_CPU_METHOD(spin_table, "spin-table", cpu_enable_spin_table); | 377 | ARM_CPU_METHOD(spin_table, "spin-table", cpu_enable_spin_table); | |
387 | #endif | 378 | #endif |