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