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