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