xref: /netbsd-src/sys/arch/sparc64/sparc64/cpu.c (revision f81322cf185a4db50f71fcf7701f20198272620e)
1 /*	$NetBSD: cpu.c,v 1.47 2006/02/20 19:00:27 cdi 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/cdefs.h>
55 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.47 2006/02/20 19:00:27 cdi Exp $");
56 
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/device.h>
60 #include <sys/kernel.h>
61 
62 #include <uvm/uvm_extern.h>
63 
64 #include <machine/autoconf.h>
65 #include <machine/cpu.h>
66 #include <machine/reg.h>
67 #include <machine/trap.h>
68 #include <machine/pmap.h>
69 #include <machine/sparc64.h>
70 #include <machine/openfirm.h>
71 
72 #include <sparc64/sparc64/cache.h>
73 
74 /* This is declared here so that you must include a CPU for the cache code. */
75 struct cacheinfo cacheinfo;
76 
77 /* Linked list of all CPUs in system. */
78 int sparc_ncpus = 0;
79 struct cpu_info *cpus = NULL;
80 
81 volatile cpuset_t cpus_active;/* set of active cpus */
82 struct cpu_bootargs *cpu_args;	/* allocated very early in pmap_bootstrap. */
83 
84 static struct cpu_info *alloc_cpuinfo(u_int);
85 
86 /* The following are used externally (sysctl_hw). */
87 char	machine[] = MACHINE;		/* from <machine/param.h> */
88 char	machine_arch[] = MACHINE_ARCH;	/* from <machine/param.h> */
89 char	cpu_model[100];			/* machine model (primary CPU) */
90 extern char machine_model[];
91 
92 /* The CPU configuration driver. */
93 void cpu_attach(struct device *, struct device *, void *);
94 int cpu_match(struct device *, struct cfdata *, void *);
95 
96 CFATTACH_DECL(cpu, sizeof(struct device),
97     cpu_match, cpu_attach, NULL, NULL);
98 
99 extern struct cfdriver cpu_cd;
100 
101 #define	IU_IMPL(v)	((((uint64_t)(v)) & VER_IMPL) >> VER_IMPL_SHIFT)
102 #define	IU_VERS(v)	((((uint64_t)(v)) & VER_MASK) >> VER_MASK_SHIFT)
103 
104 struct cpu_info *
105 alloc_cpuinfo(u_int cpu_node)
106 {
107 	paddr_t pa0, pa;
108 	vaddr_t va, va0;
109 	vsize_t sz = 8 * PAGE_SIZE;
110 	int portid;
111 	struct cpu_info *cpi, *ci;
112 	extern paddr_t cpu0paddr;
113 
114 	/*
115 	 * Check for UPAID in the cpus list.
116 	 */
117 	if (OF_getprop(cpu_node, "upa-portid", &portid, sizeof(portid)) <= 0)
118 		panic("alloc_cpuinfo: upa-portid");
119 
120 	for (cpi = cpus; cpi != NULL; cpi = cpi->ci_next)
121 		if (cpi->ci_upaid == portid)
122 			return cpi;
123 
124 	/* Allocate the aligned VA and determine the size. */
125 	va = uvm_km_alloc(kernel_map, sz, sz, UVM_KMF_VAONLY);
126 	if (!va)
127 		panic("alloc_cpuinfo: no virtual space");
128 	va0 = va;
129 
130 	pa0 = cpu0paddr;
131 	cpu0paddr += sz;
132 
133 	for (pa = pa0; pa < cpu0paddr; pa += PAGE_SIZE, va += PAGE_SIZE)
134 		pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
135 	pmap_update(pmap_kernel());
136 
137 	cpi = (struct cpu_info *)(va0 + CPUINFO_VA - INTSTACK);
138 
139 	memset((void *)va0, 0, sz);
140 
141 	/*
142 	 * Initialize cpuinfo structure.
143 	 *
144 	 * Arrange pcb, idle stack and interrupt stack in the same
145 	 * way as is done for the boot CPU in locore.
146 	 */
147 	cpi->ci_next = NULL;
148 	cpi->ci_curlwp = NULL;
149 	cpi->ci_number = portid;
150 	cpi->ci_cpuid = portid;
151 	cpi->ci_upaid = portid;
152 	cpi->ci_fplwp = NULL;
153 	cpi->ci_spinup = NULL;						/* XXX */
154 	cpi->ci_eintstack = (void *)EINTSTACK; 				/* XXX */
155 	cpi->ci_idle_u = (struct pcb *)(CPUINFO_VA + 2 * PAGE_SIZE); 	/* XXX */
156 	cpi->ci_cpcb = cpi->ci_idle_u;					/* XXX */
157 	cpi->ci_initstack = (void *)((vaddr_t)cpi->ci_idle_u + 2 * PAGE_SIZE); /* XXX */
158 	cpi->ci_paddr = pa0;
159 	cpi->ci_self = cpi;
160 	cpi->ci_node = cpu_node;
161 
162 	/*
163 	 * Finally, add itself to the list of active cpus.
164 	 */
165 	for (ci = cpus; ci->ci_next != NULL; ci = ci->ci_next)
166 		;
167 	ci->ci_next = cpi;
168 	return (cpi);
169 }
170 
171 int
172 cpu_match(struct device *parent, struct cfdata *cf, void *aux)
173 {
174 	struct mainbus_attach_args *ma = aux;
175 
176 	return (strcmp(cf->cf_name, ma->ma_name) == 0);
177 }
178 
179 /*
180  * Attach the CPU.
181  * Discover interesting goop about the virtual address cache
182  * (slightly funny place to do it, but this is where it is to be found).
183  */
184 void
185 cpu_attach(struct device *parent, struct device *dev, void *aux)
186 {
187 	int node;
188 	long clk;
189 	int impl, vers, fver;
190 	struct mainbus_attach_args *ma = aux;
191 	struct fpstate64 *fpstate;
192 	struct fpstate64 fps[2];
193 	const char *sep;
194 	register int i, l;
195 	uint64_t ver;
196 	int bigcache, cachesize;
197 	char buf[100];
198 
199 	/* This needs to be 64-bit aligned */
200 	fpstate = ALIGNFPSTATE(&fps[1]);
201 
202 	/*
203 	 * Get the FSR and clear any exceptions.  If we do not unload
204 	 * the queue here and it is left over from a previous crash, we
205 	 * will panic in the first loadfpstate(), due to a sequence error,
206 	 * so we need to dump the whole state anyway.
207 	 */
208 
209 	fpstate->fs_fsr = 7 << FSR_VER_SHIFT;	/* 7 is reserved for "none" */
210 	savefpstate(fpstate);
211 	fver = (fpstate->fs_fsr >> FSR_VER_SHIFT) & (FSR_VER >> FSR_VER_SHIFT);
212 	ver = getver();
213 	impl = IU_IMPL(ver);
214 	vers = IU_VERS(ver);
215 
216 	/* tell them what we have */
217 	node = ma->ma_node;
218 
219 	clk = prom_getpropint(node, "clock-frequency", 0);
220 	if (clk == 0) {
221 
222 		/*
223 		 * Try to find it in the OpenPROM root...
224 		 */
225 		clk = prom_getpropint(findroot(), "clock-frequency", 0);
226 	}
227 	if (clk) {
228 		cpu_clockrate[0] = clk; /* Tell OS what frequency we run on */
229 		cpu_clockrate[1] = clk / 1000000;
230 	}
231 	snprintf(buf, sizeof buf, "%s @ %s MHz, version %d FPU",
232 		prom_getpropstring(node, "name"),
233 		clockfreq(clk), fver);
234 	printf(": %s\n", buf);
235 	snprintf(cpu_model, sizeof cpu_model, "%s (%s)", machine_model, buf);
236 
237 	bigcache = 0;
238 
239 	cacheinfo.ic_linesize = l =
240 		prom_getpropint(node, "icache-line-size", 0);
241 	for (i = 0; (1 << i) < l && l; i++)
242 		/* void */;
243 	if ((1 << i) != l && l)
244 		panic("bad icache line size %d", l);
245 	cacheinfo.ic_l2linesize = i;
246 	cacheinfo.ic_totalsize =
247 		prom_getpropint(node, "icache-size", 0) *
248 		prom_getpropint(node, "icache-associativity", 1);
249 	if (cacheinfo.ic_totalsize == 0)
250 		cacheinfo.ic_totalsize = l *
251 			prom_getpropint(node, "icache-nlines", 64) *
252 			prom_getpropint(node, "icache-associativity", 1);
253 
254 	cachesize = cacheinfo.ic_totalsize /
255 	    prom_getpropint(node, "icache-associativity", 1);
256 	bigcache = cachesize;
257 
258 	cacheinfo.dc_linesize = l =
259 		prom_getpropint(node, "dcache-line-size",0);
260 	for (i = 0; (1 << i) < l && l; i++)
261 		/* void */;
262 	if ((1 << i) != l && l)
263 		panic("bad dcache line size %d", l);
264 	cacheinfo.dc_l2linesize = i;
265 	cacheinfo.dc_totalsize =
266 		prom_getpropint(node, "dcache-size", 0) *
267 		prom_getpropint(node, "dcache-associativity", 1);
268 	if (cacheinfo.dc_totalsize == 0)
269 		cacheinfo.dc_totalsize = l *
270 			prom_getpropint(node, "dcache-nlines", 128) *
271 			prom_getpropint(node, "dcache-associativity", 1);
272 
273 	cachesize = cacheinfo.dc_totalsize /
274 	    prom_getpropint(node, "dcache-associativity", 1);
275 	if (cachesize > bigcache)
276 		bigcache = cachesize;
277 
278 	cacheinfo.ec_linesize = l =
279 		prom_getpropint(node, "ecache-line-size", 0);
280 	for (i = 0; (1 << i) < l && l; i++)
281 		/* void */;
282 	if ((1 << i) != l && l)
283 		panic("bad ecache line size %d", l);
284 	cacheinfo.ec_l2linesize = i;
285 	cacheinfo.ec_totalsize =
286 		prom_getpropint(node, "ecache-size", 0) *
287 		prom_getpropint(node, "ecache-associativity", 1);
288 	if (cacheinfo.ec_totalsize == 0)
289 		cacheinfo.ec_totalsize = l *
290 			prom_getpropint(node, "ecache-nlines", 32768) *
291 			prom_getpropint(node, "ecache-associativity", 1);
292 
293 	cachesize = cacheinfo.ec_totalsize /
294 	     prom_getpropint(node, "ecache-associativity", 1);
295 	if (cachesize > bigcache)
296 		bigcache = cachesize;
297 
298 	sep = " ";
299 	printf("%s:", dev->dv_xname);
300 	if (cacheinfo.ic_totalsize > 0) {
301 		printf("%s%ldK instruction (%ld b/l)", sep,
302 		       (long)cacheinfo.ic_totalsize/1024,
303 		       (long)cacheinfo.ic_linesize);
304 		sep = ", ";
305 	}
306 	if (cacheinfo.dc_totalsize > 0) {
307 		printf("%s%ldK data (%ld b/l)", sep,
308 		       (long)cacheinfo.dc_totalsize/1024,
309 		       (long)cacheinfo.dc_linesize);
310 		sep = ", ";
311 	}
312 	if (cacheinfo.ec_totalsize > 0) {
313 		printf("%s%ldK external (%ld b/l)", sep,
314 		       (long)cacheinfo.ec_totalsize/1024,
315 		       (long)cacheinfo.ec_linesize);
316 	}
317 	printf("\n");
318 
319 	/*
320 	 * Now that we know the size of the largest cache on this CPU,
321 	 * re-color our pages.
322 	 */
323 	uvm_page_recolor(atop(bigcache)); /* XXX */
324 
325 	/*
326 	 * Allocate cpu_info structure if needed and save cache information
327 	 * in there.
328 	 */
329 	alloc_cpuinfo((u_int)node);
330 	printf("%s: upa id %" PRIu64 "\n", dev->dv_xname, CPU_UPAID);
331 }
332 
333 #if defined(MULTIPROCESSOR)
334 vaddr_t cpu_spinup_trampoline;
335 
336 u_long dump_rtf_info = 0;
337 
338 /*
339  * Start secondary processors in motion.
340  */
341 void
342 cpu_boot_secondary_processors()
343 {
344 	int i, pstate;
345 	struct cpu_info *ci;
346 
347 	sparc64_ipi_init();
348 
349 	printf("cpu0: booting secondary processors:\n");
350 
351 	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
352 		if (ci->ci_upaid == CPU_UPAID)
353 			continue;
354 
355 		cpu_args->cb_node = ci->ci_node;
356 		cpu_args->cb_cpuinfo =  ci->ci_paddr;
357 		cpu_args->cb_initstack = ci->ci_initstack;
358 		membar_sync();
359 
360 #ifdef DEBUG
361 		printf("node %x, cpuinfo %lx, initstack %p\n",
362 		       cpu_args->cb_node, cpu_args->cb_cpuinfo,
363 		       cpu_args->cb_initstack);
364 #endif
365 
366 		/* Disable interrupts and start another CPU. */
367 		pstate = getpstate();
368 		setpstate(PSTATE_KERN);
369 
370 		printf("mp_tramp: %p\n", (void*)cpu_spinup_trampoline);
371 		prom_startcpu(ci->ci_node, (void *)cpu_spinup_trampoline, 0);
372 
373 		for (i = 0; i < 2000; i++) {
374 			membar_sync();
375 			if (CPUSET_HAS(cpus_active, ci->ci_number))
376 				break;
377 			delay(10000);
378 		}
379 		setpstate(pstate);
380 
381 		if (!CPUSET_HAS(cpus_active, ci->ci_number))
382 			printf("cpu%d: startup failed\n", ci->ci_upaid);
383 		else
384 			printf("cpu%d now spinning idle (waited %d iterations)\n",
385 			       ci->ci_upaid, i);
386 	}
387 
388 	printf("\n");
389 }
390 
391 void
392 cpu_hatch()
393 {
394 	int i;
395 	char *v = (char*)CPUINFO_VA;
396 
397 	for (i = 0; i < 4*PAGE_SIZE; i += sizeof(long))
398 		flush(v + i);
399 
400 	dump_rtf_info = 1;
401 
402 	printf("cpu%d fired up.\n", cpu_number());
403 	CPUSET_ADD(cpus_active, cpu_number());
404 	for (i = 0; i < 5000000; i++)
405 		;
406 	printf("cpu%d enters idle loop.\n", cpu_number());
407 	membar_sync();
408 	spl0();
409 }
410 #endif /* MULTIPROCESSOR */
411