1 /* $NetBSD: cpu.c,v 1.65 2007/12/09 20:12:54 martin 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.65 2007/12/09 20:12:54 martin 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 int ecache_min_line_size; 75 76 /* Linked list of all CPUs in system. */ 77 int sparc_ncpus = 0; 78 struct cpu_info *cpus = NULL; 79 80 volatile cpuset_t cpus_active;/* set of active cpus */ 81 struct cpu_bootargs *cpu_args; /* allocated very early in pmap_bootstrap. */ 82 83 static struct cpu_info *alloc_cpuinfo(u_int); 84 85 /* The following are used externally (sysctl_hw). */ 86 char machine[] = MACHINE; /* from <machine/param.h> */ 87 char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */ 88 char cpu_model[100]; /* machine model (primary CPU) */ 89 extern char machine_model[]; 90 91 static void cpu_reset_fpustate(void); 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 struct cpu_info * 101 alloc_cpuinfo(u_int cpu_node) 102 { 103 paddr_t pa0, pa; 104 vaddr_t va, va0; 105 vsize_t sz = 8 * PAGE_SIZE; 106 int portid; 107 struct cpu_info *cpi, *ci; 108 extern paddr_t cpu0paddr; 109 110 /* 111 * Check for UPAID in the cpus list. 112 */ 113 if (OF_getprop(cpu_node, "upa-portid", &portid, sizeof(portid)) <= 0) 114 panic("alloc_cpuinfo: upa-portid"); 115 116 for (cpi = cpus; cpi != NULL; cpi = cpi->ci_next) 117 if (cpi->ci_cpuid == portid) 118 return cpi; 119 120 /* Allocate the aligned VA and determine the size. */ 121 va = uvm_km_alloc(kernel_map, sz, 8 * PAGE_SIZE, UVM_KMF_VAONLY); 122 if (!va) 123 panic("alloc_cpuinfo: no virtual space"); 124 va0 = va; 125 126 pa0 = cpu0paddr; 127 cpu0paddr += sz; 128 129 for (pa = pa0; pa < cpu0paddr; pa += PAGE_SIZE, va += PAGE_SIZE) 130 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); 131 132 pmap_update(pmap_kernel()); 133 134 cpi = (struct cpu_info *)(va0 + CPUINFO_VA - INTSTACK); 135 136 memset((void *)va0, 0, sz); 137 138 /* 139 * Initialize cpuinfo structure. 140 * 141 * Arrange pcb, idle stack and interrupt stack in the same 142 * way as is done for the boot CPU in pmap.c. 143 */ 144 cpi->ci_next = NULL; 145 cpi->ci_curlwp = NULL; 146 cpi->ci_cpuid = portid; 147 cpi->ci_fplwp = NULL; 148 cpi->ci_spinup = NULL; 149 cpi->ci_paddr = pa0; 150 cpi->ci_self = cpi; 151 cpi->ci_node = cpu_node; 152 cpi->ci_idepth = -1; 153 154 /* 155 * Finally, add itself to the list of active cpus. 156 */ 157 for (ci = cpus; ci->ci_next != NULL; ci = ci->ci_next) 158 ; 159 ci->ci_next = cpi; 160 return (cpi); 161 } 162 163 int 164 cpu_match(struct device *parent, struct cfdata *cf, void *aux) 165 { 166 struct mainbus_attach_args *ma = aux; 167 168 return (strcmp(cf->cf_name, ma->ma_name) == 0); 169 } 170 171 static void 172 cpu_reset_fpustate(void) 173 { 174 struct fpstate64 *fpstate; 175 struct fpstate64 fps[2]; 176 177 /* This needs to be 64-bit aligned */ 178 fpstate = ALIGNFPSTATE(&fps[1]); 179 180 /* 181 * Get the FSR and clear any exceptions. If we do not unload 182 * the queue here and it is left over from a previous crash, we 183 * will panic in the first loadfpstate(), due to a sequence error, 184 * so we need to dump the whole state anyway. 185 */ 186 fpstate->fs_fsr = 7 << FSR_VER_SHIFT; /* 7 is reserved for "none" */ 187 savefpstate(fpstate); 188 } 189 190 /* 191 * Attach the CPU. 192 * Discover interesting goop about the virtual address cache 193 * (slightly funny place to do it, but this is where it is to be found). 194 */ 195 void 196 cpu_attach(struct device *parent, struct device *dev, void *aux) 197 { 198 int node; 199 long clk; 200 struct mainbus_attach_args *ma = aux; 201 struct cpu_info *ci; 202 const char *sep; 203 register int i, l; 204 int bigcache, cachesize; 205 char buf[100]; 206 int totalsize = 0; 207 int linesize; 208 static bool passed = false; 209 210 /* tell them what we have */ 211 node = ma->ma_node; 212 213 /* 214 * Allocate cpu_info structure if needed. 215 */ 216 ci = alloc_cpuinfo((u_int)node); 217 218 /* 219 * Only do this on the boot cpu. Other cpu's call 220 * cpu_reset_fpustate() from cpu_hatch() before they 221 * call into the idle loop. 222 * For other cpus, we need to call mi_cpu_attach() 223 * and complete setting up cpcb. 224 */ 225 if (!passed) { 226 passed = true; 227 cpu_reset_fpustate(); 228 } 229 #ifdef MULTIPROCESSOR 230 else { 231 mi_cpu_attach(ci); 232 ci->ci_cpcb = (struct pcb *)ci->ci_data.cpu_idlelwp->l_addr; 233 } 234 #endif 235 236 clk = prom_getpropint(node, "clock-frequency", 0); 237 if (clk == 0) { 238 /* 239 * Try to find it in the OpenPROM root... 240 */ 241 clk = prom_getpropint(findroot(), "clock-frequency", 0); 242 } 243 if (clk) { 244 /* Tell OS what frequency we run on */ 245 ci->ci_cpu_clockrate[0] = clk; 246 ci->ci_cpu_clockrate[1] = clk / 1000000; 247 } 248 249 snprintf(buf, sizeof buf, "%s @ %s MHz", 250 prom_getpropstring(node, "name"), clockfreq(clk)); 251 snprintf(cpu_model, sizeof cpu_model, "%s (%s)", machine_model, buf); 252 253 printf(": %s, UPA id %d\n", buf, ci->ci_cpuid); 254 printf("%s:", dev->dv_xname); 255 256 bigcache = 0; 257 258 linesize = l = 259 prom_getpropint(node, "icache-line-size", 0); 260 for (i = 0; (1 << i) < l && l; i++) 261 /* void */; 262 if ((1 << i) != l && l) 263 panic("bad icache line size %d", l); 264 totalsize = 265 prom_getpropint(node, "icache-size", 0) * 266 prom_getpropint(node, "icache-associativity", 1); 267 if (totalsize == 0) 268 totalsize = l * 269 prom_getpropint(node, "icache-nlines", 64) * 270 prom_getpropint(node, "icache-associativity", 1); 271 272 cachesize = totalsize / 273 prom_getpropint(node, "icache-associativity", 1); 274 bigcache = cachesize; 275 276 sep = " "; 277 if (totalsize > 0) { 278 printf("%s%ldK instruction (%ld b/l)", sep, 279 (long)totalsize/1024, 280 (long)linesize); 281 sep = ", "; 282 } 283 284 linesize = l = 285 prom_getpropint(node, "dcache-line-size",0); 286 for (i = 0; (1 << i) < l && l; i++) 287 /* void */; 288 if ((1 << i) != l && l) 289 panic("bad dcache line size %d", l); 290 totalsize = 291 prom_getpropint(node, "dcache-size", 0) * 292 prom_getpropint(node, "dcache-associativity", 1); 293 if (totalsize == 0) 294 totalsize = l * 295 prom_getpropint(node, "dcache-nlines", 128) * 296 prom_getpropint(node, "dcache-associativity", 1); 297 298 cachesize = totalsize / 299 prom_getpropint(node, "dcache-associativity", 1); 300 if (cachesize > bigcache) 301 bigcache = cachesize; 302 303 if (totalsize > 0) { 304 printf("%s%ldK data (%ld b/l)", sep, 305 (long)totalsize/1024, 306 (long)linesize); 307 sep = ", "; 308 } 309 310 linesize = l = 311 prom_getpropint(node, "ecache-line-size", 0); 312 for (i = 0; (1 << i) < l && l; i++) 313 /* void */; 314 if ((1 << i) != l && l) 315 panic("bad ecache line size %d", l); 316 totalsize = 317 prom_getpropint(node, "ecache-size", 0) * 318 prom_getpropint(node, "ecache-associativity", 1); 319 if (totalsize == 0) 320 totalsize = l * 321 prom_getpropint(node, "ecache-nlines", 32768) * 322 prom_getpropint(node, "ecache-associativity", 1); 323 324 cachesize = totalsize / 325 prom_getpropint(node, "ecache-associativity", 1); 326 if (cachesize > bigcache) 327 bigcache = cachesize; 328 329 if (totalsize > 0) { 330 printf("%s%ldK external (%ld b/l)", sep, 331 (long)totalsize/1024, 332 (long)linesize); 333 } 334 printf("\n"); 335 336 if (ecache_min_line_size == 0 || 337 linesize < ecache_min_line_size) 338 ecache_min_line_size = linesize; 339 340 /* 341 * Now that we know the size of the largest cache on this CPU, 342 * re-color our pages. 343 */ 344 uvm_page_recolor(atop(bigcache)); /* XXX */ 345 346 } 347 348 #if defined(MULTIPROCESSOR) 349 vaddr_t cpu_spinup_trampoline; 350 351 /* 352 * Start secondary processors in motion. 353 */ 354 void 355 cpu_boot_secondary_processors() 356 { 357 int i, pstate; 358 struct cpu_info *ci; 359 360 sparc64_ipi_init(); 361 362 for (ci = cpus; ci != NULL; ci = ci->ci_next) { 363 if (ci->ci_cpuid == CPU_UPAID) 364 continue; 365 366 cpu_args->cb_node = ci->ci_node; 367 cpu_args->cb_cpuinfo = ci->ci_paddr; 368 membar_sync(); 369 370 /* Disable interrupts and start another CPU. */ 371 pstate = getpstate(); 372 setpstate(PSTATE_KERN); 373 374 prom_startcpu(ci->ci_node, (void *)cpu_spinup_trampoline, 0); 375 376 for (i = 0; i < 2000; i++) { 377 membar_sync(); 378 if (CPUSET_HAS(cpus_active, ci->ci_index)) 379 break; 380 delay(10000); 381 } 382 setpstate(pstate); 383 384 if (!CPUSET_HAS(cpus_active, ci->ci_index)) 385 printf("cpu%d: startup failed\n", ci->ci_cpuid); 386 } 387 } 388 389 void 390 cpu_hatch() 391 { 392 extern void tickintr_establish(void); 393 char *v = (char*)CPUINFO_VA; 394 int i; 395 396 for (i = 0; i < 4*PAGE_SIZE; i += sizeof(long)) 397 flush(v + i); 398 399 CPUSET_ADD(cpus_active, cpu_number()); 400 cpu_reset_fpustate(); 401 curlwp = curcpu()->ci_data.cpu_idlelwp; 402 membar_sync(); 403 spl0(); 404 405 #if 0 406 tickintr_establish(); 407 #endif 408 } 409 #endif /* MULTIPROCESSOR */ 410