xref: /netbsd-src/sys/arch/sparc64/sparc64/cpu.c (revision 9fbd88883c38d0c0fbfcbe66d76fe6b0fab3f9de)
1 /*	$NetBSD: cpu.c,v 1.18 2001/12/31 16:26:10 matt Exp $ */
2 
3 /*
4  * Copyright (c) 1996
5  *	The President and Fellows of Harvard College. All rights reserved.
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  *	This product includes software developed by Harvard University.
16  *	This product includes software developed by the University of
17  *	California, Lawrence Berkeley Laboratory.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  *
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  * 3. All advertising materials mentioning features or use of this software
29  *    must display the following acknowledgement:
30  *	This product includes software developed by Aaron Brown and
31  *	Harvard University.
32  *	This product includes software developed by the University of
33  *	California, Berkeley and its contributors.
34  * 4. Neither the name of the University nor the names of its contributors
35  *    may be used to endorse or promote products derived from this software
36  *    without specific prior written permission.
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  *
50  *	@(#)cpu.c	8.5 (Berkeley) 11/23/93
51  *
52  */
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/device.h>
57 
58 #include <uvm/uvm_extern.h>
59 
60 #include <machine/autoconf.h>
61 #include <machine/cpu.h>
62 #include <machine/reg.h>
63 #include <machine/trap.h>
64 #include <machine/pmap.h>
65 
66 #include <sparc64/sparc64/cache.h>
67 
68 /* This is declared here so that you must include a CPU for the cache code. */
69 struct cacheinfo cacheinfo;
70 
71 /* Our exported CPU info; we have only one for now. */
72 struct cpu_info cpu_info_store;
73 
74 /* Linked list of all CPUs in system. */
75 struct cpu_info *cpus = NULL;
76 
77 /* The following are used externally (sysctl_hw). */
78 char	machine[] = MACHINE;		/* from <machine/param.h> */
79 char	machine_arch[] = MACHINE_ARCH;	/* from <machine/param.h> */
80 char	cpu_model[100];
81 
82 /* The CPU configuration driver. */
83 static void cpu_attach __P((struct device *, struct device *, void *));
84 int  cpu_match __P((struct device *, struct cfdata *, void *));
85 
86 struct cfattach cpu_ca = {
87 	sizeof(struct device), cpu_match, cpu_attach
88 };
89 
90 extern struct cfdriver cpu_cd;
91 
92 #if defined(SUN4C) || defined(SUN4M)
93 static char *psrtoname __P((int, int, int, char *));
94 #endif
95 static char *fsrtoname __P((int, int, int, char *));
96 
97 #define	IU_IMPL(v)	((((u_int64_t)(v))&VER_IMPL) >> VER_IMPL_SHIFT)
98 #define	IU_VERS(v)	((((u_int64_t)(v))&VER_MASK) >> VER_MASK_SHIFT)
99 
100 #ifdef notdef
101 /*
102  * IU implementations are parceled out to vendors (with some slight
103  * glitches).  Printing these is cute but takes too much space.
104  */
105 static char *iu_vendor[16] = {
106 	"Fujitsu",	/* and also LSI Logic */
107 	"ROSS",		/* ROSS (ex-Cypress) */
108 	"BIT",
109 	"LSIL",		/* LSI Logic finally got their own */
110 	"TI",		/* Texas Instruments */
111 	"Matsushita",
112 	"Philips",
113 	"Harvest",	/* Harvest VLSI Design Center */
114 	"SPEC",		/* Systems and Processes Engineering Corporation */
115 	"Weitek",
116 	"vendor#10",
117 	"vendor#11",
118 	"vendor#12",
119 	"vendor#13",
120 	"vendor#14",
121 	"vendor#15"
122 };
123 #endif
124 
125 /*
126  * Overhead involved in firing up a new CPU:
127  *
128  *	Allocate a cpuinfo/interrupt stack
129  *	Map that into the kernel
130  *	Initialize the cpuinfo
131  *	Return the TLB entry for the cpuinfo.
132  */
133 u_int64_t
134 cpu_init(pa, cpu_num)
135 	paddr_t pa;
136 	int cpu_num;
137 {
138 	struct cpu_info *ci;
139 	u_int64_t pagesize;
140 	u_int64_t pte;
141 	struct vm_page *m;
142 	psize_t size;
143 	vaddr_t va;
144 	struct pglist mlist;
145 	int error;
146 
147 	size = NBPG; /* XXXX 8K, 64K, 512K, or 4MB */
148 	TAILQ_INIT(&mlist);
149 	if ((error = uvm_pglistalloc((psize_t)size, (paddr_t)0, (paddr_t)-1,
150 		(paddr_t)size, (paddr_t)0, &mlist, 1, 0)) != 0)
151 		panic("cpu_start: no memory, error %d", error);
152 
153 	va = uvm_km_valloc(kernel_map, size);
154 	if (va == 0)
155 		panic("cpu_start: no memory");
156 
157 	m = TAILQ_FIRST(&mlist);
158 	pa = VM_PAGE_TO_PHYS(m);
159 	pte = TSB_DATA(0 /* global */,
160 		pagesize,
161 		pa,
162 		1 /* priv */,
163 		1 /* Write */,
164 		1 /* Cacheable */,
165 		1 /* ALIAS -- Disable D$ */,
166 		1 /* valid */,
167 		0 /* IE */);
168 
169 	/* Map the pages */
170 	for (; m != NULL; m = TAILQ_NEXT(m,pageq)) {
171 		pa = VM_PAGE_TO_PHYS(m);
172 		pmap_zero_page(pa);
173 		pmap_enter(pmap_kernel(), va, pa | PMAP_NVC,
174 			VM_PROT_READ|VM_PROT_WRITE,
175 			VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
176 		va += NBPG;
177 	}
178 	pmap_update(pmap_kernel());
179 
180 	if (!cpus) cpus = (struct cpu_info *)va;
181 	else {
182 		for (ci = cpus; ci->ci_next; ci=ci->ci_next);
183 		ci->ci_next = (struct cpu_info *)va;
184 	}
185 
186 	switch (size) {
187 #define K	*1024
188 	case 8 K:
189 		pagesize = TLB_8K;
190 		break;
191 	case 64 K:
192 		pagesize = TLB_64K;
193 		break;
194 	case 512 K:
195 		pagesize = TLB_512K;
196 		break;
197 	case 4 K K:
198 		pagesize = TLB_4M;
199 		break;
200 	default:
201 		panic("cpu_start: stack size %x not a machine page size\n",
202 			(unsigned)size);
203 	}
204 	return (pte|TLB_L);
205 }
206 
207 
208 int
209 cpu_match(parent, cf, aux)
210 	struct device *parent;
211 	struct cfdata *cf;
212 	void *aux;
213 {
214 	struct mainbus_attach_args *ma = aux;
215 
216 	return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0);
217 }
218 
219 /*
220  * Attach the CPU.
221  * Discover interesting goop about the virtual address cache
222  * (slightly funny place to do it, but this is where it is to be found).
223  */
224 static void
225 cpu_attach(parent, dev, aux)
226 	struct device *parent;
227 	struct device *dev;
228 	void *aux;
229 {
230 	int node;
231 	long clk;
232 	int impl, vers, fver;
233 	char *fpuname;
234 	struct mainbus_attach_args *ma = aux;
235 	struct fpstate64 *fpstate;
236 	struct fpstate64 fps[2];
237 	char *sep;
238 	char fpbuf[40];
239 	register int i, l;
240 	u_int64_t ver;
241 	int bigcache, cachesize;
242 	extern u_int64_t cpu_clockrate[];
243 
244 	/* This needs to be 64-bit aligned */
245 	fpstate = ALIGNFPSTATE(&fps[1]);
246 	/*
247 	 * Get the FSR and clear any exceptions.  If we do not unload
248 	 * the queue here and it is left over from a previous crash, we
249 	 * will panic in the first loadfpstate(), due to a sequence error,
250 	 * so we need to dump the whole state anyway.
251 	 *
252 	 * If there is no FPU, trap.c will advance over all the stores,
253 	 * so we initialize fs_fsr here.
254 	 */
255 	fpstate->fs_fsr = 7 << FSR_VER_SHIFT;	/* 7 is reserved for "none" */
256 	savefpstate(fpstate);
257 	fver = (fpstate->fs_fsr >> FSR_VER_SHIFT) & (FSR_VER >> FSR_VER_SHIFT);
258 	ver = getver();
259 	impl = IU_IMPL(ver);
260 	vers = IU_VERS(ver);
261 	if (fver != 7) {
262 		foundfpu = 1;
263 		fpuname = fsrtoname(impl, vers, fver, fpbuf);
264 	} else
265 		fpuname = "no";
266 
267 	/* tell them what we have */
268 	node = ma->ma_node;
269 
270 	clk = PROM_getpropint(node, "clock-frequency", 0);
271 	if (clk == 0) {
272 		/*
273 		 * Try to find it in the OpenPROM root...
274 		 */
275 		clk = PROM_getpropint(findroot(), "clock-frequency", 0);
276 	}
277 	if (clk) {
278 		cpu_clockrate[0] = clk; /* Tell OS what frequency we run on */
279 		cpu_clockrate[1] = clk/1000000;
280 	}
281 	sprintf(cpu_model, "%s @ %s MHz, %s FPU",
282 		PROM_getpropstring(node, "name"),
283 		clockfreq(clk), fpuname);
284 	printf(": %s\n", cpu_model);
285 
286 	bigcache = 0;
287 
288 	cacheinfo.c_physical = 1; /* Dunno... */
289 	cacheinfo.c_split = 1;
290 	cacheinfo.ic_linesize = l = PROM_getpropint(node, "icache-line-size", 0);
291 	for (i = 0; (1 << i) < l && l; i++)
292 		/* void */;
293 	if ((1 << i) != l && l)
294 		panic("bad icache line size %d", l);
295 	cacheinfo.ic_l2linesize = i;
296 	cacheinfo.ic_totalsize =
297 		PROM_getpropint(node, "icache-size", 0) *
298 		PROM_getpropint(node, "icache-associativity", 1);
299 	if (cacheinfo.ic_totalsize == 0)
300 		cacheinfo.ic_totalsize = l *
301 			PROM_getpropint(node, "icache-nlines", 64) *
302 			PROM_getpropint(node, "icache-associativity", 1);
303 
304 	cachesize = cacheinfo.ic_totalsize /
305 	    PROM_getpropint(node, "icache-associativity", 1);
306 	bigcache = cachesize;
307 
308 	cacheinfo.dc_linesize = l =
309 		PROM_getpropint(node, "dcache-line-size",0);
310 	for (i = 0; (1 << i) < l && l; i++)
311 		/* void */;
312 	if ((1 << i) != l && l)
313 		panic("bad dcache line size %d", l);
314 	cacheinfo.dc_l2linesize = i;
315 	cacheinfo.dc_totalsize =
316 		PROM_getpropint(node, "dcache-size", 0) *
317 		PROM_getpropint(node, "dcache-associativity", 1);
318 	if (cacheinfo.dc_totalsize == 0)
319 		cacheinfo.dc_totalsize = l *
320 			PROM_getpropint(node, "dcache-nlines", 128) *
321 			PROM_getpropint(node, "dcache-associativity", 1);
322 
323 	cachesize = cacheinfo.dc_totalsize /
324 	    PROM_getpropint(node, "dcache-associativity", 1);
325 	if (cachesize > bigcache)
326 		bigcache = cachesize;
327 
328 	cacheinfo.ec_linesize = l =
329 		PROM_getpropint(node, "ecache-line-size", 0);
330 	for (i = 0; (1 << i) < l && l; i++)
331 		/* void */;
332 	if ((1 << i) != l && l)
333 		panic("bad ecache line size %d", l);
334 	cacheinfo.ec_l2linesize = i;
335 	cacheinfo.ec_totalsize =
336 		PROM_getpropint(node, "ecache-size", 0) *
337 		PROM_getpropint(node, "ecache-associativity", 1);
338 	if (cacheinfo.ec_totalsize == 0)
339 		cacheinfo.ec_totalsize = l *
340 			PROM_getpropint(node, "ecache-nlines", 32768) *
341 			PROM_getpropint(node, "ecache-associativity", 1);
342 
343 	cachesize = cacheinfo.ec_totalsize /
344 	     PROM_getpropint(node, "ecache-associativity", 1);
345 	if (cachesize > bigcache)
346 		bigcache = cachesize;
347 
348 	/*
349 	 * XXX - The following will have to do until
350 	 * we have per-cpu cache handling.
351 	 */
352 	cacheinfo.c_l2linesize =
353 		min(cacheinfo.ic_l2linesize,
354 		    cacheinfo.dc_l2linesize);
355 	cacheinfo.c_linesize =
356 		min(cacheinfo.ic_linesize,
357 		    cacheinfo.dc_linesize);
358 	cacheinfo.c_totalsize =
359 		cacheinfo.ic_totalsize +
360 		cacheinfo.dc_totalsize;
361 
362 	if (cacheinfo.c_totalsize == 0)
363 		return;
364 
365 	sep = " ";
366 	printf("%s: physical", dev->dv_xname);
367 	if (cacheinfo.ic_totalsize > 0) {
368 		printf("%s%ldK instruction (%ld b/l)", sep,
369 		       (long)cacheinfo.ic_totalsize/1024,
370 		       (long)cacheinfo.ic_linesize);
371 		sep = ", ";
372 	}
373 	if (cacheinfo.dc_totalsize > 0) {
374 		printf("%s%ldK data (%ld b/l)", sep,
375 		       (long)cacheinfo.dc_totalsize/1024,
376 		       (long)cacheinfo.dc_linesize);
377 		sep = ", ";
378 	}
379 	if (cacheinfo.ec_totalsize > 0) {
380 		printf("%s%ldK external (%ld b/l)", sep,
381 		       (long)cacheinfo.ec_totalsize/1024,
382 		       (long)cacheinfo.ec_linesize);
383 	}
384 	printf("\n");
385 	cache_enable();
386 
387 	/*
388 	 * Now that we know the size of the largest cache on this CPU,
389 	 * re-color our pages.
390 	 */
391 	uvm_page_recolor(atop(bigcache));
392 }
393 
394 /*
395  * The following tables convert <IU impl, IU version, FPU version> triples
396  * into names for the CPU and FPU chip.  In most cases we do not need to
397  * inspect the FPU version to name the IU chip, but there is one exception
398  * (for Tsunami), and this makes the tables the same.
399  *
400  * The table contents (and much of the structure here) are from Guy Harris.
401  *
402  */
403 struct info {
404 	u_char	valid;
405 	u_char	iu_impl;
406 	u_char	iu_vers;
407 	u_char	fpu_vers;
408 	char	*name;
409 };
410 
411 #define	ANY	0xff	/* match any FPU version (or, later, IU version) */
412 
413 #if defined(SUN4C) || defined(SUN4M)
414 static struct info iu_types[] = {
415 	{ 1, 0x0, 0x4, 4,   "MB86904" },
416 	{ 1, 0x0, 0x0, ANY, "MB86900/1A or L64801" },
417 	{ 1, 0x1, 0x0, ANY, "RT601 or L64811 v1" },
418 	{ 1, 0x1, 0x1, ANY, "RT601 or L64811 v2" },
419 	{ 1, 0x1, 0x3, ANY, "RT611" },
420 	{ 1, 0x1, 0xf, ANY, "RT620" },
421 	{ 1, 0x2, 0x0, ANY, "B5010" },
422 	{ 1, 0x4, 0x0,   0, "TMS390Z50 v0 or TMS390Z55" },
423 	{ 1, 0x4, 0x1,   0, "TMS390Z50 v1" },
424 	{ 1, 0x4, 0x1,   4, "TMS390S10" },
425 	{ 1, 0x5, 0x0, ANY, "MN10501" },
426 	{ 1, 0x9, 0x0, ANY, "W8601/8701 or MB86903" },
427 	{ 0 }
428 };
429 
430 static char *
431 psrtoname(impl, vers, fver, buf)
432 	register int impl, vers, fver;
433 	char *buf;
434 {
435 	register struct info *p;
436 
437 	for (p = iu_types; p->valid; p++)
438 		if (p->iu_impl == impl && p->iu_vers == vers &&
439 		    (p->fpu_vers == fver || p->fpu_vers == ANY))
440 			return (p->name);
441 
442 	/* Not found. */
443 	sprintf(buf, "IU impl 0x%x vers 0x%x", impl, vers);
444 	return (buf);
445 }
446 #endif /* SUN4C || SUN4M */
447 
448 /* NB: table order matters here; specific numbers must appear before ANY. */
449 static struct info fpu_types[] = {
450 	/*
451 	 * Vendor 0, IU Fujitsu0.
452 	 */
453 	{ 1, 0x0, ANY, 0, "MB86910 or WTL1164/5" },
454 	{ 1, 0x0, ANY, 1, "MB86911 or WTL1164/5" },
455 	{ 1, 0x0, ANY, 2, "L64802 or ACT8847" },
456 	{ 1, 0x0, ANY, 3, "WTL3170/2" },
457 	{ 1, 0x0, 4,   4, "on-chip" },		/* Swift */
458 	{ 1, 0x0, ANY, 4, "L64804" },
459 
460 	/*
461 	 * Vendor 1, IU ROSS0/1 or Pinnacle.
462 	 */
463 	{ 1, 0x1, 0xf, 0, "on-chip" },		/* Pinnacle */
464 	{ 1, 0x1, ANY, 0, "L64812 or ACT8847" },
465 	{ 1, 0x1, ANY, 1, "L64814" },
466 	{ 1, 0x1, ANY, 2, "TMS390C602A" },
467 	{ 1, 0x1, ANY, 3, "RT602 or WTL3171" },
468 
469 	/*
470 	 * Vendor 2, IU BIT0.
471 	 */
472 	{ 1, 0x2, ANY, 0, "B5010 or B5110/20 or B5210" },
473 
474 	/*
475 	 * Vendor 4, Texas Instruments.
476 	 */
477 	{ 1, 0x4, ANY, 0, "on-chip" },		/* Viking */
478 	{ 1, 0x4, ANY, 4, "on-chip" },		/* Tsunami */
479 
480 	/*
481 	 * Vendor 5, IU Matsushita0.
482 	 */
483 	{ 1, 0x5, ANY, 0, "on-chip" },
484 
485 	/*
486 	 * Vendor 9, Weitek.
487 	 */
488 	{ 1, 0x9, ANY, 3, "on-chip" },
489 
490 	{ 0 }
491 };
492 
493 static char *
494 fsrtoname(impl, vers, fver, buf)
495 	register int impl, vers, fver;
496 	char *buf;
497 {
498 	register struct info *p;
499 
500 	for (p = fpu_types; p->valid; p++)
501 		if (p->iu_impl == impl &&
502 		    (p->iu_vers == vers || p->iu_vers == ANY) &&
503 		    (p->fpu_vers == fver))
504 			return (p->name);
505 	sprintf(buf, "version %x", fver);
506 	return (buf);
507 }
508