1 /* $NetBSD: cpu.c,v 1.42 2005/12/11 12:19:14 christos 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.42 2005/12/11 12:19:14 christos 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