1 /* $NetBSD: cpu.c,v 1.29 2003/04/01 16:34:59 thorpej 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]; /* machine model (primary cpu) */ 81 extern char machine_model[]; 82 83 /* The CPU configuration driver. */ 84 static void cpu_attach __P((struct device *, struct device *, void *)); 85 int cpu_match __P((struct device *, struct cfdata *, void *)); 86 87 CFATTACH_DECL(cpu, sizeof(struct device), 88 cpu_match, cpu_attach, NULL, NULL); 89 90 extern struct cfdriver cpu_cd; 91 92 #define IU_IMPL(v) ((((uint64_t)(v)) & VER_IMPL) >> VER_IMPL_SHIFT) 93 #define IU_VERS(v) ((((uint64_t)(v)) & VER_MASK) >> VER_MASK_SHIFT) 94 95 #ifdef notdef 96 /* 97 * IU implementations are parceled out to vendors (with some slight 98 * glitches). Printing these is cute but takes too much space. 99 */ 100 static char *iu_vendor[16] = { 101 "Fujitsu", /* and also LSI Logic */ 102 "ROSS", /* ROSS (ex-Cypress) */ 103 "BIT", 104 "LSIL", /* LSI Logic finally got their own */ 105 "TI", /* Texas Instruments */ 106 "Matsushita", 107 "Philips", 108 "Harvest", /* Harvest VLSI Design Center */ 109 "SPEC", /* Systems and Processes Engineering Corporation */ 110 "Weitek", 111 "vendor#10", 112 "vendor#11", 113 "vendor#12", 114 "vendor#13", 115 "vendor#14", 116 "vendor#15" 117 }; 118 #endif 119 120 /* 121 * Overhead involved in firing up a new CPU: 122 * 123 * Allocate a cpuinfo/interrupt stack 124 * Map that into the kernel 125 * Initialize the cpuinfo 126 * Return the TLB entry for the cpuinfo. 127 */ 128 uint64_t 129 cpu_init(pa, cpu_num) 130 paddr_t pa; 131 int cpu_num; 132 { 133 struct cpu_info *ci; 134 uint64_t pagesize; 135 uint64_t pte; 136 struct vm_page *pg; 137 psize_t size; 138 vaddr_t va; 139 struct pglist pglist; 140 int error; 141 142 size = PAGE_SIZE; /* XXXX 8K, 64K, 512K, or 4MB */ 143 if ((error = uvm_pglistalloc(size, (paddr_t)0, (paddr_t)-1, 144 (paddr_t)size, (paddr_t)0, &pglist, 1, 0)) != 0) 145 panic("cpu_start: no memory, error %d", error); 146 147 va = uvm_km_valloc(kernel_map, size); 148 if (va == 0) 149 panic("cpu_start: no memory"); 150 151 pg = TAILQ_FIRST(&pglist); 152 pa = VM_PAGE_TO_PHYS(pg); 153 pte = TSB_DATA(0 /* global */, 154 pagesize, 155 pa, 156 1 /* priv */, 157 1 /* Write */, 158 1 /* Cacheable */, 159 1 /* ALIAS -- Disable D$ */, 160 1 /* valid */, 161 0 /* IE */); 162 163 /* Map the pages */ 164 for (; pg != NULL; pg = TAILQ_NEXT(pg, pageq)) { 165 pa = VM_PAGE_TO_PHYS(pg); 166 pmap_zero_page(pa); 167 pmap_kenter_pa(va, pa | PMAP_NVC, VM_PROT_READ | VM_PROT_WRITE); 168 va += PAGE_SIZE; 169 } 170 pmap_update(pmap_kernel()); 171 172 if (!cpus) 173 cpus = (struct cpu_info *)va; 174 else { 175 for (ci = cpus; ci->ci_next; ci = ci->ci_next) 176 ; 177 ci->ci_next = (struct cpu_info *)va; 178 } 179 180 switch (size) { 181 #define K *1024 182 case 8 K: 183 pagesize = TLB_8K; 184 break; 185 case 64 K: 186 pagesize = TLB_64K; 187 break; 188 case 512 K: 189 pagesize = TLB_512K; 190 break; 191 case 4 K K: 192 pagesize = TLB_4M; 193 break; 194 default: 195 panic("cpu_start: stack size %x not a machine page size", 196 (unsigned)size); 197 } 198 return (pte | TLB_L); 199 } 200 201 int 202 cpu_match(parent, cf, aux) 203 struct device *parent; 204 struct cfdata *cf; 205 void *aux; 206 { 207 struct mainbus_attach_args *ma = aux; 208 209 return (strcmp(cf->cf_name, ma->ma_name) == 0); 210 } 211 212 /* 213 * Attach the CPU. 214 * Discover interesting goop about the virtual address cache 215 * (slightly funny place to do it, but this is where it is to be found). 216 */ 217 static void 218 cpu_attach(parent, dev, aux) 219 struct device *parent; 220 struct device *dev; 221 void *aux; 222 { 223 int node; 224 long clk; 225 int impl, vers, fver; 226 struct mainbus_attach_args *ma = aux; 227 struct fpstate64 *fpstate; 228 struct fpstate64 fps[2]; 229 char *sep; 230 register int i, l; 231 uint64_t ver; 232 int bigcache, cachesize; 233 char buf[100]; 234 235 /* This needs to be 64-bit aligned */ 236 fpstate = ALIGNFPSTATE(&fps[1]); 237 238 /* 239 * Get the FSR and clear any exceptions. If we do not unload 240 * the queue here and it is left over from a previous crash, we 241 * will panic in the first loadfpstate(), due to a sequence error, 242 * so we need to dump the whole state anyway. 243 */ 244 245 fpstate->fs_fsr = 7 << FSR_VER_SHIFT; /* 7 is reserved for "none" */ 246 savefpstate(fpstate); 247 fver = (fpstate->fs_fsr >> FSR_VER_SHIFT) & (FSR_VER >> FSR_VER_SHIFT); 248 ver = getver(); 249 impl = IU_IMPL(ver); 250 vers = IU_VERS(ver); 251 252 /* tell them what we have */ 253 node = ma->ma_node; 254 255 clk = PROM_getpropint(node, "clock-frequency", 0); 256 if (clk == 0) { 257 258 /* 259 * Try to find it in the OpenPROM root... 260 */ 261 clk = PROM_getpropint(findroot(), "clock-frequency", 0); 262 } 263 if (clk) { 264 cpu_clockrate[0] = clk; /* Tell OS what frequency we run on */ 265 cpu_clockrate[1] = clk / 1000000; 266 } 267 snprintf(buf, sizeof buf, "%s @ %s MHz, version %d FPU", 268 PROM_getpropstring(node, "name"), 269 clockfreq(clk), fver); 270 printf(": %s\n", buf); 271 snprintf(cpu_model, sizeof cpu_model, "%s (%s)", machine_model, buf); 272 273 bigcache = 0; 274 275 cacheinfo.ic_linesize = l = 276 PROM_getpropint(node, "icache-line-size", 0); 277 for (i = 0; (1 << i) < l && l; i++) 278 /* void */; 279 if ((1 << i) != l && l) 280 panic("bad icache line size %d", l); 281 cacheinfo.ic_l2linesize = i; 282 cacheinfo.ic_totalsize = 283 PROM_getpropint(node, "icache-size", 0) * 284 PROM_getpropint(node, "icache-associativity", 1); 285 if (cacheinfo.ic_totalsize == 0) 286 cacheinfo.ic_totalsize = l * 287 PROM_getpropint(node, "icache-nlines", 64) * 288 PROM_getpropint(node, "icache-associativity", 1); 289 290 cachesize = cacheinfo.ic_totalsize / 291 PROM_getpropint(node, "icache-associativity", 1); 292 bigcache = cachesize; 293 294 cacheinfo.dc_linesize = l = 295 PROM_getpropint(node, "dcache-line-size",0); 296 for (i = 0; (1 << i) < l && l; i++) 297 /* void */; 298 if ((1 << i) != l && l) 299 panic("bad dcache line size %d", l); 300 cacheinfo.dc_l2linesize = i; 301 cacheinfo.dc_totalsize = 302 PROM_getpropint(node, "dcache-size", 0) * 303 PROM_getpropint(node, "dcache-associativity", 1); 304 if (cacheinfo.dc_totalsize == 0) 305 cacheinfo.dc_totalsize = l * 306 PROM_getpropint(node, "dcache-nlines", 128) * 307 PROM_getpropint(node, "dcache-associativity", 1); 308 309 cachesize = cacheinfo.dc_totalsize / 310 PROM_getpropint(node, "dcache-associativity", 1); 311 if (cachesize > bigcache) 312 bigcache = cachesize; 313 314 cacheinfo.ec_linesize = l = 315 PROM_getpropint(node, "ecache-line-size", 0); 316 for (i = 0; (1 << i) < l && l; i++) 317 /* void */; 318 if ((1 << i) != l && l) 319 panic("bad ecache line size %d", l); 320 cacheinfo.ec_l2linesize = i; 321 cacheinfo.ec_totalsize = 322 PROM_getpropint(node, "ecache-size", 0) * 323 PROM_getpropint(node, "ecache-associativity", 1); 324 if (cacheinfo.ec_totalsize == 0) 325 cacheinfo.ec_totalsize = l * 326 PROM_getpropint(node, "ecache-nlines", 32768) * 327 PROM_getpropint(node, "ecache-associativity", 1); 328 329 cachesize = cacheinfo.ec_totalsize / 330 PROM_getpropint(node, "ecache-associativity", 1); 331 if (cachesize > bigcache) 332 bigcache = cachesize; 333 334 sep = " "; 335 printf("%s:", dev->dv_xname); 336 if (cacheinfo.ic_totalsize > 0) { 337 printf("%s%ldK instruction (%ld b/l)", sep, 338 (long)cacheinfo.ic_totalsize/1024, 339 (long)cacheinfo.ic_linesize); 340 sep = ", "; 341 } 342 if (cacheinfo.dc_totalsize > 0) { 343 printf("%s%ldK data (%ld b/l)", sep, 344 (long)cacheinfo.dc_totalsize/1024, 345 (long)cacheinfo.dc_linesize); 346 sep = ", "; 347 } 348 if (cacheinfo.ec_totalsize > 0) { 349 printf("%s%ldK external (%ld b/l)", sep, 350 (long)cacheinfo.ec_totalsize/1024, 351 (long)cacheinfo.ec_linesize); 352 } 353 printf("\n"); 354 355 /* 356 * Now that we know the size of the largest cache on this CPU, 357 * re-color our pages. 358 */ 359 uvm_page_recolor(atop(bigcache)); 360 } 361