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