cpu.c revision 1.37 1 1.37 rin /* $NetBSD: cpu.c,v 1.37 2021/03/30 02:27:00 rin Exp $ */
2 1.1 eeh
3 1.1 eeh /*
4 1.1 eeh * Copyright 2001 Wasabi Systems, Inc.
5 1.1 eeh * All rights reserved.
6 1.1 eeh *
7 1.1 eeh * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 1.1 eeh *
9 1.1 eeh * Redistribution and use in source and binary forms, with or without
10 1.1 eeh * modification, are permitted provided that the following conditions
11 1.1 eeh * are met:
12 1.1 eeh * 1. Redistributions of source code must retain the above copyright
13 1.1 eeh * notice, this list of conditions and the following disclaimer.
14 1.1 eeh * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 eeh * notice, this list of conditions and the following disclaimer in the
16 1.1 eeh * documentation and/or other materials provided with the distribution.
17 1.1 eeh * 3. All advertising materials mentioning features or use of this software
18 1.1 eeh * must display the following acknowledgement:
19 1.1 eeh * This product includes software developed for the NetBSD Project by
20 1.1 eeh * Wasabi Systems, Inc.
21 1.1 eeh * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.1 eeh * or promote products derived from this software without specific prior
23 1.1 eeh * written permission.
24 1.1 eeh *
25 1.1 eeh * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.1 eeh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.1 eeh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.1 eeh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.1 eeh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.1 eeh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.1 eeh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.1 eeh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.1 eeh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.1 eeh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.1 eeh * POSSIBILITY OF SUCH DAMAGE.
36 1.1 eeh */
37 1.16 lukem
38 1.16 lukem #include <sys/cdefs.h>
39 1.37 rin __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.37 2021/03/30 02:27:00 rin Exp $");
40 1.1 eeh
41 1.1 eeh #include <sys/param.h>
42 1.1 eeh #include <sys/systm.h>
43 1.1 eeh #include <sys/device.h>
44 1.24 freza #include <sys/evcnt.h>
45 1.30 matt #include <sys/cpu.h>
46 1.1 eeh
47 1.13 thorpej #include <uvm/uvm_extern.h>
48 1.13 thorpej
49 1.23 thorpej #include <prop/proplib.h>
50 1.23 thorpej
51 1.30 matt #include <powerpc/ibm4xx/cpu.h>
52 1.4 simonb #include <powerpc/ibm4xx/dev/plbvar.h>
53 1.1 eeh
54 1.1 eeh struct cputab {
55 1.25 freza u_int version;
56 1.25 freza u_int mask;
57 1.19 scw const char *name;
58 1.32 matt struct cache_info ci;
59 1.1 eeh };
60 1.32 matt
61 1.31 matt static const struct cputab models[] = {
62 1.32 matt {
63 1.32 matt .version = PVR_401A1,
64 1.32 matt .mask = 0xffff0000,
65 1.32 matt .name = "401A1",
66 1.32 matt .ci = {
67 1.32 matt .dcache_size = 1024,
68 1.32 matt .dcache_line_size = 16,
69 1.32 matt .icache_size = 2848,
70 1.32 matt .icache_line_size = 16,
71 1.32 matt }
72 1.32 matt }, {
73 1.32 matt .version = PVR_401B2,
74 1.32 matt .mask = 0xffff0000,
75 1.32 matt .name = "401B21",
76 1.32 matt .ci = {
77 1.32 matt .dcache_size = 8192,
78 1.32 matt .dcache_line_size = 16,
79 1.32 matt .icache_size = 16384,
80 1.32 matt .icache_line_size = 16,
81 1.32 matt }
82 1.32 matt }, {
83 1.32 matt .version = PVR_401C2,
84 1.32 matt .mask = 0xffff0000,
85 1.32 matt .name = "401C2",
86 1.32 matt .ci = {
87 1.32 matt .dcache_size = 8192,
88 1.32 matt .dcache_line_size = 16,
89 1.32 matt .icache_size = 0,
90 1.32 matt .icache_line_size = 16,
91 1.32 matt }
92 1.32 matt }, {
93 1.32 matt .version = PVR_401D2,
94 1.32 matt .mask = 0xffff0000,
95 1.32 matt .name = "401D2",
96 1.32 matt .ci = {
97 1.32 matt .dcache_size = 2848,
98 1.32 matt .dcache_line_size = 16,
99 1.32 matt .icache_size = 4096,
100 1.32 matt .icache_line_size = 16,
101 1.32 matt }
102 1.32 matt }, {
103 1.32 matt .version = PVR_401E2,
104 1.32 matt .mask = 0xffff0000,
105 1.32 matt .name = "401E2",
106 1.32 matt .ci = {
107 1.32 matt .dcache_size = 0,
108 1.32 matt .dcache_line_size = 16,
109 1.32 matt .icache_size = 0,
110 1.32 matt .icache_line_size = 16,
111 1.32 matt }
112 1.32 matt }, {
113 1.32 matt .version = PVR_401F2,
114 1.32 matt .mask = 0xffff0000,
115 1.32 matt .name = "401F2",
116 1.32 matt .ci = {
117 1.32 matt .dcache_size = 2048,
118 1.32 matt .dcache_line_size = 16,
119 1.32 matt .icache_size = 2848,
120 1.32 matt .icache_line_size = 16,
121 1.32 matt }
122 1.32 matt }, {
123 1.32 matt .version = PVR_401G2,
124 1.32 matt .mask = 0xffff0000,
125 1.32 matt .name = "401G2",
126 1.32 matt .ci = {
127 1.32 matt .dcache_size = 2848,
128 1.32 matt .dcache_line_size = 16,
129 1.32 matt .icache_size = 8192,
130 1.32 matt .icache_line_size = 16,
131 1.32 matt }
132 1.32 matt }, {
133 1.35 rin .version = PVR_403GA, /* XXX no MMU */
134 1.35 rin .mask = 0xffffff00,
135 1.35 rin .name = "403GA",
136 1.35 rin .ci = {
137 1.35 rin .dcache_size = 1024,
138 1.35 rin .dcache_line_size = 16,
139 1.35 rin .icache_size = 2048,
140 1.35 rin .icache_line_size = 16,
141 1.35 rin }
142 1.35 rin }, {
143 1.35 rin .version = PVR_403GB, /* XXX no MMU */
144 1.35 rin .mask = 0xffffff00,
145 1.35 rin .name = "403GB",
146 1.35 rin .ci = {
147 1.35 rin .dcache_size = 1024,
148 1.35 rin .dcache_line_size = 16,
149 1.35 rin .icache_size = 2048,
150 1.35 rin .icache_line_size = 16,
151 1.35 rin }
152 1.35 rin }, {
153 1.35 rin .version = PVR_403GC,
154 1.35 rin .mask = 0xffffff00,
155 1.35 rin .name = "403GC",
156 1.35 rin .ci = {
157 1.35 rin .dcache_size = 1024,
158 1.35 rin .dcache_line_size = 16,
159 1.35 rin .icache_size = 2048,
160 1.35 rin .icache_line_size = 16,
161 1.35 rin }
162 1.35 rin }, {
163 1.35 rin .version = PVR_403GCX,
164 1.35 rin .mask = 0xffffff00,
165 1.35 rin .name = "403GCX",
166 1.32 matt .ci = {
167 1.32 matt .dcache_size = 8192,
168 1.32 matt .dcache_line_size = 16,
169 1.32 matt .icache_size = 16384,
170 1.32 matt .icache_line_size = 16,
171 1.32 matt }
172 1.32 matt }, {
173 1.32 matt .version = PVR_405GP,
174 1.32 matt .mask = 0xffff0000,
175 1.32 matt .name = "405GP",
176 1.32 matt .ci = {
177 1.32 matt .dcache_size = 8192,
178 1.32 matt .dcache_line_size = 32,
179 1.37 rin .icache_size = 16384,
180 1.32 matt .icache_line_size = 32,
181 1.32 matt }
182 1.32 matt }, {
183 1.32 matt .version = PVR_405GPR,
184 1.32 matt .mask = 0xffff0000,
185 1.32 matt .name = "405GPr",
186 1.32 matt .ci = {
187 1.32 matt .dcache_size = 16384,
188 1.32 matt .dcache_line_size = 32,
189 1.32 matt .icache_size = 16384,
190 1.32 matt .icache_line_size = 32,
191 1.32 matt }
192 1.32 matt }, {
193 1.32 matt .version = PVR_405D5X1,
194 1.32 matt .mask = 0xfffff000,
195 1.32 matt .name = "Xilinx Virtex II Pro",
196 1.32 matt .ci = {
197 1.32 matt .dcache_size = 16384,
198 1.32 matt .dcache_line_size = 32,
199 1.32 matt .icache_size = 16384,
200 1.32 matt .icache_line_size = 32,
201 1.32 matt }
202 1.32 matt }, {
203 1.32 matt .version = PVR_405D5X2,
204 1.32 matt .mask = 0xfffff000,
205 1.32 matt .name = "Xilinx Virtex 4 FX",
206 1.32 matt .ci = {
207 1.32 matt .dcache_size = 16384,
208 1.32 matt .dcache_line_size = 32,
209 1.32 matt .icache_size = 16384,
210 1.32 matt .icache_line_size = 32,
211 1.32 matt }
212 1.32 matt }, {
213 1.32 matt .version = PVR_405EX,
214 1.32 matt .mask = 0xffff0000,
215 1.32 matt .name = "405EX",
216 1.32 matt .ci = {
217 1.32 matt .dcache_size = 16384,
218 1.32 matt .dcache_line_size = 32,
219 1.32 matt .icache_size = 16384,
220 1.32 matt .icache_line_size = 32,
221 1.32 matt }
222 1.32 matt }, {
223 1.32 matt .version = 0,
224 1.32 matt .mask = 0,
225 1.32 matt .name = NULL,
226 1.32 matt .ci = {
227 1.32 matt /*
228 1.32 matt * Unknown CPU type. For safety we'll specify a
229 1.32 matt * cache with a 4-byte line size. That way cache
230 1.32 matt * flush routines won't miss any lines.
231 1.32 matt */
232 1.32 matt .dcache_line_size = 4,
233 1.32 matt .icache_line_size = 4,
234 1.32 matt },
235 1.32 matt },
236 1.1 eeh };
237 1.1 eeh
238 1.29 matt static int cpumatch(device_t, cfdata_t, void *);
239 1.29 matt static void cpuattach(device_t, device_t, void *);
240 1.1 eeh
241 1.32 matt CFATTACH_DECL_NEW(cpu, 0, cpumatch, cpuattach, NULL, NULL);
242 1.1 eeh
243 1.1 eeh int ncpus;
244 1.1 eeh
245 1.24 freza struct cpu_info cpu_info[1] = {
246 1.24 freza {
247 1.24 freza /* XXX add more ci_ev_* as we teach 4xx about them */
248 1.24 freza .ci_ev_clock = EVCNT_INITIALIZER(EVCNT_TYPE_INTR,
249 1.24 freza NULL, "cpu0", "clock"),
250 1.24 freza .ci_ev_statclock = EVCNT_INITIALIZER(EVCNT_TYPE_INTR,
251 1.24 freza NULL, "cpu0", "stat clock"),
252 1.26 ad .ci_curlwp = &lwp0,
253 1.24 freza }
254 1.24 freza };
255 1.17 shige
256 1.32 matt bool cpufound;
257 1.1 eeh
258 1.1 eeh static int
259 1.29 matt cpumatch(device_t parent, cfdata_t cf, void *aux)
260 1.1 eeh {
261 1.4 simonb struct plb_attach_args *paa = aux;
262 1.1 eeh
263 1.1 eeh /* make sure that we're looking for a CPU */
264 1.8 thorpej if (strcmp(paa->plb_name, cf->cf_name) != 0)
265 1.3 simonb return (0);
266 1.1 eeh
267 1.1 eeh return !cpufound;
268 1.1 eeh }
269 1.1 eeh
270 1.1 eeh static void
271 1.29 matt cpuattach(device_t parent, device_t self, void *aux)
272 1.1 eeh {
273 1.32 matt struct cpu_info * const ci = curcpu();
274 1.32 matt const struct cputab *cp;
275 1.25 freza u_int processor_freq;
276 1.23 thorpej prop_number_t freq;
277 1.2 eeh
278 1.23 thorpej freq = prop_dictionary_get(board_properties, "processor-frequency");
279 1.23 thorpej KASSERT(freq != NULL);
280 1.23 thorpej processor_freq = (unsigned int) prop_number_integer_value(freq);
281 1.1 eeh
282 1.32 matt cpufound = true;
283 1.1 eeh ncpus++;
284 1.1 eeh
285 1.32 matt const u_int pvr = mfpvr();
286 1.32 matt for (cp = models; cp->name != NULL; cp++) {
287 1.32 matt if ((pvr & cp->mask) == cp->version) {
288 1.33 christos cpu_setmodel("%s", cp->name);
289 1.1 eeh break;
290 1.32 matt }
291 1.1 eeh }
292 1.32 matt if (__predict_false(cp->name == NULL))
293 1.33 christos cpu_setmodel("Version 0x%x", pvr);
294 1.25 freza
295 1.36 rin aprint_normal(": %uMHz %s (PVR 0x%08x)\n",
296 1.32 matt (processor_freq + 500000) / 1000000,
297 1.33 christos (cp->name != NULL ? cpu_getmodel() : "unknown model"),
298 1.32 matt pvr);
299 1.1 eeh
300 1.1 eeh cpu_probe_cache();
301 1.1 eeh
302 1.25 freza /* We would crash later on anyway so just make the reason obvious */
303 1.32 matt if (ci->ci_ci.icache_size == 0 && ci->ci_ci.dcache_size == 0)
304 1.32 matt panic("%s: %s: could not detect cache size",
305 1.32 matt __func__, device_xname(self));
306 1.32 matt
307 1.32 matt aprint_normal_dev(self, "%uKB/%uB L1 instruction cache\n",
308 1.32 matt ci->ci_ci.icache_size / 1024, ci->ci_ci.icache_line_size);
309 1.32 matt aprint_normal_dev(self, "%uKB/%uB L1 data cache\n",
310 1.32 matt ci->ci_ci.dcache_size / 1024, ci->ci_ci.dcache_line_size);
311 1.1 eeh }
312 1.1 eeh
313 1.1 eeh /*
314 1.3 simonb * This routine must be explicitly called to initialize the
315 1.3 simonb * CPU cache information so cache flushe and memcpy operation
316 1.1 eeh * work.
317 1.1 eeh */
318 1.1 eeh void
319 1.27 cegger cpu_probe_cache(void)
320 1.1 eeh {
321 1.32 matt struct cpu_info * const ci = curcpu();
322 1.31 matt const struct cputab *cp = models;
323 1.28 kiyohara
324 1.32 matt const u_int pvr = mfpvr();
325 1.32 matt for (cp = models; cp->name != NULL; cp++) {
326 1.28 kiyohara if ((pvr & cp->mask) == cp->version)
327 1.28 kiyohara break;
328 1.28 kiyohara }
329 1.28 kiyohara
330 1.1 eeh /*
331 1.32 matt * Copy the cache from the cputab into cpu_info.
332 1.1 eeh */
333 1.32 matt ci->ci_ci = cp->ci;
334 1.1 eeh }
335 1.1 eeh
336 1.1 eeh /*
337 1.1 eeh * These small routines may have to be replaced,
338 1.1 eeh * if/when we support processors other that the 604.
339 1.1 eeh */
340 1.1 eeh
341 1.1 eeh void
342 1.32 matt dcache_wbinv_page(vaddr_t va)
343 1.1 eeh {
344 1.32 matt const size_t dcache_line_size = curcpu()->ci_ci.dcache_line_size;
345 1.1 eeh
346 1.32 matt if (dcache_line_size) {
347 1.32 matt for (size_t i = 0; i < PAGE_SIZE; i += dcache_line_size) {
348 1.32 matt __asm volatile("dcbf %0,%1" : : "b" (va), "r" (i));
349 1.32 matt }
350 1.34 rin __asm volatile("sync; isync" : : );
351 1.32 matt }
352 1.1 eeh }
353