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