xref: /netbsd/sys/arch/sparc64/sparc64/cpu.c (revision c4a72b64)
1 /*	$NetBSD: cpu.c,v 1.26 2002/10/02 16:02:21 thorpej 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 CFATTACH_DECL(cpu, sizeof(struct device),
87     cpu_match, cpu_attach, NULL, NULL);
88 
89 extern struct cfdriver cpu_cd;
90 
91 #define	IU_IMPL(v)	((((uint64_t)(v)) & VER_IMPL) >> VER_IMPL_SHIFT)
92 #define	IU_VERS(v)	((((uint64_t)(v)) & VER_MASK) >> VER_MASK_SHIFT)
93 
94 #ifdef notdef
95 /*
96  * IU implementations are parceled out to vendors (with some slight
97  * glitches).  Printing these is cute but takes too much space.
98  */
99 static char *iu_vendor[16] = {
100 	"Fujitsu",	/* and also LSI Logic */
101 	"ROSS",		/* ROSS (ex-Cypress) */
102 	"BIT",
103 	"LSIL",		/* LSI Logic finally got their own */
104 	"TI",		/* Texas Instruments */
105 	"Matsushita",
106 	"Philips",
107 	"Harvest",	/* Harvest VLSI Design Center */
108 	"SPEC",		/* Systems and Processes Engineering Corporation */
109 	"Weitek",
110 	"vendor#10",
111 	"vendor#11",
112 	"vendor#12",
113 	"vendor#13",
114 	"vendor#14",
115 	"vendor#15"
116 };
117 #endif
118 
119 /*
120  * Overhead involved in firing up a new CPU:
121  *
122  *	Allocate a cpuinfo/interrupt stack
123  *	Map that into the kernel
124  *	Initialize the cpuinfo
125  *	Return the TLB entry for the cpuinfo.
126  */
127 uint64_t
128 cpu_init(pa, cpu_num)
129 	paddr_t pa;
130 	int cpu_num;
131 {
132 	struct cpu_info *ci;
133 	uint64_t pagesize;
134 	uint64_t pte;
135 	struct vm_page *pg;
136 	psize_t size;
137 	vaddr_t va;
138 	struct pglist pglist;
139 	int error;
140 
141 	size = NBPG; /* XXXX 8K, 64K, 512K, or 4MB */
142 	if ((error = uvm_pglistalloc(size, (paddr_t)0, (paddr_t)-1,
143 		(paddr_t)size, (paddr_t)0, &pglist, 1, 0)) != 0)
144 		panic("cpu_start: no memory, error %d", error);
145 
146 	va = uvm_km_valloc(kernel_map, size);
147 	if (va == 0)
148 		panic("cpu_start: no memory");
149 
150 	pg = TAILQ_FIRST(&pglist);
151 	pa = VM_PAGE_TO_PHYS(pg);
152 	pte = TSB_DATA(0 /* global */,
153 		pagesize,
154 		pa,
155 		1 /* priv */,
156 		1 /* Write */,
157 		1 /* Cacheable */,
158 		1 /* ALIAS -- Disable D$ */,
159 		1 /* valid */,
160 		0 /* IE */);
161 
162 	/* Map the pages */
163 	for (; pg != NULL; pg = TAILQ_NEXT(pg, pageq)) {
164 		pa = VM_PAGE_TO_PHYS(pg);
165 		pmap_zero_page(pa);
166 		pmap_kenter_pa(va, pa | PMAP_NVC, VM_PROT_READ | VM_PROT_WRITE);
167 		va += NBPG;
168 	}
169 	pmap_update(pmap_kernel());
170 
171 	if (!cpus)
172 		cpus = (struct cpu_info *)va;
173 	else {
174 		for (ci = cpus; ci->ci_next; ci = ci->ci_next)
175 			;
176 		ci->ci_next = (struct cpu_info *)va;
177 	}
178 
179 	switch (size) {
180 #define K	*1024
181 	case 8 K:
182 		pagesize = TLB_8K;
183 		break;
184 	case 64 K:
185 		pagesize = TLB_64K;
186 		break;
187 	case 512 K:
188 		pagesize = TLB_512K;
189 		break;
190 	case 4 K K:
191 		pagesize = TLB_4M;
192 		break;
193 	default:
194 		panic("cpu_start: stack size %x not a machine page size",
195 			(unsigned)size);
196 	}
197 	return (pte | TLB_L);
198 }
199 
200 int
201 cpu_match(parent, cf, aux)
202 	struct device *parent;
203 	struct cfdata *cf;
204 	void *aux;
205 {
206 	struct mainbus_attach_args *ma = aux;
207 
208 	return (strcmp(cf->cf_name, ma->ma_name) == 0);
209 }
210 
211 /*
212  * Attach the CPU.
213  * Discover interesting goop about the virtual address cache
214  * (slightly funny place to do it, but this is where it is to be found).
215  */
216 static void
217 cpu_attach(parent, dev, aux)
218 	struct device *parent;
219 	struct device *dev;
220 	void *aux;
221 {
222 	int node;
223 	long clk;
224 	int impl, vers, fver;
225 	struct mainbus_attach_args *ma = aux;
226 	struct fpstate64 *fpstate;
227 	struct fpstate64 fps[2];
228 	char *sep;
229 	register int i, l;
230 	uint64_t ver;
231 	int bigcache, cachesize;
232 	extern uint64_t cpu_clockrate[];
233 
234 	/* This needs to be 64-bit aligned */
235 	fpstate = ALIGNFPSTATE(&fps[1]);
236 
237 	/*
238 	 * Get the FSR and clear any exceptions.  If we do not unload
239 	 * the queue here and it is left over from a previous crash, we
240 	 * will panic in the first loadfpstate(), due to a sequence error,
241 	 * so we need to dump the whole state anyway.
242 	 */
243 
244 	fpstate->fs_fsr = 7 << FSR_VER_SHIFT;	/* 7 is reserved for "none" */
245 	savefpstate(fpstate);
246 	fver = (fpstate->fs_fsr >> FSR_VER_SHIFT) & (FSR_VER >> FSR_VER_SHIFT);
247 	ver = getver();
248 	impl = IU_IMPL(ver);
249 	vers = IU_VERS(ver);
250 
251 	/* tell them what we have */
252 	node = ma->ma_node;
253 
254 	clk = PROM_getpropint(node, "clock-frequency", 0);
255 	if (clk == 0) {
256 
257 		/*
258 		 * Try to find it in the OpenPROM root...
259 		 */
260 		clk = PROM_getpropint(findroot(), "clock-frequency", 0);
261 	}
262 	if (clk) {
263 		cpu_clockrate[0] = clk; /* Tell OS what frequency we run on */
264 		cpu_clockrate[1] = clk / 1000000;
265 	}
266 	sprintf(cpu_model, "%s @ %s MHz, version %d FPU",
267 		PROM_getpropstring(node, "name"),
268 		clockfreq(clk), fver);
269 	printf(": %s\n", cpu_model);
270 
271 	bigcache = 0;
272 
273 	cacheinfo.ic_linesize = l =
274 		PROM_getpropint(node, "icache-line-size", 0);
275 	for (i = 0; (1 << i) < l && l; i++)
276 		/* void */;
277 	if ((1 << i) != l && l)
278 		panic("bad icache line size %d", l);
279 	cacheinfo.ic_l2linesize = i;
280 	cacheinfo.ic_totalsize =
281 		PROM_getpropint(node, "icache-size", 0) *
282 		PROM_getpropint(node, "icache-associativity", 1);
283 	if (cacheinfo.ic_totalsize == 0)
284 		cacheinfo.ic_totalsize = l *
285 			PROM_getpropint(node, "icache-nlines", 64) *
286 			PROM_getpropint(node, "icache-associativity", 1);
287 
288 	cachesize = cacheinfo.ic_totalsize /
289 	    PROM_getpropint(node, "icache-associativity", 1);
290 	bigcache = cachesize;
291 
292 	cacheinfo.dc_linesize = l =
293 		PROM_getpropint(node, "dcache-line-size",0);
294 	for (i = 0; (1 << i) < l && l; i++)
295 		/* void */;
296 	if ((1 << i) != l && l)
297 		panic("bad dcache line size %d", l);
298 	cacheinfo.dc_l2linesize = i;
299 	cacheinfo.dc_totalsize =
300 		PROM_getpropint(node, "dcache-size", 0) *
301 		PROM_getpropint(node, "dcache-associativity", 1);
302 	if (cacheinfo.dc_totalsize == 0)
303 		cacheinfo.dc_totalsize = l *
304 			PROM_getpropint(node, "dcache-nlines", 128) *
305 			PROM_getpropint(node, "dcache-associativity", 1);
306 
307 	cachesize = cacheinfo.dc_totalsize /
308 	    PROM_getpropint(node, "dcache-associativity", 1);
309 	if (cachesize > bigcache)
310 		bigcache = cachesize;
311 
312 	cacheinfo.ec_linesize = l =
313 		PROM_getpropint(node, "ecache-line-size", 0);
314 	for (i = 0; (1 << i) < l && l; i++)
315 		/* void */;
316 	if ((1 << i) != l && l)
317 		panic("bad ecache line size %d", l);
318 	cacheinfo.ec_l2linesize = i;
319 	cacheinfo.ec_totalsize =
320 		PROM_getpropint(node, "ecache-size", 0) *
321 		PROM_getpropint(node, "ecache-associativity", 1);
322 	if (cacheinfo.ec_totalsize == 0)
323 		cacheinfo.ec_totalsize = l *
324 			PROM_getpropint(node, "ecache-nlines", 32768) *
325 			PROM_getpropint(node, "ecache-associativity", 1);
326 
327 	cachesize = cacheinfo.ec_totalsize /
328 	     PROM_getpropint(node, "ecache-associativity", 1);
329 	if (cachesize > bigcache)
330 		bigcache = cachesize;
331 
332 	sep = " ";
333 	printf("%s:", dev->dv_xname);
334 	if (cacheinfo.ic_totalsize > 0) {
335 		printf("%s%ldK instruction (%ld b/l)", sep,
336 		       (long)cacheinfo.ic_totalsize/1024,
337 		       (long)cacheinfo.ic_linesize);
338 		sep = ", ";
339 	}
340 	if (cacheinfo.dc_totalsize > 0) {
341 		printf("%s%ldK data (%ld b/l)", sep,
342 		       (long)cacheinfo.dc_totalsize/1024,
343 		       (long)cacheinfo.dc_linesize);
344 		sep = ", ";
345 	}
346 	if (cacheinfo.ec_totalsize > 0) {
347 		printf("%s%ldK external (%ld b/l)", sep,
348 		       (long)cacheinfo.ec_totalsize/1024,
349 		       (long)cacheinfo.ec_linesize);
350 	}
351 	printf("\n");
352 
353 	/*
354 	 * Now that we know the size of the largest cache on this CPU,
355 	 * re-color our pages.
356 	 */
357 	uvm_page_recolor(atop(bigcache));
358 }
359