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