1 /* $NetBSD: cpu.c,v 1.18 2001/12/31 16:26:10 matt 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/param.h> 55 #include <sys/systm.h> 56 #include <sys/device.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #include <machine/autoconf.h> 61 #include <machine/cpu.h> 62 #include <machine/reg.h> 63 #include <machine/trap.h> 64 #include <machine/pmap.h> 65 66 #include <sparc64/sparc64/cache.h> 67 68 /* This is declared here so that you must include a CPU for the cache code. */ 69 struct cacheinfo cacheinfo; 70 71 /* Our exported CPU info; we have only one for now. */ 72 struct cpu_info cpu_info_store; 73 74 /* Linked list of all CPUs in system. */ 75 struct cpu_info *cpus = NULL; 76 77 /* The following are used externally (sysctl_hw). */ 78 char machine[] = MACHINE; /* from <machine/param.h> */ 79 char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */ 80 char cpu_model[100]; 81 82 /* The CPU configuration driver. */ 83 static void cpu_attach __P((struct device *, struct device *, void *)); 84 int cpu_match __P((struct device *, struct cfdata *, void *)); 85 86 struct cfattach cpu_ca = { 87 sizeof(struct device), cpu_match, cpu_attach 88 }; 89 90 extern struct cfdriver cpu_cd; 91 92 #if defined(SUN4C) || defined(SUN4M) 93 static char *psrtoname __P((int, int, int, char *)); 94 #endif 95 static char *fsrtoname __P((int, int, int, char *)); 96 97 #define IU_IMPL(v) ((((u_int64_t)(v))&VER_IMPL) >> VER_IMPL_SHIFT) 98 #define IU_VERS(v) ((((u_int64_t)(v))&VER_MASK) >> VER_MASK_SHIFT) 99 100 #ifdef notdef 101 /* 102 * IU implementations are parceled out to vendors (with some slight 103 * glitches). Printing these is cute but takes too much space. 104 */ 105 static char *iu_vendor[16] = { 106 "Fujitsu", /* and also LSI Logic */ 107 "ROSS", /* ROSS (ex-Cypress) */ 108 "BIT", 109 "LSIL", /* LSI Logic finally got their own */ 110 "TI", /* Texas Instruments */ 111 "Matsushita", 112 "Philips", 113 "Harvest", /* Harvest VLSI Design Center */ 114 "SPEC", /* Systems and Processes Engineering Corporation */ 115 "Weitek", 116 "vendor#10", 117 "vendor#11", 118 "vendor#12", 119 "vendor#13", 120 "vendor#14", 121 "vendor#15" 122 }; 123 #endif 124 125 /* 126 * Overhead involved in firing up a new CPU: 127 * 128 * Allocate a cpuinfo/interrupt stack 129 * Map that into the kernel 130 * Initialize the cpuinfo 131 * Return the TLB entry for the cpuinfo. 132 */ 133 u_int64_t 134 cpu_init(pa, cpu_num) 135 paddr_t pa; 136 int cpu_num; 137 { 138 struct cpu_info *ci; 139 u_int64_t pagesize; 140 u_int64_t pte; 141 struct vm_page *m; 142 psize_t size; 143 vaddr_t va; 144 struct pglist mlist; 145 int error; 146 147 size = NBPG; /* XXXX 8K, 64K, 512K, or 4MB */ 148 TAILQ_INIT(&mlist); 149 if ((error = uvm_pglistalloc((psize_t)size, (paddr_t)0, (paddr_t)-1, 150 (paddr_t)size, (paddr_t)0, &mlist, 1, 0)) != 0) 151 panic("cpu_start: no memory, error %d", error); 152 153 va = uvm_km_valloc(kernel_map, size); 154 if (va == 0) 155 panic("cpu_start: no memory"); 156 157 m = TAILQ_FIRST(&mlist); 158 pa = VM_PAGE_TO_PHYS(m); 159 pte = TSB_DATA(0 /* global */, 160 pagesize, 161 pa, 162 1 /* priv */, 163 1 /* Write */, 164 1 /* Cacheable */, 165 1 /* ALIAS -- Disable D$ */, 166 1 /* valid */, 167 0 /* IE */); 168 169 /* Map the pages */ 170 for (; m != NULL; m = TAILQ_NEXT(m,pageq)) { 171 pa = VM_PAGE_TO_PHYS(m); 172 pmap_zero_page(pa); 173 pmap_enter(pmap_kernel(), va, pa | PMAP_NVC, 174 VM_PROT_READ|VM_PROT_WRITE, 175 VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); 176 va += NBPG; 177 } 178 pmap_update(pmap_kernel()); 179 180 if (!cpus) cpus = (struct cpu_info *)va; 181 else { 182 for (ci = cpus; ci->ci_next; ci=ci->ci_next); 183 ci->ci_next = (struct cpu_info *)va; 184 } 185 186 switch (size) { 187 #define K *1024 188 case 8 K: 189 pagesize = TLB_8K; 190 break; 191 case 64 K: 192 pagesize = TLB_64K; 193 break; 194 case 512 K: 195 pagesize = TLB_512K; 196 break; 197 case 4 K K: 198 pagesize = TLB_4M; 199 break; 200 default: 201 panic("cpu_start: stack size %x not a machine page size\n", 202 (unsigned)size); 203 } 204 return (pte|TLB_L); 205 } 206 207 208 int 209 cpu_match(parent, cf, aux) 210 struct device *parent; 211 struct cfdata *cf; 212 void *aux; 213 { 214 struct mainbus_attach_args *ma = aux; 215 216 return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0); 217 } 218 219 /* 220 * Attach the CPU. 221 * Discover interesting goop about the virtual address cache 222 * (slightly funny place to do it, but this is where it is to be found). 223 */ 224 static void 225 cpu_attach(parent, dev, aux) 226 struct device *parent; 227 struct device *dev; 228 void *aux; 229 { 230 int node; 231 long clk; 232 int impl, vers, fver; 233 char *fpuname; 234 struct mainbus_attach_args *ma = aux; 235 struct fpstate64 *fpstate; 236 struct fpstate64 fps[2]; 237 char *sep; 238 char fpbuf[40]; 239 register int i, l; 240 u_int64_t ver; 241 int bigcache, cachesize; 242 extern u_int64_t cpu_clockrate[]; 243 244 /* This needs to be 64-bit aligned */ 245 fpstate = ALIGNFPSTATE(&fps[1]); 246 /* 247 * Get the FSR and clear any exceptions. If we do not unload 248 * the queue here and it is left over from a previous crash, we 249 * will panic in the first loadfpstate(), due to a sequence error, 250 * so we need to dump the whole state anyway. 251 * 252 * If there is no FPU, trap.c will advance over all the stores, 253 * so we initialize fs_fsr here. 254 */ 255 fpstate->fs_fsr = 7 << FSR_VER_SHIFT; /* 7 is reserved for "none" */ 256 savefpstate(fpstate); 257 fver = (fpstate->fs_fsr >> FSR_VER_SHIFT) & (FSR_VER >> FSR_VER_SHIFT); 258 ver = getver(); 259 impl = IU_IMPL(ver); 260 vers = IU_VERS(ver); 261 if (fver != 7) { 262 foundfpu = 1; 263 fpuname = fsrtoname(impl, vers, fver, fpbuf); 264 } else 265 fpuname = "no"; 266 267 /* tell them what we have */ 268 node = ma->ma_node; 269 270 clk = PROM_getpropint(node, "clock-frequency", 0); 271 if (clk == 0) { 272 /* 273 * Try to find it in the OpenPROM root... 274 */ 275 clk = PROM_getpropint(findroot(), "clock-frequency", 0); 276 } 277 if (clk) { 278 cpu_clockrate[0] = clk; /* Tell OS what frequency we run on */ 279 cpu_clockrate[1] = clk/1000000; 280 } 281 sprintf(cpu_model, "%s @ %s MHz, %s FPU", 282 PROM_getpropstring(node, "name"), 283 clockfreq(clk), fpuname); 284 printf(": %s\n", cpu_model); 285 286 bigcache = 0; 287 288 cacheinfo.c_physical = 1; /* Dunno... */ 289 cacheinfo.c_split = 1; 290 cacheinfo.ic_linesize = l = PROM_getpropint(node, "icache-line-size", 0); 291 for (i = 0; (1 << i) < l && l; i++) 292 /* void */; 293 if ((1 << i) != l && l) 294 panic("bad icache line size %d", l); 295 cacheinfo.ic_l2linesize = i; 296 cacheinfo.ic_totalsize = 297 PROM_getpropint(node, "icache-size", 0) * 298 PROM_getpropint(node, "icache-associativity", 1); 299 if (cacheinfo.ic_totalsize == 0) 300 cacheinfo.ic_totalsize = l * 301 PROM_getpropint(node, "icache-nlines", 64) * 302 PROM_getpropint(node, "icache-associativity", 1); 303 304 cachesize = cacheinfo.ic_totalsize / 305 PROM_getpropint(node, "icache-associativity", 1); 306 bigcache = cachesize; 307 308 cacheinfo.dc_linesize = l = 309 PROM_getpropint(node, "dcache-line-size",0); 310 for (i = 0; (1 << i) < l && l; i++) 311 /* void */; 312 if ((1 << i) != l && l) 313 panic("bad dcache line size %d", l); 314 cacheinfo.dc_l2linesize = i; 315 cacheinfo.dc_totalsize = 316 PROM_getpropint(node, "dcache-size", 0) * 317 PROM_getpropint(node, "dcache-associativity", 1); 318 if (cacheinfo.dc_totalsize == 0) 319 cacheinfo.dc_totalsize = l * 320 PROM_getpropint(node, "dcache-nlines", 128) * 321 PROM_getpropint(node, "dcache-associativity", 1); 322 323 cachesize = cacheinfo.dc_totalsize / 324 PROM_getpropint(node, "dcache-associativity", 1); 325 if (cachesize > bigcache) 326 bigcache = cachesize; 327 328 cacheinfo.ec_linesize = l = 329 PROM_getpropint(node, "ecache-line-size", 0); 330 for (i = 0; (1 << i) < l && l; i++) 331 /* void */; 332 if ((1 << i) != l && l) 333 panic("bad ecache line size %d", l); 334 cacheinfo.ec_l2linesize = i; 335 cacheinfo.ec_totalsize = 336 PROM_getpropint(node, "ecache-size", 0) * 337 PROM_getpropint(node, "ecache-associativity", 1); 338 if (cacheinfo.ec_totalsize == 0) 339 cacheinfo.ec_totalsize = l * 340 PROM_getpropint(node, "ecache-nlines", 32768) * 341 PROM_getpropint(node, "ecache-associativity", 1); 342 343 cachesize = cacheinfo.ec_totalsize / 344 PROM_getpropint(node, "ecache-associativity", 1); 345 if (cachesize > bigcache) 346 bigcache = cachesize; 347 348 /* 349 * XXX - The following will have to do until 350 * we have per-cpu cache handling. 351 */ 352 cacheinfo.c_l2linesize = 353 min(cacheinfo.ic_l2linesize, 354 cacheinfo.dc_l2linesize); 355 cacheinfo.c_linesize = 356 min(cacheinfo.ic_linesize, 357 cacheinfo.dc_linesize); 358 cacheinfo.c_totalsize = 359 cacheinfo.ic_totalsize + 360 cacheinfo.dc_totalsize; 361 362 if (cacheinfo.c_totalsize == 0) 363 return; 364 365 sep = " "; 366 printf("%s: physical", dev->dv_xname); 367 if (cacheinfo.ic_totalsize > 0) { 368 printf("%s%ldK instruction (%ld b/l)", sep, 369 (long)cacheinfo.ic_totalsize/1024, 370 (long)cacheinfo.ic_linesize); 371 sep = ", "; 372 } 373 if (cacheinfo.dc_totalsize > 0) { 374 printf("%s%ldK data (%ld b/l)", sep, 375 (long)cacheinfo.dc_totalsize/1024, 376 (long)cacheinfo.dc_linesize); 377 sep = ", "; 378 } 379 if (cacheinfo.ec_totalsize > 0) { 380 printf("%s%ldK external (%ld b/l)", sep, 381 (long)cacheinfo.ec_totalsize/1024, 382 (long)cacheinfo.ec_linesize); 383 } 384 printf("\n"); 385 cache_enable(); 386 387 /* 388 * Now that we know the size of the largest cache on this CPU, 389 * re-color our pages. 390 */ 391 uvm_page_recolor(atop(bigcache)); 392 } 393 394 /* 395 * The following tables convert <IU impl, IU version, FPU version> triples 396 * into names for the CPU and FPU chip. In most cases we do not need to 397 * inspect the FPU version to name the IU chip, but there is one exception 398 * (for Tsunami), and this makes the tables the same. 399 * 400 * The table contents (and much of the structure here) are from Guy Harris. 401 * 402 */ 403 struct info { 404 u_char valid; 405 u_char iu_impl; 406 u_char iu_vers; 407 u_char fpu_vers; 408 char *name; 409 }; 410 411 #define ANY 0xff /* match any FPU version (or, later, IU version) */ 412 413 #if defined(SUN4C) || defined(SUN4M) 414 static struct info iu_types[] = { 415 { 1, 0x0, 0x4, 4, "MB86904" }, 416 { 1, 0x0, 0x0, ANY, "MB86900/1A or L64801" }, 417 { 1, 0x1, 0x0, ANY, "RT601 or L64811 v1" }, 418 { 1, 0x1, 0x1, ANY, "RT601 or L64811 v2" }, 419 { 1, 0x1, 0x3, ANY, "RT611" }, 420 { 1, 0x1, 0xf, ANY, "RT620" }, 421 { 1, 0x2, 0x0, ANY, "B5010" }, 422 { 1, 0x4, 0x0, 0, "TMS390Z50 v0 or TMS390Z55" }, 423 { 1, 0x4, 0x1, 0, "TMS390Z50 v1" }, 424 { 1, 0x4, 0x1, 4, "TMS390S10" }, 425 { 1, 0x5, 0x0, ANY, "MN10501" }, 426 { 1, 0x9, 0x0, ANY, "W8601/8701 or MB86903" }, 427 { 0 } 428 }; 429 430 static char * 431 psrtoname(impl, vers, fver, buf) 432 register int impl, vers, fver; 433 char *buf; 434 { 435 register struct info *p; 436 437 for (p = iu_types; p->valid; p++) 438 if (p->iu_impl == impl && p->iu_vers == vers && 439 (p->fpu_vers == fver || p->fpu_vers == ANY)) 440 return (p->name); 441 442 /* Not found. */ 443 sprintf(buf, "IU impl 0x%x vers 0x%x", impl, vers); 444 return (buf); 445 } 446 #endif /* SUN4C || SUN4M */ 447 448 /* NB: table order matters here; specific numbers must appear before ANY. */ 449 static struct info fpu_types[] = { 450 /* 451 * Vendor 0, IU Fujitsu0. 452 */ 453 { 1, 0x0, ANY, 0, "MB86910 or WTL1164/5" }, 454 { 1, 0x0, ANY, 1, "MB86911 or WTL1164/5" }, 455 { 1, 0x0, ANY, 2, "L64802 or ACT8847" }, 456 { 1, 0x0, ANY, 3, "WTL3170/2" }, 457 { 1, 0x0, 4, 4, "on-chip" }, /* Swift */ 458 { 1, 0x0, ANY, 4, "L64804" }, 459 460 /* 461 * Vendor 1, IU ROSS0/1 or Pinnacle. 462 */ 463 { 1, 0x1, 0xf, 0, "on-chip" }, /* Pinnacle */ 464 { 1, 0x1, ANY, 0, "L64812 or ACT8847" }, 465 { 1, 0x1, ANY, 1, "L64814" }, 466 { 1, 0x1, ANY, 2, "TMS390C602A" }, 467 { 1, 0x1, ANY, 3, "RT602 or WTL3171" }, 468 469 /* 470 * Vendor 2, IU BIT0. 471 */ 472 { 1, 0x2, ANY, 0, "B5010 or B5110/20 or B5210" }, 473 474 /* 475 * Vendor 4, Texas Instruments. 476 */ 477 { 1, 0x4, ANY, 0, "on-chip" }, /* Viking */ 478 { 1, 0x4, ANY, 4, "on-chip" }, /* Tsunami */ 479 480 /* 481 * Vendor 5, IU Matsushita0. 482 */ 483 { 1, 0x5, ANY, 0, "on-chip" }, 484 485 /* 486 * Vendor 9, Weitek. 487 */ 488 { 1, 0x9, ANY, 3, "on-chip" }, 489 490 { 0 } 491 }; 492 493 static char * 494 fsrtoname(impl, vers, fver, buf) 495 register int impl, vers, fver; 496 char *buf; 497 { 498 register struct info *p; 499 500 for (p = fpu_types; p->valid; p++) 501 if (p->iu_impl == impl && 502 (p->iu_vers == vers || p->iu_vers == ANY) && 503 (p->fpu_vers == fver)) 504 return (p->name); 505 sprintf(buf, "version %x", fver); 506 return (buf); 507 } 508