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/11.0/sys/mips/mips/cpu.c 294883 2016-01-27 02:23:54Z jhibbits $");
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 #ifndef CPU_CNMIPS
77 u_int32_t cfg2;
78 #endif
79 #if defined(CPU_CNMIPS)
80 u_int32_t cfg4;
81 #endif
82 u_int32_t tmp;
83
84 memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
85
86 /* Read and store the PrID ID for CPU identification. */
87 prid = mips_rd_prid();
88 cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
89 cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
90 cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
91
92 /* Read config register selection 0 to learn TLB type. */
93 cfg0 = mips_rd_config();
94
95 cpuinfo->tlb_type =
96 ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
97 cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
98
99 /* If config register selection 1 does not exist, exit. */
100 if (!(cfg0 & MIPS_CONFIG_CM))
101 return;
102
103 /* Learn TLB size and L1 cache geometry. */
104 cfg1 = mips_rd_config1();
105
106 #if defined(CPU_NLM)
107 /* Account for Extended TLB entries in XLP */
108 tmp = mips_rd_config6();
109 cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
110 #elif defined(BERI_LARGE_TLB)
111 /* Check if we support extended TLB entries and if so activate. */
112 tmp = mips_rd_config5();
113 #define BERI_CP5_LTLB_SUPPORTED 0x1
114 if (tmp & BERI_CP5_LTLB_SUPPORTED) {
115 /* See how many extra TLB entries we have. */
116 tmp = mips_rd_config6();
117 cpuinfo->tlb_nentries = (tmp >> 16) + 1;
118 /* Activate the extended entries. */
119 mips_wr_config6(tmp|0x4);
120 } else
121 #endif
122 #if !defined(CPU_NLM)
123 cpuinfo->tlb_nentries =
124 ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
125 #endif
126 #if defined(CPU_CNMIPS)
127 /* Add extended TLB size information from config4. */
128 cfg4 = mips_rd_config4();
129 if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
130 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
131 #endif
132
133 /* L1 instruction cache. */
134 #ifdef MIPS_DISABLE_L1_CACHE
135 cpuinfo->l1.ic_linesize = 0;
136 #else
137 tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
138 if (tmp != 0) {
139 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
140 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
141 cpuinfo->l1.ic_nsets =
142 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
143 }
144 #endif
145
146 /* L1 data cache. */
147 #ifdef MIPS_DISABLE_L1_CACHE
148 cpuinfo->l1.dc_linesize = 0;
149 #else
150 #ifndef CPU_CNMIPS
151 tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
152 if (tmp != 0) {
153 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
154 cpuinfo->l1.dc_nways =
155 (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
156 cpuinfo->l1.dc_nsets =
157 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
158 }
159 #else
160 /*
161 * Some Octeon cache configuration parameters are by model family, not
162 * config1.
163 */
164 if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
165 /* Octeon and Octeon XL. */
166 cpuinfo->l1.dc_nsets = 1;
167 cpuinfo->l1.dc_nways = 64;
168 } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
169 /* Octeon Plus. */
170 cpuinfo->l1.dc_nsets = 2;
171 cpuinfo->l1.dc_nways = 64;
172 } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
173 /* Octeon II. */
174 cpuinfo->l1.dc_nsets = 8;
175 cpuinfo->l1.dc_nways = 32;
176
177 cpuinfo->l1.ic_nsets = 8;
178 cpuinfo->l1.ic_nways = 37;
179 } else {
180 panic("%s: unsupported Cavium Networks CPU.", __func__);
181 }
182
183 /* All Octeon models use 128 byte line size. */
184 cpuinfo->l1.dc_linesize = 128;
185 #endif
186 #endif
187
188 cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
189 * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
190 cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize
191 * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
192
193 /*
194 * Probe PageMask register to see what sizes of pages are supported
195 * by writing all one's and then reading it back.
196 */
197 mips_wr_pagemask(~0);
198 cpuinfo->tlb_pgmask = mips_rd_pagemask();
199 mips_wr_pagemask(MIPS3_PGMASK_4K);
200
201 #ifndef CPU_CNMIPS
202 /* L2 cache */
203 if (!(cfg1 & MIPS_CONFIG_CM)) {
204 /* We don't have valid cfg2 register */
205 return;
206 }
207
208 cfg2 = mips_rd_config2();
209
210 tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
211 if (0 < tmp && tmp <= 7)
212 cpuinfo->l2.dc_linesize = 2 << tmp;
213
214 tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
215 if (0 <= tmp && tmp <= 7)
216 cpuinfo->l2.dc_nsets = 64 << tmp;
217
218 tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
219 if (0 <= tmp && tmp <= 7)
220 cpuinfo->l2.dc_nways = tmp + 1;
221
222 cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
223 * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
224 #endif
225 }
226
227 void
228 mips_cpu_init(void)
229 {
230 platform_cpu_init();
231 mips_get_identity(&cpuinfo);
232 num_tlbentries = cpuinfo.tlb_nentries;
233 mips_wr_wired(0);
234 tlb_invalidate_all();
235 mips_wr_wired(VMWIRED_ENTRIES);
236 mips_config_cache(&cpuinfo);
237 mips_vector_init();
238
239 mips_icache_sync_all();
240 mips_dcache_wbinv_all();
241 /* Print some info about CPU */
242 cpu_identify();
243 }
244
245 static void
246 cpu_identify(void)
247 {
248 uint32_t cfg0, cfg1, cfg2, cfg3;
249 printf("cpu%d: ", 0); /* XXX per-cpu */
250 switch (cpuinfo.cpu_vendor) {
251 case MIPS_PRID_CID_MTI:
252 printf("MIPS Technologies");
253 break;
254 case MIPS_PRID_CID_BROADCOM:
255 case MIPS_PRID_CID_SIBYTE:
256 printf("Broadcom");
257 break;
258 case MIPS_PRID_CID_ALCHEMY:
259 printf("AMD");
260 break;
261 case MIPS_PRID_CID_SANDCRAFT:
262 printf("Sandcraft");
263 break;
264 case MIPS_PRID_CID_PHILIPS:
265 printf("Philips");
266 break;
267 case MIPS_PRID_CID_TOSHIBA:
268 printf("Toshiba");
269 break;
270 case MIPS_PRID_CID_LSI:
271 printf("LSI");
272 break;
273 case MIPS_PRID_CID_LEXRA:
274 printf("Lexra");
275 break;
276 case MIPS_PRID_CID_RMI:
277 printf("RMI");
278 break;
279 case MIPS_PRID_CID_CAVIUM:
280 printf("Cavium");
281 break;
282 case MIPS_PRID_CID_PREHISTORIC:
283 default:
284 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
285 break;
286 }
287 printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
288
289 printf(" MMU: ");
290 if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
291 printf("none present\n");
292 } else {
293 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
294 printf("Standard TLB");
295 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
296 printf("Standard BAT");
297 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
298 printf("Fixed mapping");
299 }
300 printf(", %d entries ", cpuinfo.tlb_nentries);
301 }
302
303 if (cpuinfo.tlb_pgmask) {
304 printf("(");
305 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX)
306 printf("1K ");
307 printf("4K ");
308 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K)
309 printf("16K ");
310 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K)
311 printf("64K ");
312 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K)
313 printf("256K ");
314 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M)
315 printf("1M ");
316 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M)
317 printf("16M ");
318 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M)
319 printf("64M ");
320 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M)
321 printf("256M ");
322 printf("pg sizes)");
323 }
324 printf("\n");
325
326 printf(" L1 i-cache: ");
327 if (cpuinfo.l1.ic_linesize == 0) {
328 printf("disabled");
329 } else {
330 if (cpuinfo.l1.ic_nways == 1) {
331 printf("direct-mapped with");
332 } else {
333 printf ("%d ways of", cpuinfo.l1.ic_nways);
334 }
335 printf(" %d sets, %d bytes per line\n",
336 cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
337 }
338
339 printf(" L1 d-cache: ");
340 if (cpuinfo.l1.dc_linesize == 0) {
341 printf("disabled");
342 } else {
343 if (cpuinfo.l1.dc_nways == 1) {
344 printf("direct-mapped with");
345 } else {
346 printf ("%d ways of", cpuinfo.l1.dc_nways);
347 }
348 printf(" %d sets, %d bytes per line\n",
349 cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
350 }
351
352 printf(" L2 cache: ");
353 if (cpuinfo.l2.dc_linesize == 0) {
354 printf("disabled\n");
355 } else {
356 printf("%d ways of %d sets, %d bytes per line, "
357 "%d KiB total size\n",
358 cpuinfo.l2.dc_nways,
359 cpuinfo.l2.dc_nsets,
360 cpuinfo.l2.dc_linesize,
361 cpuinfo.l2.dc_size / 1024);
362 }
363
364 cfg0 = mips_rd_config();
365 /* If config register selection 1 does not exist, exit. */
366 if (!(cfg0 & MIPS_CONFIG_CM))
367 return;
368
369 cfg1 = mips_rd_config1();
370 printf(" Config1=0x%b\n", cfg1,
371 "\2\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
372
373 /* If config register selection 2 does not exist, exit. */
374 if (!(cfg1 & MIPS_CONFIG_CM))
375 return;
376 cfg2 = mips_rd_config2();
377 /*
378 * Config2 contains no useful information other then Config3
379 * existence flag
380 */
381 printf(" Config2=0x%08x\n", cfg2);
382
383 /* If config register selection 3 does not exist, exit. */
384 if (!(cfg2 & MIPS_CONFIG_CM))
385 return;
386 cfg3 = mips_rd_config3();
387
388 /* Print Config3 if it contains any useful info */
389 if (cfg3 & ~(0x80000000))
390 printf(" Config3=0x%b\n", cfg3, "\2\2SmartMIPS\1TraceLogic");
391 }
392
393 static struct rman cpu_hardirq_rman;
394
395 static devclass_t cpu_devclass;
396
397 /*
398 * Device methods
399 */
400 static int cpu_probe(device_t);
401 static int cpu_attach(device_t);
402 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
403 rman_res_t, rman_res_t, rman_res_t,
404 u_int);
405 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
406 driver_filter_t *f, driver_intr_t *, void *,
407 void **);
408
409 static device_method_t cpu_methods[] = {
410 /* Device interface */
411 DEVMETHOD(device_probe, cpu_probe),
412 DEVMETHOD(device_attach, cpu_attach),
413 DEVMETHOD(device_detach, bus_generic_detach),
414 DEVMETHOD(device_shutdown, bus_generic_shutdown),
415
416 /* Bus interface */
417 DEVMETHOD(bus_alloc_resource, cpu_alloc_resource),
418 DEVMETHOD(bus_setup_intr, cpu_setup_intr),
419 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
420
421 { 0, 0 }
422 };
423
424 static driver_t cpu_driver = {
425 "cpu", cpu_methods, 1
426 };
427
428 static int
429 cpu_probe(device_t dev)
430 {
431
432 return (0);
433 }
434
435 static int
436 cpu_attach(device_t dev)
437 {
438 int error;
439 #ifdef notyet
440 device_t clock;
441 #endif
442
443 cpu_hardirq_rman.rm_start = 0;
444 cpu_hardirq_rman.rm_end = 5;
445 cpu_hardirq_rman.rm_type = RMAN_ARRAY;
446 cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
447
448 error = rman_init(&cpu_hardirq_rman);
449 if (error != 0) {
450 device_printf(dev, "failed to initialize irq resources\n");
451 return (error);
452 }
453 /* XXX rman_manage_all. */
454 error = rman_manage_region(&cpu_hardirq_rman,
455 cpu_hardirq_rman.rm_start,
456 cpu_hardirq_rman.rm_end);
457 if (error != 0) {
458 device_printf(dev, "failed to manage irq resources\n");
459 return (error);
460 }
461
462 if (device_get_unit(dev) != 0)
463 panic("can't attach more cpus");
464 device_set_desc(dev, "MIPS32 processor");
465
466 #ifdef notyet
467 clock = device_add_child(dev, "clock", device_get_unit(dev));
468 if (clock == NULL)
469 device_printf(dev, "clock failed to attach");
470 #endif
471
472 return (bus_generic_attach(dev));
473 }
474
475 static struct resource *
476 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
477 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
478 {
479 struct resource *res;
480
481 if (type != SYS_RES_IRQ)
482 return (NULL);
483 res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
484 child);
485 return (res);
486 }
487
488 static int
489 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
490 driver_filter_t *filt, driver_intr_t *handler, void *arg,
491 void **cookiep)
492 {
493 int error;
494 int intr;
495
496 error = rman_activate_resource(res);
497 if (error != 0) {
498 device_printf(child, "could not activate irq\n");
499 return (error);
500 }
501
502 intr = rman_get_start(res);
503
504 cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
505 intr, flags, cookiep);
506 device_printf(child, "established CPU interrupt %d\n", intr);
507 return (0);
508 }
509
510 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);
Cache object: 7d06a951a47706c531988890d8a6bf00
|