xref: /NextBSD/sys/mips/mips/cpu.c (revision 4557fabb34e865d7f40be64b39c9e34fa41dbb60)
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$");
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
mips_get_identity(struct mips_cpuinfo * cpuinfo)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
mips_cpu_init(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
cpu_identify(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 	    "\20\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, "\20\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 					   u_long, u_long, u_long, u_int);
404 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
405 			  driver_filter_t *f, driver_intr_t *, void *,
406 			  void **);
407 
408 static device_method_t cpu_methods[] = {
409 	/* Device interface */
410 	DEVMETHOD(device_probe,		cpu_probe),
411 	DEVMETHOD(device_attach,	cpu_attach),
412 	DEVMETHOD(device_detach,	bus_generic_detach),
413 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
414 
415 	/* Bus interface */
416 	DEVMETHOD(bus_alloc_resource,	cpu_alloc_resource),
417 	DEVMETHOD(bus_setup_intr,	cpu_setup_intr),
418 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
419 
420 	{ 0, 0 }
421 };
422 
423 static driver_t cpu_driver = {
424 	"cpu", cpu_methods, 1
425 };
426 
427 static int
cpu_probe(device_t dev)428 cpu_probe(device_t dev)
429 {
430 
431 	return (0);
432 }
433 
434 static int
cpu_attach(device_t dev)435 cpu_attach(device_t dev)
436 {
437 	int error;
438 #ifdef notyet
439 	device_t clock;
440 #endif
441 
442 	cpu_hardirq_rman.rm_start = 0;
443 	cpu_hardirq_rman.rm_end = 5;
444 	cpu_hardirq_rman.rm_type = RMAN_ARRAY;
445 	cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
446 
447 	error = rman_init(&cpu_hardirq_rman);
448 	if (error != 0) {
449 		device_printf(dev, "failed to initialize irq resources\n");
450 		return (error);
451 	}
452 	/* XXX rman_manage_all. */
453 	error = rman_manage_region(&cpu_hardirq_rman,
454 				   cpu_hardirq_rman.rm_start,
455 				   cpu_hardirq_rman.rm_end);
456 	if (error != 0) {
457 		device_printf(dev, "failed to manage irq resources\n");
458 		return (error);
459 	}
460 
461 	if (device_get_unit(dev) != 0)
462 		panic("can't attach more cpus");
463 	device_set_desc(dev, "MIPS32 processor");
464 
465 #ifdef notyet
466 	clock = device_add_child(dev, "clock", device_get_unit(dev));
467 	if (clock == NULL)
468 		device_printf(dev, "clock failed to attach");
469 #endif
470 
471 	return (bus_generic_attach(dev));
472 }
473 
474 static struct resource *
cpu_alloc_resource(device_t dev,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags)475 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
476 		   u_long start, u_long end, u_long count, u_int flags)
477 {
478 	struct resource *res;
479 
480 	if (type != SYS_RES_IRQ)
481 		return (NULL);
482 	res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
483 				    child);
484 	return (res);
485 }
486 
487 static int
cpu_setup_intr(device_t dev,device_t child,struct resource * res,int flags,driver_filter_t * filt,driver_intr_t * handler,void * arg,void ** cookiep)488 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
489 	       driver_filter_t *filt, driver_intr_t *handler, void *arg,
490 	       void **cookiep)
491 {
492 	int error;
493 	int intr;
494 
495 	error = rman_activate_resource(res);
496 	if (error != 0) {
497 		device_printf(child, "could not activate irq\n");
498 		return (error);
499 	}
500 
501 	intr = rman_get_start(res);
502 
503 	cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
504 	    intr, flags, cookiep);
505 	device_printf(child, "established CPU interrupt %d\n", intr);
506 	return (0);
507 }
508 
509 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);
510