Print this page
cpuid for ARMv7
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/armv7/os/cpuid.c
+++ new/usr/src/uts/armv7/os/cpuid.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright (c) 2014 Joyent, Inc. All rights reserved.
14 + * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
14 15 */
15 16
16 17 #include <sys/cpuid_impl.h>
17 18 #include <sys/param.h>
18 19 #include <sys/bootconf.h>
19 20 #include <vm/vm_dep.h>
20 21 #include <sys/armv7_bsmf.h>
21 22
22 23 /*
23 24 * Handle classification and identification of ARM processors.
24 25 *
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
25 26 * Currently we do a single pass which reads in information and asserts that the
26 27 * basic information which we receive here matches what we'd expect and are able
27 28 * to do everything that we need with this ARM CPU.
28 29 *
29 30 * TODO We'll eventually do another pass to make sure that we properly determine
30 31 * the feature set to expose to userland.
31 32 */
32 33
33 34 static arm_cpuid_t cpuid_data0;
34 35
35 -static void
36 -cpuid_parse_stage(uint32_t line, uint32_t mask, uint32_t shift, int *out)
36 +static uint32_t
37 +extract(uint32_t line, uint32_t mask, uint32_t shift)
37 38 {
38 - *out = (line & mask) >> shift;
39 + return ((line & mask) >> shift);
39 40 }
40 41
41 42 static void
42 43 cpuid_fill_main(arm_cpuid_t *cpd)
43 44 {
44 45 cpd->ac_pfr[0] = arm_cpuid_pfr0();
45 46 cpd->ac_pfr[1] = arm_cpuid_pfr1();
46 47 cpd->ac_dfr = arm_cpuid_dfr0();
47 48 cpd->ac_mmfr[0] = arm_cpuid_mmfr0();
48 49 cpd->ac_mmfr[1] = arm_cpuid_mmfr1();
49 50 cpd->ac_mmfr[2] = arm_cpuid_mmfr2();
50 51 cpd->ac_mmfr[3] = arm_cpuid_mmfr3();
51 52 cpd->ac_isar[0] = arm_cpuid_isar0();
52 53 cpd->ac_isar[1] = arm_cpuid_isar1();
53 54 cpd->ac_isar[2] = arm_cpuid_isar2();
54 55 cpd->ac_isar[3] = arm_cpuid_isar3();
55 56 cpd->ac_isar[4] = arm_cpuid_isar4();
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
56 57 cpd->ac_isar[5] = arm_cpuid_isar5();
57 58 }
58 59
59 60 static void
60 61 cpuid_fill_fpu(arm_cpuid_t *cpd)
61 62 {
62 63 cpd->ac_mvfr[0] = arm_cpuid_mvfr0();
63 64 cpd->ac_mvfr[1] = arm_cpuid_mvfr1();
64 65 }
65 66
66 -#define CACHE_LEN_MASK 0x003
67 -#define CACHE_M_BIT 0x004
68 -#define CACHE_ASSOC_MASK 0x038
69 -#define CACHE_ASSOC_SHIFT 3
70 -#define CACHE_SIZE_MASK 0x3c0
71 -#define CACHE_SIZE_SHIFT 6
72 -#define CACHE_COLOR_BIT 0x800
73 -#define CACHE_MASK 0xfff
74 -#define CACHE_DCACHE_SHIFT 12
75 -#define CACHE_SEPARATE 0x1000000
67 +#define CCSIDR_WT 0x80000000
68 +#define CCSIDR_WB 0x40000000
69 +#define CCSIDR_RA 0x20000000
70 +#define CCSIDR_WA 0x10000000
71 +#define CCSIDR_NUMSETS_MASK 0x0fffe000
72 +#define CCSIDR_NUMSETS_SHIFT 13
73 +#define CCSIDR_ASSOC_MASK 0x00001ff8
74 +#define CCSIDR_ASSOC_SHIFT 3
75 +#define CCSIDR_LINESIZE_MASK 0x00000007
76 +#define CCSIDR_LINESIZE_SHIFT 0
77 +
78 +static void
79 +cpuid_fill_onecache(arm_cpuid_t *cpd, int level, boolean_t icache)
80 +{
81 + arm_cpuid_cache_t *cache = &cpd->ac_caches[icache][level];
82 + uint32_t ccsidr;
83 +
84 + ccsidr = arm_cpuid_ccsidr(level, icache);
85 + cpd->ac_ccsidr[icache][level] = ccsidr;
86 +
87 + cache->acc_exists = B_TRUE;
88 + cache->acc_wt = (ccsidr & CCSIDR_WT) == CCSIDR_WT;
89 + cache->acc_wb = (ccsidr & CCSIDR_WB) == CCSIDR_WB;
90 + cache->acc_ra = (ccsidr & CCSIDR_RA) == CCSIDR_RA;
91 + cache->acc_wa = (ccsidr & CCSIDR_WA) == CCSIDR_WA;
92 + cache->acc_sets = extract(ccsidr, CCSIDR_NUMSETS_MASK,
93 + CCSIDR_NUMSETS_SHIFT) + 1;
94 + cache->acc_assoc = extract(ccsidr, CCSIDR_ASSOC_MASK,
95 + CCSIDR_ASSOC_SHIFT) + 1;
96 + cache->acc_linesz = sizeof (uint32_t) << (extract(ccsidr,
97 + CCSIDR_LINESIZE_MASK, CCSIDR_LINESIZE_SHIFT) + 2);
76 98
77 99 /*
78 - * On ARMv6 the value of the cache size and the cache associativity depends on
79 - * the value of the M bit, which modifies the value that's in the actual index.
100 + * XXX?
101 +#warning "set acc_size?"
80 102 */
81 -static uint32_t armv6_cpuid_cache_sizes[2][9] = {
82 - { 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x100000,
83 - 0x20000 },
84 - { 0x300, 0x600, 0xc00, 0x1800, 0x3000, 0x6000, 0xc000, 0x18000,
85 - 0x30000 }
86 -};
87 -
88 -static int8_t armv6_cpuid_cache_assoc[2][9] = {
89 - { 1, 2, 4, 8, 16, 32, 64, 128 },
90 - { -1, 3, 6, 12, 24, 48, 96, 192 }
91 -};
92 -
93 -static uint8_t armv6_cpuid_cache_linesz[] = {
94 - 8,
95 - 16,
96 - 32,
97 - 64
98 -};
99 -
100 -static void
101 -cpuid_fill_onecache(arm_cpuid_cache_t *accp, uint32_t val)
102 -{
103 - int mbit, index, assoc;
104 -
105 - mbit = (val & CACHE_M_BIT) != 0 ? 1 : 0;
106 - index = (val & CACHE_ASSOC_MASK) >> CACHE_ASSOC_SHIFT;
107 - assoc = armv6_cpuid_cache_assoc[mbit][index];
108 - if (assoc == -1) {
109 - accp->acc_exists = B_FALSE;
110 - return;
111 - }
112 - ASSERT(assoc > 0);
113 - accp->acc_assoc = assoc;
114 - accp->acc_rcolor = (val & CACHE_COLOR_BIT) == 0 ?
115 - B_FALSE : B_TRUE;
116 - index = val & CACHE_LEN_MASK;
117 - accp->acc_linesz = armv6_cpuid_cache_linesz[index];
118 - index = (val & CACHE_SIZE_MASK) >> CACHE_SIZE_SHIFT;
119 - accp->acc_size = armv6_cpuid_cache_sizes[mbit][index];
120 - accp->acc_exists = B_TRUE;
121 103 }
122 104
123 105 static void
124 106 cpuid_fill_caches(arm_cpuid_t *cpd)
125 107 {
126 - uint32_t val, icache, dcache;
108 + uint32_t erg, cwg;
109 + uint32_t l1ip;
110 + uint32_t ctr;
111 + uint32_t clidr;
112 + int level;
113 +
114 + clidr = arm_cpuid_clidr();
115 + cpd->ac_clidr = clidr;
116 +
117 + /* default all caches to not existing, and not unified */
118 + for (level = 0; level < 7; level++) {
119 + cpd->ac_caches[B_TRUE][level].acc_exists = B_FALSE;
120 + cpd->ac_caches[B_FALSE][level].acc_exists = B_FALSE;
121 + cpd->ac_caches[B_TRUE][level].acc_unified = B_FALSE;
122 + cpd->ac_caches[B_FALSE][level].acc_unified = B_FALSE;
123 + }
124 +
125 + /* retrieve cache info for each level */
126 + for (level = 0; level < 7; level++) {
127 + arm_cpuid_cache_t *icache = &cpd->ac_caches[B_TRUE][level];
128 + arm_cpuid_cache_t *dcache = &cpd->ac_caches[B_FALSE][level];
129 + uint32_t ctype = (cpd->ac_clidr >> (3 * level)) & 0x7;
130 +
131 + /* stop looking we find the first non-existent level */
132 + if (!ctype)
133 + break;
134 +
135 + switch (ctype) {
136 + case 1:
137 + cpuid_fill_onecache(cpd, level, B_TRUE);
138 + break;
139 + case 2:
140 + cpuid_fill_onecache(cpd, level, B_FALSE);
141 + break;
142 + case 3:
143 + cpuid_fill_onecache(cpd, level, B_TRUE);
144 + cpuid_fill_onecache(cpd, level, B_FALSE);
145 + break;
146 + case 4:
147 + cpuid_fill_onecache(cpd, level, B_FALSE);
148 + dcache->acc_unified = B_TRUE;
149 + break;
150 + default:
151 + bop_panic("unsupported cache type");
152 + }
153 + }
154 +
155 + /*
156 + * We require L1-I/D & L2-D. Unified caches are OK as well.
157 + */
158 + if (!cpd->ac_caches[B_TRUE][0].acc_exists &&
159 + (!cpd->ac_caches[B_FALSE][0].acc_exists ||
160 + !cpd->ac_caches[B_FALSE][0].acc_unified))
161 + bop_panic("no L1 instructian cache detected");
162 +
163 + if (!cpd->ac_caches[B_FALSE][1].acc_exists)
164 + bop_panic("no L2 data cache detected");
127 165
128 - val = arm_cpuid_ctr();
129 - icache = val & CACHE_MASK;
130 - cpuid_fill_onecache(&cpd->ac_icache, icache);
131 - dcache = (val >> CACHE_DCACHE_SHIFT) & CACHE_MASK;
132 - cpuid_fill_onecache(&cpd->ac_dcache, dcache);
133 -
134 - if (val & CACHE_SEPARATE) {
135 - cpd->ac_unifiedl1 = B_FALSE;
136 - } else {
137 - cpd->ac_unifiedl1 = B_TRUE;
138 - }
139 -
140 - armv7_bsmdep_l2cacheinfo();
141 - armv6_cachesz = cpd->ac_dcache.acc_size;
142 - armv6_cache_assoc = cpd->ac_dcache.acc_assoc;
166 + /*
167 + * set globals with cache size info
168 + */
169 + l2cache_sz = cpd->ac_caches[B_FALSE][1].acc_size;
170 + l2cache_linesz = cpd->ac_caches[B_FALSE][1].acc_linesz;
171 + l2cache_assoc = cpd->ac_caches[B_FALSE][1].acc_assoc;
143 172 }
144 173
145 174
146 175 /*
147 - * There isn't a specific way to indicate that we're on ARMv6k. Instead what we
148 - * need to do is go through and check for a few features that we know we're
149 - * going to need.
150 - *
151 - * TODO This will have to be revisited with ARMv7 support
176 + * We need to do is go through and check for a few features that we know
177 + * we're going to need.
152 178 */
153 179 static void
154 180 cpuid_verify(void)
155 181 {
156 182 arm_cpuid_mem_vmsa_t vmsa;
157 183 arm_cpuid_mem_barrier_t barrier;
158 184 int sync, syncf;
159 185
160 186 arm_cpuid_t *cpd = &cpuid_data0;
161 187
162 - /* v6 vmsa */
163 - cpuid_parse_stage(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK,
164 - ARM_CPUID_MMFR0_STATE0_SHIFT, (int *)&vmsa);
165 - /* TODO We might be able to support v6, but bcm2835+qvpb are this */
188 + /* v7 vmsa */
189 + vmsa = extract(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK,
190 + ARM_CPUID_MMFR0_STATE0_SHIFT);
166 191 if (vmsa != ARM_CPUID_MEM_VMSA_V7) {
167 192 bop_printf(NULL, "invalid vmsa setting, found 0x%x\n", vmsa);
168 193 bop_panic("unsupported cpu");
169 194 }
170 195
171 196 /* check for ISB, DSB, etc. in cp15 */
172 - cpuid_parse_stage(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK,
173 - ARM_CPUID_MMFR2_STATE5_SHIFT, (int *)&barrier);
174 - if (barrier != ARM_CPUID_MEM_BARRIER_CP15 &&
175 - barrier != ARM_CPUID_MEM_BARRIER_INSTR) {
176 - bop_printf(NULL, "missing support for CP15 memory barriers\n");
197 + barrier = extract(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK,
198 + ARM_CPUID_MMFR2_STATE5_SHIFT);
199 + if (barrier != ARM_CPUID_MEM_BARRIER_INSTR) {
200 + bop_printf(NULL, "missing support for memory barrier "
201 + "instructions\n");
177 202 bop_panic("unsupported CPU");
178 203 }
179 204
180 205 /* synch prims */
181 - cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR3_STATE3_SHIFT,
182 - ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&sync);
183 - cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE3_SHIFT,
184 - ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&syncf);
206 + sync = extract(cpd->ac_isar[3], ARM_CPUID_ISAR3_STATE3_SHIFT,
207 + ARM_CPUID_ISAR3_STATE3_SHIFT);
208 + syncf = extract(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE5_SHIFT,
209 + ARM_CPUID_ISAR4_STATE5_SHIFT);
185 210 if (sync != 0x2 && syncf != 0x0) {
186 211 bop_printf(NULL, "unsupported synch primitives: sync,frac: "
187 212 "%x,%x\n", sync, syncf);
188 213 bop_panic("unsupported CPU");
189 214 }
190 -
191 - if (cpd->ac_icache.acc_exists == B_FALSE) {
192 - bop_printf(NULL, "icache not defined to exist\n");
193 - bop_panic("unsupported CPU");
194 - }
195 -
196 - if (cpd->ac_dcache.acc_exists == B_FALSE) {
197 - bop_printf(NULL, "dcache not defined to exist\n");
198 - bop_panic("unsupported CPU");
199 - }
200 215 }
201 216
202 217 static void
203 218 cpuid_valid_ident(uint32_t ident)
204 219 {
205 220 arm_cpuid_ident_arch_t arch;
206 221
207 222 /*
208 - * We don't support stock ARMv6 or older.
223 + * We don't support anything older than ARMv7.
209 224 */
210 225 arch = (ident & ARM_CPUID_IDENT_ARCH_MASK) >>
211 226 ARM_CPUID_IDENT_ARCH_SHIFT;
212 227 if (arch != ARM_CPUID_IDENT_ARCH_CPUID) {
213 228 bop_printf(NULL, "encountered unsupported CPU arch: 0x%x",
214 229 arch);
215 230 bop_panic("unsupported CPU");
216 231 }
217 232 }
218 233
219 234 static void
220 235 cpuid_valid_fpident(uint32_t ident)
221 236 {
222 237 arm_cpuid_vfp_arch_t vfp;
223 238
224 - cpuid_parse_stage(ident, ARM_CPUID_VFP_ARCH_MASK,
225 - ARM_CPUID_VFP_ARCH_SHIFT, (int *)&vfp);
239 + vfp = extract(ident, ARM_CPUID_VFP_ARCH_MASK, ARM_CPUID_VFP_ARCH_SHIFT);
240 + // XXX: _V3_V2BASE? _V3_NOBASE? _V3_V3BASE?
226 241 if (vfp != ARM_CPUID_VFP_ARCH_V2) {
227 242 bop_printf(NULL, "unsupported vfp version: %x\n", vfp);
228 243 bop_panic("unsupported CPU");
229 244 }
230 245
231 246 if ((ident & ARM_CPUID_VFP_SW_MASK) != 0) {
232 247 bop_printf(NULL, "encountered software-only vfp\n");
233 248 bop_panic("unsuppored CPU");
234 249 }
235 250 }
236 251 void
237 252 cpuid_setup(void)
238 253 {
239 254 arm_cpuid_t *cpd = &cpuid_data0;
240 255
241 - cpd->ac_ident = arm_cpuid_idreg();
256 + cpd->ac_ident = arm_cpuid_midr();
242 257 cpuid_valid_ident(cpd->ac_ident);
243 258 cpuid_fill_main(cpd);
244 259
245 260 cpd->ac_fpident = arm_cpuid_vfpidreg();
246 261 cpuid_valid_fpident(cpd->ac_fpident);
247 262 cpuid_fill_fpu(cpd);
263 +
248 264 cpuid_fill_caches(cpd);
249 265
250 266 cpuid_verify();
251 267 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX