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