/* $OpenBSD: cpu.c,v 1.20 2007/05/02 18:46:07 kettenis Exp $ */ /* $NetBSD: cpu.c,v 1.13 2001/05/26 21:27:15 chs Exp $ */ /* * Copyright (c) 1996 * The President and Fellows of Harvard College. All rights reserved. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Harvard University. * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Aaron Brown and * Harvard University. * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cpu.c 8.5 (Berkeley) 11/23/93 * */ #include #include #include #include #include #include #include #include #include #include /* This is declared here so that you must include a CPU for the cache code. */ struct cacheinfo cacheinfo = { us_dcache_flush_page }; /* Linked list of all CPUs in system. */ struct cpu_info *cpus = NULL; /* The following are used externally (sysctl_hw). */ char machine[] = MACHINE; /* from */ char cpu_model[100]; struct proc *fpproc; int foundfpu; int want_ast; extern int want_resched; /* The CPU configuration driver. */ static void cpu_attach(struct device *, struct device *, void *); int cpu_match(struct device *, void *, void *); struct cfattach cpu_ca = { sizeof(struct device), cpu_match, cpu_attach }; extern struct cfdriver cpu_cd; static char *fsrtoname(int, int, int, char *, size_t); #define IU_IMPL(v) ((((u_int64_t)(v))&VER_IMPL) >> VER_IMPL_SHIFT) #define IU_VERS(v) ((((u_int64_t)(v))&VER_MASK) >> VER_MASK_SHIFT) int cpu_match(parent, vcf, aux) struct device *parent; void *vcf; void *aux; { struct mainbus_attach_args *ma = aux; struct cfdata *cf = (struct cfdata *)vcf; return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0); } /* * Attach the CPU. * Discover interesting goop about the virtual address cache * (slightly funny place to do it, but this is where it is to be found). */ static void cpu_attach(parent, dev, aux) struct device *parent; struct device *dev; void *aux; { int node; long clk; int impl, vers, fver; char *cpuname; char *fpuname; struct mainbus_attach_args *ma = aux; struct fpstate64 *fpstate; struct fpstate64 fps[2]; char *sep; char fpbuf[40]; register int i, l; u_int64_t ver; extern u_int64_t cpu_clockrate[]; /* This needs to be 64-bit aligned */ fpstate = ALIGNFPSTATE(&fps[1]); /* * Get the FSR and clear any exceptions. If we do not unload * the queue here and it is left over from a previous crash, we * will panic in the first loadfpstate(), due to a sequence error, * so we need to dump the whole state anyway. * * If there is no FPU, trap.c will advance over all the stores, * so we initialize fs_fsr here. */ fpstate->fs_fsr = 7 << FSR_VER_SHIFT; /* 7 is reserved for "none" */ savefpstate(fpstate); fver = (fpstate->fs_fsr >> FSR_VER_SHIFT) & (FSR_VER >> FSR_VER_SHIFT); ver = getver(); impl = IU_IMPL(ver); vers = IU_VERS(ver); if (fver != 7) { foundfpu = 1; fpuname = fsrtoname(impl, vers, fver, fpbuf, sizeof fpbuf); } else fpuname = "no"; /* tell them what we have */ node = ma->ma_node; clk = getpropint(node, "clock-frequency", 0); if (clk == 0) { /* * Try to find it in the OpenPROM root... */ clk = getpropint(findroot(), "clock-frequency", 0); } if (clk) { cpu_clockrate[0] = clk; /* Tell OS what frequency we run on */ cpu_clockrate[1] = clk/1000000; } cpuname = getpropstring(node, "name"); if (strcmp(cpuname, "cpu") == 0) cpuname = getpropstring(node, "compatible"); snprintf(cpu_model, sizeof cpu_model, "%s (rev %d.%d) @ %s MHz, %s FPU", cpuname, vers >> 4, vers & 0xf, clockfreq(clk), fpuname); printf(": %s\n", cpu_model); cacheinfo.c_physical = 1; /* Dunno... */ cacheinfo.c_split = 1; l = getpropint(node, "icache-line-size", 0); if (l == 0) l = getpropint(node, "l1-icache-line-size", 0); cacheinfo.ic_linesize = l; for (i = 0; (1 << i) < l && l; i++) /* void */; if ((1 << i) != l && l) panic("bad icache line size %d", l); cacheinfo.ic_l2linesize = i; cacheinfo.ic_totalsize = getpropint(node, "icache-size", 0); if (cacheinfo.ic_totalsize == 0) cacheinfo.ic_totalsize = getpropint(node, "l1-icache-size", 0); if (cacheinfo.ic_totalsize == 0) cacheinfo.ic_totalsize = l * getpropint(node, "icache-nlines", 64) * getpropint(node, "icache-associativity", 1); l = getpropint(node, "dcache-line-size", 0); if (l == 0) l = getpropint(node, "l1-dcache-line-size", 0); cacheinfo.dc_linesize = l; for (i = 0; (1 << i) < l && l; i++) /* void */; if ((1 << i) != l && l) panic("bad dcache line size %d", l); cacheinfo.dc_l2linesize = i; cacheinfo.dc_totalsize = getpropint(node, "dcache-size", 0); if (cacheinfo.dc_totalsize == 0) cacheinfo.dc_totalsize = getpropint(node, "l1-dcache-size", 0); if (cacheinfo.dc_totalsize == 0) cacheinfo.dc_totalsize = l * getpropint(node, "dcache-nlines", 128) * getpropint(node, "dcache-associativity", 1); l = getpropint(node, "ecache-line-size", 0); if (l == 0) l = getpropint(node, "l2-cache-line-size", 0); cacheinfo.ec_linesize = l; for (i = 0; (1 << i) < l && l; i++) /* void */; if ((1 << i) != l && l) panic("bad ecache line size %d", l); cacheinfo.ec_l2linesize = i; cacheinfo.ec_totalsize = getpropint(node, "ecache-size", 0); if (cacheinfo.ec_totalsize == 0) cacheinfo.ec_totalsize = getpropint(node, "l2-cache-size", 0); if (cacheinfo.ec_totalsize == 0) cacheinfo.ec_totalsize = l * getpropint(node, "ecache-nlines", 32768) * getpropint(node, "ecache-associativity", 1); /* * XXX - The following will have to do until * we have per-cpu cache handling. */ cacheinfo.c_l2linesize = min(cacheinfo.ic_l2linesize, cacheinfo.dc_l2linesize); cacheinfo.c_linesize = min(cacheinfo.ic_linesize, cacheinfo.dc_linesize); cacheinfo.c_totalsize = cacheinfo.ic_totalsize + cacheinfo.dc_totalsize; if (cacheinfo.c_totalsize == 0) return; sep = " "; printf("%s: physical", dev->dv_xname); if (cacheinfo.ic_totalsize > 0) { printf("%s%ldK instruction (%ld b/l)", sep, (long)cacheinfo.ic_totalsize/1024, (long)cacheinfo.ic_linesize); sep = ", "; } if (cacheinfo.dc_totalsize > 0) { printf("%s%ldK data (%ld b/l)", sep, (long)cacheinfo.dc_totalsize/1024, (long)cacheinfo.dc_linesize); sep = ", "; } if (cacheinfo.ec_totalsize > 0) { printf("%s%ldK external (%ld b/l)", sep, (long)cacheinfo.ec_totalsize/1024, (long)cacheinfo.ec_linesize); } printf("\n"); cache_enable(); if (impl >= IMPL_CHEETAH) { extern vaddr_t ktext, dlflush_start; extern paddr_t ktextp; vaddr_t *pva; paddr_t pa; u_int32_t inst; for (pva = &dlflush_start; *pva; pva++) { inst = *(u_int32_t *)(*pva); inst &= ~(ASI_DCACHE_TAG << 5); inst |= (ASI_DCACHE_INVALIDATE << 5); pa = (paddr_t) (ktextp - ktext + *pva); stwa(pa, ASI_PHYS_CACHED, inst); flush((void *)KERNBASE); } cacheinfo.c_dcache_flush_page = us3_dcache_flush_page; } } /* * The following tables convert triples * into names for the CPU and FPU chip. In most cases we do not need to * inspect the FPU version to name the IU chip, but there is one exception * (for Tsunami), and this makes the tables the same. * * The table contents (and much of the structure here) are from Guy Harris. * */ struct info { u_char valid; u_char iu_impl; u_char iu_vers; u_char fpu_vers; char *name; }; #define ANY 0xff /* match any FPU version (or, later, IU version) */ /* NB: table order matters here; specific numbers must appear before ANY. */ static struct info fpu_types[] = { /* * Vendor 0, IU Fujitsu0. */ { 1, 0x0, ANY, 0, "MB86910 or WTL1164/5" }, { 1, 0x0, ANY, 1, "MB86911 or WTL1164/5" }, { 1, 0x0, ANY, 2, "L64802 or ACT8847" }, { 1, 0x0, ANY, 3, "WTL3170/2" }, { 1, 0x0, 4, 4, "on-chip" }, /* Swift */ { 1, 0x0, ANY, 4, "L64804" }, /* * Vendor 1, IU ROSS0/1 or Pinnacle. */ { 1, 0x1, 0xf, 0, "on-chip" }, /* Pinnacle */ { 1, 0x1, ANY, 0, "L64812 or ACT8847" }, { 1, 0x1, ANY, 1, "L64814" }, { 1, 0x1, ANY, 2, "TMS390C602A" }, { 1, 0x1, ANY, 3, "RT602 or WTL3171" }, /* * Vendor 2, IU BIT0. */ { 1, 0x2, ANY, 0, "B5010 or B5110/20 or B5210" }, /* * Vendor 4, Texas Instruments. */ { 1, 0x4, ANY, 0, "on-chip" }, /* Viking */ { 1, 0x4, ANY, 4, "on-chip" }, /* Tsunami */ /* * Vendor 5, IU Matsushita0. */ { 1, 0x5, ANY, 0, "on-chip" }, /* * Vendor 9, Weitek. */ { 1, 0x9, ANY, 3, "on-chip" }, { 0 } }; static char * fsrtoname(impl, vers, fver, buf, buflen) register int impl, vers, fver; char *buf; size_t buflen; { register struct info *p; for (p = fpu_types; p->valid; p++) if (p->iu_impl == impl && (p->iu_vers == vers || p->iu_vers == ANY) && (p->fpu_vers == fver)) return (p->name); snprintf(buf, buflen, "version %x", fver); return (buf); } struct cfdriver cpu_cd = { NULL, "cpu", DV_DULL };