FreeBSD/Linux Kernel Cross Reference
sys/mips/mips/cpu.c
1 /*-
2 * Copyright (c) 2004 Juli Mallett. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: releng/10.1/sys/mips/mips/cpu.c 261277 2014-01-29 22:01:42Z brooks $");
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/stdint.h>
34
35 #include <sys/bus.h>
36 #include <sys/rman.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
39
40 #include <vm/vm.h>
41 #include <vm/vm_page.h>
42
43 #include <machine/cache.h>
44 #include <machine/cpufunc.h>
45 #include <machine/cpuinfo.h>
46 #include <machine/cpuregs.h>
47 #include <machine/intr_machdep.h>
48 #include <machine/locore.h>
49 #include <machine/pte.h>
50 #include <machine/tlb.h>
51 #include <machine/hwfunc.h>
52
53 #if defined(CPU_CNMIPS)
54 #include <contrib/octeon-sdk/cvmx.h>
55 #include <contrib/octeon-sdk/octeon-model.h>
56 #endif
57
58 static void cpu_identify(void);
59
60 struct mips_cpuinfo cpuinfo;
61
62 /*
63 * Attempt to identify the MIPS CPU as much as possible.
64 *
65 * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
66 * XXX: For now, skip config register selections 2 and 3
67 * as we don't currently use L2/L3 cache or additional
68 * MIPS32 processor features.
69 */
70 static void
71 mips_get_identity(struct mips_cpuinfo *cpuinfo)
72 {
73 u_int32_t prid;
74 u_int32_t cfg0;
75 u_int32_t cfg1;
76 #if defined(CPU_CNMIPS)
77 u_int32_t cfg4;
78 #endif
79 u_int32_t tmp;
80
81 memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
82
83 /* Read and store the PrID ID for CPU identification. */
84 prid = mips_rd_prid();
85 cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
86 cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
87 cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
88
89 /* Read config register selection 0 to learn TLB type. */
90 cfg0 = mips_rd_config();
91
92 cpuinfo->tlb_type =
93 ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
94 cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
95
96 /* If config register selection 1 does not exist, exit. */
97 if (!(cfg0 & MIPS_CONFIG_CM))
98 return;
99
100 /* Learn TLB size and L1 cache geometry. */
101 cfg1 = mips_rd_config1();
102
103 #if defined(CPU_NLM)
104 /* Account for Extended TLB entries in XLP */
105 tmp = mips_rd_config6();
106 cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
107 #elif defined(BERI_LARGE_TLB)
108 /* Check if we support extended TLB entries and if so activate. */
109 tmp = mips_rd_config5();
110 #define BERI_CP5_LTLB_SUPPORTED 0x1
111 if (tmp & BERI_CP5_LTLB_SUPPORTED) {
112 /* See how many extra TLB entries we have. */
113 tmp = mips_rd_config6();
114 cpuinfo->tlb_nentries = (tmp >> 16) + 1;
115 /* Activate the extended entries. */
116 mips_wr_config6(tmp|0x4);
117 } else
118 #endif
119 #if !defined(CPU_NLM)
120 cpuinfo->tlb_nentries =
121 ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
122 #endif
123 #if defined(CPU_CNMIPS)
124 /* Add extended TLB size information from config4. */
125 cfg4 = mips_rd_config4();
126 if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
127 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
128 #endif
129
130 /* L1 instruction cache. */
131 #ifdef MIPS_DISABLE_L1_CACHE
132 cpuinfo->l1.ic_linesize = 0;
133 #else
134 tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
135 if (tmp != 0) {
136 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
137 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
138 cpuinfo->l1.ic_nsets =
139 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
140 }
141 #endif
142
143 /* L1 data cache. */
144 #ifdef MIPS_DISABLE_L1_CACHE
145 cpuinfo->l1.dc_linesize = 0;
146 #else
147 #ifndef CPU_CNMIPS
148 tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
149 if (tmp != 0) {
150 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
151 cpuinfo->l1.dc_nways =
152 (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
153 cpuinfo->l1.dc_nsets =
154 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
155 }
156 #else
157 /*
158 * Some Octeon cache configuration parameters are by model family, not
159 * config1.
160 */
161 if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
162 /* Octeon and Octeon XL. */
163 cpuinfo->l1.dc_nsets = 1;
164 cpuinfo->l1.dc_nways = 64;
165 } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
166 /* Octeon Plus. */
167 cpuinfo->l1.dc_nsets = 2;
168 cpuinfo->l1.dc_nways = 64;
169 } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
170 /* Octeon II. */
171 cpuinfo->l1.dc_nsets = 8;
172 cpuinfo->l1.dc_nways = 32;
173
174 cpuinfo->l1.ic_nsets = 8;
175 cpuinfo->l1.ic_nways = 37;
176 } else {
177 panic("%s: unsupported Cavium Networks CPU.", __func__);
178 }
179
180 /* All Octeon models use 128 byte line size. */
181 cpuinfo->l1.dc_linesize = 128;
182 #endif
183 #endif
184
185 cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
186 * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
187 cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize
188 * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
189 }
190
191 void
192 mips_cpu_init(void)
193 {
194 platform_cpu_init();
195 mips_get_identity(&cpuinfo);
196 num_tlbentries = cpuinfo.tlb_nentries;
197 mips_wr_wired(0);
198 tlb_invalidate_all();
199 mips_wr_wired(VMWIRED_ENTRIES);
200 mips_config_cache(&cpuinfo);
201 mips_vector_init();
202
203 mips_icache_sync_all();
204 mips_dcache_wbinv_all();
205 /* Print some info about CPU */
206 cpu_identify();
207 }
208
209 static void
210 cpu_identify(void)
211 {
212 uint32_t cfg0, cfg1, cfg2, cfg3;
213 printf("cpu%d: ", 0); /* XXX per-cpu */
214 switch (cpuinfo.cpu_vendor) {
215 case MIPS_PRID_CID_MTI:
216 printf("MIPS Technologies");
217 break;
218 case MIPS_PRID_CID_BROADCOM:
219 case MIPS_PRID_CID_SIBYTE:
220 printf("Broadcom");
221 break;
222 case MIPS_PRID_CID_ALCHEMY:
223 printf("AMD");
224 break;
225 case MIPS_PRID_CID_SANDCRAFT:
226 printf("Sandcraft");
227 break;
228 case MIPS_PRID_CID_PHILIPS:
229 printf("Philips");
230 break;
231 case MIPS_PRID_CID_TOSHIBA:
232 printf("Toshiba");
233 break;
234 case MIPS_PRID_CID_LSI:
235 printf("LSI");
236 break;
237 case MIPS_PRID_CID_LEXRA:
238 printf("Lexra");
239 break;
240 case MIPS_PRID_CID_RMI:
241 printf("RMI");
242 break;
243 case MIPS_PRID_CID_CAVIUM:
244 printf("Cavium");
245 break;
246 case MIPS_PRID_CID_PREHISTORIC:
247 default:
248 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
249 break;
250 }
251 printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
252
253 printf(" MMU: ");
254 if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
255 printf("none present\n");
256 } else {
257 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
258 printf("Standard TLB");
259 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
260 printf("Standard BAT");
261 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
262 printf("Fixed mapping");
263 }
264 printf(", %d entries\n", cpuinfo.tlb_nentries);
265 }
266
267 printf(" L1 i-cache: ");
268 if (cpuinfo.l1.ic_linesize == 0) {
269 printf("disabled");
270 } else {
271 if (cpuinfo.l1.ic_nways == 1) {
272 printf("direct-mapped with");
273 } else {
274 printf ("%d ways of", cpuinfo.l1.ic_nways);
275 }
276 printf(" %d sets, %d bytes per line\n",
277 cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
278 }
279
280 printf(" L1 d-cache: ");
281 if (cpuinfo.l1.dc_linesize == 0) {
282 printf("disabled");
283 } else {
284 if (cpuinfo.l1.dc_nways == 1) {
285 printf("direct-mapped with");
286 } else {
287 printf ("%d ways of", cpuinfo.l1.dc_nways);
288 }
289 printf(" %d sets, %d bytes per line\n",
290 cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
291 }
292
293 cfg0 = mips_rd_config();
294 /* If config register selection 1 does not exist, exit. */
295 if (!(cfg0 & MIPS_CONFIG_CM))
296 return;
297
298 cfg1 = mips_rd_config1();
299 printf(" Config1=0x%b\n", cfg1,
300 "\2\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
301
302 /* If config register selection 2 does not exist, exit. */
303 if (!(cfg1 & MIPS_CONFIG_CM))
304 return;
305 cfg2 = mips_rd_config2();
306 /*
307 * Config2 contains no useful information other then Config3
308 * existence flag
309 */
310
311 /* If config register selection 3 does not exist, exit. */
312 if (!(cfg2 & MIPS_CONFIG_CM))
313 return;
314 cfg3 = mips_rd_config3();
315
316 /* Print Config3 if it contains any useful info */
317 if (cfg3 & ~(0x80000000))
318 printf(" Config3=0x%b\n", cfg3, "\2\2SmartMIPS\1TraceLogic");
319 }
320
321 static struct rman cpu_hardirq_rman;
322
323 static devclass_t cpu_devclass;
324
325 /*
326 * Device methods
327 */
328 static int cpu_probe(device_t);
329 static int cpu_attach(device_t);
330 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
331 u_long, u_long, u_long, u_int);
332 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
333 driver_filter_t *f, driver_intr_t *, void *,
334 void **);
335
336 static device_method_t cpu_methods[] = {
337 /* Device interface */
338 DEVMETHOD(device_probe, cpu_probe),
339 DEVMETHOD(device_attach, cpu_attach),
340 DEVMETHOD(device_detach, bus_generic_detach),
341 DEVMETHOD(device_shutdown, bus_generic_shutdown),
342
343 /* Bus interface */
344 DEVMETHOD(bus_alloc_resource, cpu_alloc_resource),
345 DEVMETHOD(bus_setup_intr, cpu_setup_intr),
346 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
347
348 { 0, 0 }
349 };
350
351 static driver_t cpu_driver = {
352 "cpu", cpu_methods, 1
353 };
354
355 static int
356 cpu_probe(device_t dev)
357 {
358 return (0);
359 }
360
361 static int
362 cpu_attach(device_t dev)
363 {
364 int error;
365 #ifdef notyet
366 device_t clock;
367 #endif
368
369 cpu_hardirq_rman.rm_start = 0;
370 cpu_hardirq_rman.rm_end = 5;
371 cpu_hardirq_rman.rm_type = RMAN_ARRAY;
372 cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
373
374 error = rman_init(&cpu_hardirq_rman);
375 if (error != 0) {
376 device_printf(dev, "failed to initialize irq resources\n");
377 return (error);
378 }
379 /* XXX rman_manage_all. */
380 error = rman_manage_region(&cpu_hardirq_rman,
381 cpu_hardirq_rman.rm_start,
382 cpu_hardirq_rman.rm_end);
383 if (error != 0) {
384 device_printf(dev, "failed to manage irq resources\n");
385 return (error);
386 }
387
388 if (device_get_unit(dev) != 0)
389 panic("can't attach more cpus");
390 device_set_desc(dev, "MIPS32 processor");
391
392 #ifdef notyet
393 clock = device_add_child(dev, "clock", device_get_unit(dev));
394 if (clock == NULL)
395 device_printf(dev, "clock failed to attach");
396 #endif
397
398 return (bus_generic_attach(dev));
399 }
400
401 static struct resource *
402 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
403 u_long start, u_long end, u_long count, u_int flags)
404 {
405 struct resource *res;
406
407 if (type != SYS_RES_IRQ)
408 return (NULL);
409 res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
410 child);
411 return (res);
412 }
413
414 static int
415 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
416 driver_filter_t *filt, driver_intr_t *handler, void *arg,
417 void **cookiep)
418 {
419 int error;
420 int intr;
421
422 error = rman_activate_resource(res);
423 if (error != 0) {
424 device_printf(child, "could not activate irq\n");
425 return (error);
426 }
427
428 intr = rman_get_start(res);
429
430 cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
431 intr, flags, cookiep);
432 device_printf(child, "established CPU interrupt %d\n", intr);
433 return (0);
434 }
435
436 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);
Cache object: 4fdbef27920d2b637048459e32295289
|