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