cpu.c revision 1.33 1 1.33 christos /* $NetBSD: cpu.c,v 1.33 2014/03/24 19:29:59 christos 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.33 christos __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.33 2014/03/24 19:29:59 christos 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.32 matt .version = PVR_403,
134 1.32 matt .mask = 0xffff0000,
135 1.32 matt .name = "403",
136 1.32 matt .ci = {
137 1.32 matt .dcache_size = 8192,
138 1.32 matt .dcache_line_size = 16,
139 1.32 matt .icache_size = 16384,
140 1.32 matt .icache_line_size = 16,
141 1.32 matt }
142 1.32 matt }, {
143 1.32 matt .version = PVR_405GP,
144 1.32 matt .mask = 0xffff0000,
145 1.32 matt .name = "405GP",
146 1.32 matt .ci = {
147 1.32 matt .dcache_size = 8192,
148 1.32 matt .dcache_line_size = 32,
149 1.32 matt .icache_size = 8192,
150 1.32 matt .icache_line_size = 32,
151 1.32 matt }
152 1.32 matt }, {
153 1.32 matt .version = PVR_405GPR,
154 1.32 matt .mask = 0xffff0000,
155 1.32 matt .name = "405GPr",
156 1.32 matt .ci = {
157 1.32 matt .dcache_size = 16384,
158 1.32 matt .dcache_line_size = 32,
159 1.32 matt .icache_size = 16384,
160 1.32 matt .icache_line_size = 32,
161 1.32 matt }
162 1.32 matt }, {
163 1.32 matt .version = PVR_405D5X1,
164 1.32 matt .mask = 0xfffff000,
165 1.32 matt .name = "Xilinx Virtex II Pro",
166 1.32 matt .ci = {
167 1.32 matt .dcache_size = 16384,
168 1.32 matt .dcache_line_size = 32,
169 1.32 matt .icache_size = 16384,
170 1.32 matt .icache_line_size = 32,
171 1.32 matt }
172 1.32 matt }, {
173 1.32 matt .version = PVR_405D5X2,
174 1.32 matt .mask = 0xfffff000,
175 1.32 matt .name = "Xilinx Virtex 4 FX",
176 1.32 matt .ci = {
177 1.32 matt .dcache_size = 16384,
178 1.32 matt .dcache_line_size = 32,
179 1.32 matt .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_405EX,
184 1.32 matt .mask = 0xffff0000,
185 1.32 matt .name = "405EX",
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 = 0,
194 1.32 matt .mask = 0,
195 1.32 matt .name = NULL,
196 1.32 matt .ci = {
197 1.32 matt /*
198 1.32 matt * Unknown CPU type. For safety we'll specify a
199 1.32 matt * cache with a 4-byte line size. That way cache
200 1.32 matt * flush routines won't miss any lines.
201 1.32 matt */
202 1.32 matt .dcache_line_size = 4,
203 1.32 matt .icache_line_size = 4,
204 1.32 matt },
205 1.32 matt },
206 1.1 eeh };
207 1.1 eeh
208 1.29 matt static int cpumatch(device_t, cfdata_t, void *);
209 1.29 matt static void cpuattach(device_t, device_t, void *);
210 1.1 eeh
211 1.32 matt CFATTACH_DECL_NEW(cpu, 0, cpumatch, cpuattach, NULL, NULL);
212 1.1 eeh
213 1.1 eeh int ncpus;
214 1.1 eeh
215 1.24 freza struct cpu_info cpu_info[1] = {
216 1.24 freza {
217 1.24 freza /* XXX add more ci_ev_* as we teach 4xx about them */
218 1.24 freza .ci_ev_clock = EVCNT_INITIALIZER(EVCNT_TYPE_INTR,
219 1.24 freza NULL, "cpu0", "clock"),
220 1.24 freza .ci_ev_statclock = EVCNT_INITIALIZER(EVCNT_TYPE_INTR,
221 1.24 freza NULL, "cpu0", "stat clock"),
222 1.26 ad .ci_curlwp = &lwp0,
223 1.24 freza }
224 1.24 freza };
225 1.17 shige
226 1.32 matt bool cpufound;
227 1.1 eeh
228 1.1 eeh static int
229 1.29 matt cpumatch(device_t parent, cfdata_t cf, void *aux)
230 1.1 eeh {
231 1.4 simonb struct plb_attach_args *paa = aux;
232 1.1 eeh
233 1.1 eeh /* make sure that we're looking for a CPU */
234 1.8 thorpej if (strcmp(paa->plb_name, cf->cf_name) != 0)
235 1.3 simonb return (0);
236 1.1 eeh
237 1.1 eeh return !cpufound;
238 1.1 eeh }
239 1.1 eeh
240 1.1 eeh static void
241 1.29 matt cpuattach(device_t parent, device_t self, void *aux)
242 1.1 eeh {
243 1.32 matt struct cpu_info * const ci = curcpu();
244 1.32 matt const struct cputab *cp;
245 1.25 freza u_int processor_freq;
246 1.23 thorpej prop_number_t freq;
247 1.2 eeh
248 1.23 thorpej freq = prop_dictionary_get(board_properties, "processor-frequency");
249 1.23 thorpej KASSERT(freq != NULL);
250 1.23 thorpej processor_freq = (unsigned int) prop_number_integer_value(freq);
251 1.1 eeh
252 1.32 matt cpufound = true;
253 1.1 eeh ncpus++;
254 1.1 eeh
255 1.32 matt const u_int pvr = mfpvr();
256 1.32 matt for (cp = models; cp->name != NULL; cp++) {
257 1.32 matt if ((pvr & cp->mask) == cp->version) {
258 1.33 christos cpu_setmodel("%s", cp->name);
259 1.1 eeh break;
260 1.32 matt }
261 1.1 eeh }
262 1.32 matt if (__predict_false(cp->name == NULL))
263 1.33 christos cpu_setmodel("Version 0x%x", pvr);
264 1.25 freza
265 1.32 matt aprint_normal(": %uMHz %s (PVR 0x%x)\n",
266 1.32 matt (processor_freq + 500000) / 1000000,
267 1.33 christos (cp->name != NULL ? cpu_getmodel() : "unknown model"),
268 1.32 matt pvr);
269 1.1 eeh
270 1.1 eeh cpu_probe_cache();
271 1.1 eeh
272 1.25 freza /* We would crash later on anyway so just make the reason obvious */
273 1.32 matt if (ci->ci_ci.icache_size == 0 && ci->ci_ci.dcache_size == 0)
274 1.32 matt panic("%s: %s: could not detect cache size",
275 1.32 matt __func__, device_xname(self));
276 1.32 matt
277 1.32 matt aprint_normal_dev(self, "%uKB/%uB L1 instruction cache\n",
278 1.32 matt ci->ci_ci.icache_size / 1024, ci->ci_ci.icache_line_size);
279 1.32 matt aprint_normal_dev(self, "%uKB/%uB L1 data cache\n",
280 1.32 matt ci->ci_ci.dcache_size / 1024, ci->ci_ci.dcache_line_size);
281 1.1 eeh }
282 1.1 eeh
283 1.1 eeh /*
284 1.3 simonb * This routine must be explicitly called to initialize the
285 1.3 simonb * CPU cache information so cache flushe and memcpy operation
286 1.1 eeh * work.
287 1.1 eeh */
288 1.1 eeh void
289 1.27 cegger cpu_probe_cache(void)
290 1.1 eeh {
291 1.32 matt struct cpu_info * const ci = curcpu();
292 1.31 matt const struct cputab *cp = models;
293 1.28 kiyohara
294 1.32 matt const u_int pvr = mfpvr();
295 1.32 matt for (cp = models; cp->name != NULL; cp++) {
296 1.28 kiyohara if ((pvr & cp->mask) == cp->version)
297 1.28 kiyohara break;
298 1.28 kiyohara }
299 1.28 kiyohara
300 1.1 eeh /*
301 1.32 matt * Copy the cache from the cputab into cpu_info.
302 1.1 eeh */
303 1.32 matt ci->ci_ci = cp->ci;
304 1.1 eeh }
305 1.1 eeh
306 1.1 eeh /*
307 1.1 eeh * These small routines may have to be replaced,
308 1.1 eeh * if/when we support processors other that the 604.
309 1.1 eeh */
310 1.1 eeh
311 1.1 eeh void
312 1.32 matt dcache_wbinv_page(vaddr_t va)
313 1.1 eeh {
314 1.32 matt const size_t dcache_line_size = curcpu()->ci_ci.dcache_line_size;
315 1.1 eeh
316 1.32 matt if (dcache_line_size) {
317 1.32 matt for (size_t i = 0; i < PAGE_SIZE; i += dcache_line_size) {
318 1.32 matt __asm volatile("dcbf %0,%1" : : "b" (va), "r" (i));
319 1.32 matt }
320 1.32 matt __asm volatile("sync;isync" : : );
321 1.32 matt }
322 1.1 eeh }
323