1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/clock.h> 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/promimpl.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/spitregs.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/cheetahregs.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/cmp.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/async.h> 49*7c478bd9Sstevel@tonic-gate #include <vm/page.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* 52*7c478bd9Sstevel@tonic-gate * The OpenBoot Standalone Interface supplies the kernel with 53*7c478bd9Sstevel@tonic-gate * implementation dependent parameters through the devinfo/property mechanism 54*7c478bd9Sstevel@tonic-gate */ 55*7c478bd9Sstevel@tonic-gate typedef enum { XDRBOOL, XDRINT, XDRSTRING } xdrs; 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate /* 58*7c478bd9Sstevel@tonic-gate * structure describing properties that we are interested in querying the 59*7c478bd9Sstevel@tonic-gate * OBP for. 60*7c478bd9Sstevel@tonic-gate */ 61*7c478bd9Sstevel@tonic-gate struct getprop_info { 62*7c478bd9Sstevel@tonic-gate char *name; 63*7c478bd9Sstevel@tonic-gate xdrs type; 64*7c478bd9Sstevel@tonic-gate uint_t *var; 65*7c478bd9Sstevel@tonic-gate }; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * structure used to convert between a string returned by the OBP & a type 69*7c478bd9Sstevel@tonic-gate * used within the kernel. We prefer to paramaterize rather than type. 70*7c478bd9Sstevel@tonic-gate */ 71*7c478bd9Sstevel@tonic-gate struct convert_info { 72*7c478bd9Sstevel@tonic-gate char *name; 73*7c478bd9Sstevel@tonic-gate uint_t var; 74*7c478bd9Sstevel@tonic-gate char *realname; 75*7c478bd9Sstevel@tonic-gate }; 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * structure describing nodes that we are interested in querying the OBP for 79*7c478bd9Sstevel@tonic-gate * properties. 80*7c478bd9Sstevel@tonic-gate */ 81*7c478bd9Sstevel@tonic-gate struct node_info { 82*7c478bd9Sstevel@tonic-gate char *name; 83*7c478bd9Sstevel@tonic-gate int size; 84*7c478bd9Sstevel@tonic-gate struct getprop_info *prop; 85*7c478bd9Sstevel@tonic-gate struct getprop_info *prop_end; 86*7c478bd9Sstevel@tonic-gate unsigned int *value; 87*7c478bd9Sstevel@tonic-gate }; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* 90*7c478bd9Sstevel@tonic-gate * macro definitions for routines that form the OBP interface 91*7c478bd9Sstevel@tonic-gate */ 92*7c478bd9Sstevel@tonic-gate #define NEXT prom_nextnode 93*7c478bd9Sstevel@tonic-gate #define CHILD prom_childnode 94*7c478bd9Sstevel@tonic-gate #define GETPROP prom_getprop 95*7c478bd9Sstevel@tonic-gate #define GETPROPLEN prom_getproplen 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate /* 0=quiet; 1=verbose; 2=debug */ 99*7c478bd9Sstevel@tonic-gate int debug_fillsysinfo = 0; 100*7c478bd9Sstevel@tonic-gate #define VPRINTF if (debug_fillsysinfo) prom_printf 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate int ncpunode; 103*7c478bd9Sstevel@tonic-gate struct cpu_node cpunodes[NCPU]; 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate static void check_cpus_ver(void); 106*7c478bd9Sstevel@tonic-gate static void check_cpus_set(void); 107*7c478bd9Sstevel@tonic-gate void fill_cpu(dnode_t); 108*7c478bd9Sstevel@tonic-gate void fill_cpu_ddi(dev_info_t *); 109*7c478bd9Sstevel@tonic-gate void empty_cpu(int); 110*7c478bd9Sstevel@tonic-gate void plat_fill_mc(dnode_t); 111*7c478bd9Sstevel@tonic-gate #pragma weak plat_fill_mc 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate uint64_t system_clock_freq; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* 116*7c478bd9Sstevel@tonic-gate * list of well known devices that must be mapped, and the variables that 117*7c478bd9Sstevel@tonic-gate * contain their addresses. 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate caddr_t v_auxio_addr = NULL; 120*7c478bd9Sstevel@tonic-gate caddr_t v_eeprom_addr = NULL; 121*7c478bd9Sstevel@tonic-gate caddr_t v_timecheck_addr = NULL; 122*7c478bd9Sstevel@tonic-gate caddr_t v_rtc_addr_reg = NULL; 123*7c478bd9Sstevel@tonic-gate volatile unsigned char *v_rtc_data_reg = NULL; 124*7c478bd9Sstevel@tonic-gate volatile uint8_t *v_pmc_addr_reg = NULL; 125*7c478bd9Sstevel@tonic-gate volatile uint8_t *v_pmc_data_reg = NULL; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate int niobus = 0; 128*7c478bd9Sstevel@tonic-gate uint_t niommu_tsbs = 0; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate * Hardware watchdog support. 132*7c478bd9Sstevel@tonic-gate */ 133*7c478bd9Sstevel@tonic-gate #define CHOSEN_EEPROM "eeprom" 134*7c478bd9Sstevel@tonic-gate #define WATCHDOG_ENABLE "watchdog-enable" 135*7c478bd9Sstevel@tonic-gate static dnode_t chosen_eeprom; 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * Appropriate tod module will be dynamically selected while booting 139*7c478bd9Sstevel@tonic-gate * based on finding a device tree node with a "device_type" property value 140*7c478bd9Sstevel@tonic-gate * of "tod". If such a node describing tod is not found, for backward 141*7c478bd9Sstevel@tonic-gate * compatibility, a node with a "name" property value of "eeprom" and 142*7c478bd9Sstevel@tonic-gate * "model" property value of "mk48t59" will be used. Failing to find a 143*7c478bd9Sstevel@tonic-gate * node matching either of the above criteria will result in no tod module 144*7c478bd9Sstevel@tonic-gate * being selected; this will cause the boot process to halt. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate char *tod_module_name; 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * If this variable is non-zero, cpr should return "not supported" when 150*7c478bd9Sstevel@tonic-gate * it is queried even though it would normally be supported on this platform. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate int cpr_supported_override; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * Some platforms may need to support CPR even in the absence of the 156*7c478bd9Sstevel@tonic-gate * energystar-v* property (Enchilada server, for example). If this 157*7c478bd9Sstevel@tonic-gate * variable is non-zero, cpr should proceed even in the absence 158*7c478bd9Sstevel@tonic-gate * of the energystar-v* property. 159*7c478bd9Sstevel@tonic-gate */ 160*7c478bd9Sstevel@tonic-gate int cpr_platform_enable = 0; 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Some nodes have functions that need to be called when they're seen. 164*7c478bd9Sstevel@tonic-gate */ 165*7c478bd9Sstevel@tonic-gate static void have_sbus(dnode_t); 166*7c478bd9Sstevel@tonic-gate static void have_pci(dnode_t); 167*7c478bd9Sstevel@tonic-gate static void have_eeprom(dnode_t); 168*7c478bd9Sstevel@tonic-gate static void have_auxio(dnode_t); 169*7c478bd9Sstevel@tonic-gate static void have_rtc(dnode_t); 170*7c478bd9Sstevel@tonic-gate static void have_tod(dnode_t); 171*7c478bd9Sstevel@tonic-gate static void have_pmc(dnode_t); 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate static struct wkdevice { 174*7c478bd9Sstevel@tonic-gate char *wk_namep; 175*7c478bd9Sstevel@tonic-gate void (*wk_func)(dnode_t); 176*7c478bd9Sstevel@tonic-gate caddr_t *wk_vaddrp; 177*7c478bd9Sstevel@tonic-gate ushort_t wk_flags; 178*7c478bd9Sstevel@tonic-gate #define V_OPTIONAL 0x0000 179*7c478bd9Sstevel@tonic-gate #define V_MUSTHAVE 0x0001 180*7c478bd9Sstevel@tonic-gate #define V_MAPPED 0x0002 181*7c478bd9Sstevel@tonic-gate #define V_MULTI 0x0003 /* optional, may be more than one */ 182*7c478bd9Sstevel@tonic-gate } wkdevice[] = { 183*7c478bd9Sstevel@tonic-gate { "sbus", have_sbus, NULL, V_MULTI }, 184*7c478bd9Sstevel@tonic-gate { "pci", have_pci, NULL, V_MULTI }, 185*7c478bd9Sstevel@tonic-gate { "eeprom", have_eeprom, NULL, V_MULTI }, 186*7c478bd9Sstevel@tonic-gate { "auxio", have_auxio, NULL, V_OPTIONAL }, 187*7c478bd9Sstevel@tonic-gate { "rtc", have_rtc, NULL, V_OPTIONAL }, 188*7c478bd9Sstevel@tonic-gate { "pmc", have_pmc, NULL, V_OPTIONAL }, 189*7c478bd9Sstevel@tonic-gate { 0, }, 190*7c478bd9Sstevel@tonic-gate }; 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate static void map_wellknown(dnode_t); 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate void 195*7c478bd9Sstevel@tonic-gate map_wellknown_devices() 196*7c478bd9Sstevel@tonic-gate { 197*7c478bd9Sstevel@tonic-gate struct wkdevice *wkp; 198*7c478bd9Sstevel@tonic-gate phandle_t ieeprom; 199*7c478bd9Sstevel@tonic-gate dnode_t root; 200*7c478bd9Sstevel@tonic-gate uint_t stick_freq; 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * if there is a chosen eeprom, note it (for have_eeprom()) 204*7c478bd9Sstevel@tonic-gate */ 205*7c478bd9Sstevel@tonic-gate if (GETPROPLEN(prom_chosennode(), CHOSEN_EEPROM) == 206*7c478bd9Sstevel@tonic-gate sizeof (phandle_t) && 207*7c478bd9Sstevel@tonic-gate GETPROP(prom_chosennode(), CHOSEN_EEPROM, (caddr_t)&ieeprom) != -1) 208*7c478bd9Sstevel@tonic-gate chosen_eeprom = (dnode_t)prom_decode_int(ieeprom); 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate root = prom_nextnode((dnode_t)0); 211*7c478bd9Sstevel@tonic-gate /* 212*7c478bd9Sstevel@tonic-gate * Get System clock frequency from root node if it exists. 213*7c478bd9Sstevel@tonic-gate */ 214*7c478bd9Sstevel@tonic-gate if (GETPROP(root, "stick-frequency", (caddr_t)&stick_freq) != -1) 215*7c478bd9Sstevel@tonic-gate system_clock_freq = stick_freq; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate map_wellknown(NEXT((dnode_t)0)); 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* 220*7c478bd9Sstevel@tonic-gate * See if it worked 221*7c478bd9Sstevel@tonic-gate */ 222*7c478bd9Sstevel@tonic-gate for (wkp = wkdevice; wkp->wk_namep; ++wkp) { 223*7c478bd9Sstevel@tonic-gate if (wkp->wk_flags == V_MUSTHAVE) { 224*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "map_wellknown_devices: required " 225*7c478bd9Sstevel@tonic-gate "device %s not mapped", wkp->wk_namep); 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate /* 230*7c478bd9Sstevel@tonic-gate * all sun4u systems must have an IO bus, i.e. sbus or pcibus 231*7c478bd9Sstevel@tonic-gate */ 232*7c478bd9Sstevel@tonic-gate if (niobus == 0) 233*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "map_wellknown_devices: no i/o bus node"); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate check_cpus_ver(); 236*7c478bd9Sstevel@tonic-gate check_cpus_set(); 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate /* 240*7c478bd9Sstevel@tonic-gate * map_wellknown - map known devices & registers 241*7c478bd9Sstevel@tonic-gate */ 242*7c478bd9Sstevel@tonic-gate static void 243*7c478bd9Sstevel@tonic-gate map_wellknown(dnode_t curnode) 244*7c478bd9Sstevel@tonic-gate { 245*7c478bd9Sstevel@tonic-gate extern int status_okay(int, char *, int); 246*7c478bd9Sstevel@tonic-gate char tmp_name[MAXSYSNAME]; 247*7c478bd9Sstevel@tonic-gate static void fill_address(dnode_t, char *); 248*7c478bd9Sstevel@tonic-gate int sok; 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate #ifdef VPRINTF 251*7c478bd9Sstevel@tonic-gate VPRINTF("map_wellknown(%x)\n", curnode); 252*7c478bd9Sstevel@tonic-gate #endif /* VPRINTF */ 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate for (curnode = CHILD(curnode); curnode; curnode = NEXT(curnode)) { 255*7c478bd9Sstevel@tonic-gate /* 256*7c478bd9Sstevel@tonic-gate * prune subtree if status property indicating not okay 257*7c478bd9Sstevel@tonic-gate */ 258*7c478bd9Sstevel@tonic-gate sok = status_okay((int)curnode, (char *)NULL, 0); 259*7c478bd9Sstevel@tonic-gate if (!sok) { 260*7c478bd9Sstevel@tonic-gate char devtype_buf[OBP_MAXPROPNAME]; 261*7c478bd9Sstevel@tonic-gate int size; 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate #ifdef VPRINTF 264*7c478bd9Sstevel@tonic-gate VPRINTF("map_wellknown: !okay status property\n"); 265*7c478bd9Sstevel@tonic-gate #endif /* VPRINTF */ 266*7c478bd9Sstevel@tonic-gate /* 267*7c478bd9Sstevel@tonic-gate * a status property indicating bad memory will be 268*7c478bd9Sstevel@tonic-gate * associated with a node which has a "device_type" 269*7c478bd9Sstevel@tonic-gate * property with a value of "memory-controller" 270*7c478bd9Sstevel@tonic-gate */ 271*7c478bd9Sstevel@tonic-gate if ((size = GETPROPLEN(curnode, 272*7c478bd9Sstevel@tonic-gate OBP_DEVICETYPE)) == -1) 273*7c478bd9Sstevel@tonic-gate continue; 274*7c478bd9Sstevel@tonic-gate if (size > OBP_MAXPROPNAME) { 275*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "node %x '%s' prop too " 276*7c478bd9Sstevel@tonic-gate "big\n", curnode, OBP_DEVICETYPE); 277*7c478bd9Sstevel@tonic-gate continue; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate if (GETPROP(curnode, OBP_DEVICETYPE, 280*7c478bd9Sstevel@tonic-gate devtype_buf) == -1) { 281*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "node %x '%s' get failed\n", 282*7c478bd9Sstevel@tonic-gate curnode, OBP_DEVICETYPE); 283*7c478bd9Sstevel@tonic-gate continue; 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate if (strcmp(devtype_buf, "memory-controller") != 0) 286*7c478bd9Sstevel@tonic-gate continue; 287*7c478bd9Sstevel@tonic-gate /* 288*7c478bd9Sstevel@tonic-gate * ...else fall thru and process the node... 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate bzero(tmp_name, MAXSYSNAME); 292*7c478bd9Sstevel@tonic-gate if (GETPROP(curnode, OBP_NAME, (caddr_t)tmp_name) != -1) 293*7c478bd9Sstevel@tonic-gate fill_address(curnode, tmp_name); 294*7c478bd9Sstevel@tonic-gate if (GETPROP(curnode, OBP_DEVICETYPE, tmp_name) != -1 && 295*7c478bd9Sstevel@tonic-gate strcmp(tmp_name, "cpu") == 0) { 296*7c478bd9Sstevel@tonic-gate fill_cpu(curnode); 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate if (strcmp(tmp_name, "tod") == 0) 299*7c478bd9Sstevel@tonic-gate have_tod(curnode); 300*7c478bd9Sstevel@tonic-gate if (sok && (strcmp(tmp_name, "memory-controller") == 0) && 301*7c478bd9Sstevel@tonic-gate (&plat_fill_mc != NULL)) 302*7c478bd9Sstevel@tonic-gate plat_fill_mc(curnode); 303*7c478bd9Sstevel@tonic-gate map_wellknown(curnode); 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate static void 308*7c478bd9Sstevel@tonic-gate fill_address(dnode_t curnode, char *namep) 309*7c478bd9Sstevel@tonic-gate { 310*7c478bd9Sstevel@tonic-gate struct wkdevice *wkp; 311*7c478bd9Sstevel@tonic-gate int size; 312*7c478bd9Sstevel@tonic-gate uint32_t vaddr; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate for (wkp = wkdevice; wkp->wk_namep; ++wkp) { 315*7c478bd9Sstevel@tonic-gate if (strcmp(wkp->wk_namep, namep) != 0) 316*7c478bd9Sstevel@tonic-gate continue; 317*7c478bd9Sstevel@tonic-gate if (wkp->wk_flags == V_MAPPED) 318*7c478bd9Sstevel@tonic-gate return; 319*7c478bd9Sstevel@tonic-gate if (wkp->wk_vaddrp != NULL) { 320*7c478bd9Sstevel@tonic-gate if ((size = GETPROPLEN(curnode, OBP_ADDRESS)) == -1) { 321*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "device %s size %d\n", 322*7c478bd9Sstevel@tonic-gate namep, size); 323*7c478bd9Sstevel@tonic-gate continue; 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate if (size != sizeof (vaddr)) { 326*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "device %s address prop too " 327*7c478bd9Sstevel@tonic-gate "big\n", namep); 328*7c478bd9Sstevel@tonic-gate continue; 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate if (GETPROP(curnode, OBP_ADDRESS, 331*7c478bd9Sstevel@tonic-gate (caddr_t)&vaddr) == -1) { 332*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "device %s not mapped\n", 333*7c478bd9Sstevel@tonic-gate namep); 334*7c478bd9Sstevel@tonic-gate continue; 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /* make into a native pointer */ 338*7c478bd9Sstevel@tonic-gate *wkp->wk_vaddrp = (caddr_t)vaddr; 339*7c478bd9Sstevel@tonic-gate #ifdef VPRINTF 340*7c478bd9Sstevel@tonic-gate VPRINTF("fill_address: %s mapped to %x\n", namep, 341*7c478bd9Sstevel@tonic-gate *wkp->wk_vaddrp); 342*7c478bd9Sstevel@tonic-gate #endif /* VPRINTF */ 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate if (wkp->wk_func != NULL) 345*7c478bd9Sstevel@tonic-gate (*wkp->wk_func)(curnode); 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * If this one is optional and there may be more than 348*7c478bd9Sstevel@tonic-gate * one, don't set V_MAPPED, which would cause us to skip it 349*7c478bd9Sstevel@tonic-gate * next time around 350*7c478bd9Sstevel@tonic-gate */ 351*7c478bd9Sstevel@tonic-gate if (wkp->wk_flags != V_MULTI) 352*7c478bd9Sstevel@tonic-gate wkp->wk_flags = V_MAPPED; 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate int 357*7c478bd9Sstevel@tonic-gate get_portid(dnode_t node, dnode_t *cmpp) 358*7c478bd9Sstevel@tonic-gate { 359*7c478bd9Sstevel@tonic-gate int portid; 360*7c478bd9Sstevel@tonic-gate char dev_type[OBP_MAXPROPNAME]; 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate if (cmpp != NULL) 363*7c478bd9Sstevel@tonic-gate *cmpp = OBP_NONODE; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "portid", (caddr_t)&portid) != -1) 366*7c478bd9Sstevel@tonic-gate return (portid); 367*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "upa-portid", (caddr_t)&portid) != -1) 368*7c478bd9Sstevel@tonic-gate return (portid); 369*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "device_type", (caddr_t)&dev_type) == -1) 370*7c478bd9Sstevel@tonic-gate return (-1); 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate /* On a CMP core, the "portid" is in the parent */ 373*7c478bd9Sstevel@tonic-gate if (strcmp(dev_type, "cpu") == 0) { 374*7c478bd9Sstevel@tonic-gate node = prom_parentnode(node); 375*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "portid", (caddr_t)&portid) != -1) { 376*7c478bd9Sstevel@tonic-gate if (cmpp != NULL) 377*7c478bd9Sstevel@tonic-gate *cmpp = node; 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate return (portid); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate return (-1); 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate /* 387*7c478bd9Sstevel@tonic-gate * Adjust page coloring variables based on the physical ecache setsize of 388*7c478bd9Sstevel@tonic-gate * the configured cpus: 389*7c478bd9Sstevel@tonic-gate * 390*7c478bd9Sstevel@tonic-gate * Set ecache_setsize to max ecache set size to be used by 391*7c478bd9Sstevel@tonic-gate * page_coloring_init() to determine the page colors to configure. 392*7c478bd9Sstevel@tonic-gate * The adjustment is unlikely to be necessary... For cheetah+ systems, 393*7c478bd9Sstevel@tonic-gate * ecache_setsize should already be set in cpu_fiximp() to the maximum 394*7c478bd9Sstevel@tonic-gate * possible ecache setsize of any supported cheetah+ cpus. The adjustment 395*7c478bd9Sstevel@tonic-gate * is for the off chance that a non-cheetah+ system may have heterogenous 396*7c478bd9Sstevel@tonic-gate * cpus. 397*7c478bd9Sstevel@tonic-gate * 398*7c478bd9Sstevel@tonic-gate * Set cpu_setsize to the actual cpu setsize if the setsize is homogenous 399*7c478bd9Sstevel@tonic-gate * across all cpus otherwise set it to -1 if heterogenous. 400*7c478bd9Sstevel@tonic-gate * 401*7c478bd9Sstevel@tonic-gate * Set cpu_page_colors to -1 to signify heterogeneity of ecache setsizes 402*7c478bd9Sstevel@tonic-gate * to the page_get routines. 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate static void 405*7c478bd9Sstevel@tonic-gate adj_ecache_setsize(int ecsetsize) 406*7c478bd9Sstevel@tonic-gate { 407*7c478bd9Sstevel@tonic-gate if (ecsetsize > ecache_setsize) 408*7c478bd9Sstevel@tonic-gate ecache_setsize = ecsetsize; 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate switch (cpu_setsize) { 411*7c478bd9Sstevel@tonic-gate case -1: 412*7c478bd9Sstevel@tonic-gate break; 413*7c478bd9Sstevel@tonic-gate case 0: 414*7c478bd9Sstevel@tonic-gate cpu_setsize = ecsetsize; 415*7c478bd9Sstevel@tonic-gate break; 416*7c478bd9Sstevel@tonic-gate default: 417*7c478bd9Sstevel@tonic-gate /* set to -1 if hetergenous cpus */ 418*7c478bd9Sstevel@tonic-gate if (cpu_setsize != ecsetsize) { 419*7c478bd9Sstevel@tonic-gate if (do_pg_coloring) 420*7c478bd9Sstevel@tonic-gate cpu_page_colors = -1; 421*7c478bd9Sstevel@tonic-gate /* 422*7c478bd9Sstevel@tonic-gate * if page coloring disabled, cpu_page_colors should 423*7c478bd9Sstevel@tonic-gate * remain 0 to prevent page coloring processing. 424*7c478bd9Sstevel@tonic-gate */ 425*7c478bd9Sstevel@tonic-gate cpu_setsize = -1; 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate break; 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate } 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate void 432*7c478bd9Sstevel@tonic-gate fill_cpu(dnode_t node) 433*7c478bd9Sstevel@tonic-gate { 434*7c478bd9Sstevel@tonic-gate extern int cpu_get_cpu_unum(int, char *, int, int *); 435*7c478bd9Sstevel@tonic-gate struct cpu_node *cpunode; 436*7c478bd9Sstevel@tonic-gate processorid_t cpuid; 437*7c478bd9Sstevel@tonic-gate int portid; 438*7c478bd9Sstevel@tonic-gate int tlbsize; 439*7c478bd9Sstevel@tonic-gate int size; 440*7c478bd9Sstevel@tonic-gate uint_t clk_freq; 441*7c478bd9Sstevel@tonic-gate dnode_t cmpnode; 442*7c478bd9Sstevel@tonic-gate char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN]; 443*7c478bd9Sstevel@tonic-gate char *namebufp; 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate if ((portid = get_portid(node, &cmpnode)) == -1) { 446*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "portid not found"); 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "cpuid", (caddr_t)&cpuid) == -1) { 450*7c478bd9Sstevel@tonic-gate cpuid = portid; 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate if (cpuid < 0 || cpuid >= NCPU) { 454*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu node %x: cpuid %d out of range", 455*7c478bd9Sstevel@tonic-gate node, cpuid); 456*7c478bd9Sstevel@tonic-gate return; 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate cpunode = &cpunodes[cpuid]; 460*7c478bd9Sstevel@tonic-gate cpunode->portid = portid; 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &size) != 0) { 463*7c478bd9Sstevel@tonic-gate cpunode->fru_fmri[0] = '\0'; 464*7c478bd9Sstevel@tonic-gate } else { 465*7c478bd9Sstevel@tonic-gate (void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri), 466*7c478bd9Sstevel@tonic-gate "%s%s", CPU_FRU_FMRI, unum); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, (cmpnode ? "compatible" : "name"), namebuf); 470*7c478bd9Sstevel@tonic-gate namebufp = namebuf; 471*7c478bd9Sstevel@tonic-gate if (strncmp(namebufp, "SUNW,", 5) == 0) 472*7c478bd9Sstevel@tonic-gate namebufp += 5; 473*7c478bd9Sstevel@tonic-gate (void) strcpy(cpunode->name, namebufp); 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "implementation#", 476*7c478bd9Sstevel@tonic-gate (caddr_t)&cpunode->implementation); 477*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "mask#", (caddr_t)&cpunode->version); 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate if (IS_CHEETAH(cpunode->implementation)) { 480*7c478bd9Sstevel@tonic-gate /* remap mask reg */ 481*7c478bd9Sstevel@tonic-gate cpunode->version = REMAP_CHEETAH_MASK(cpunode->version); 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "clock-frequency", (caddr_t)&clk_freq) == -1) { 484*7c478bd9Sstevel@tonic-gate /* 485*7c478bd9Sstevel@tonic-gate * If we didn't find it in the CPU node, look in the root node. 486*7c478bd9Sstevel@tonic-gate */ 487*7c478bd9Sstevel@tonic-gate dnode_t root = prom_nextnode((dnode_t)0); 488*7c478bd9Sstevel@tonic-gate if (GETPROP(root, "clock-frequency", (caddr_t)&clk_freq) == -1) 489*7c478bd9Sstevel@tonic-gate clk_freq = 0; 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate cpunode->clock_freq = clk_freq; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->clock_freq != 0); 494*7c478bd9Sstevel@tonic-gate /* 495*7c478bd9Sstevel@tonic-gate * Compute scaling factor based on rate of %tick. This is used 496*7c478bd9Sstevel@tonic-gate * to convert from ticks derived from %tick to nanoseconds. See 497*7c478bd9Sstevel@tonic-gate * comment in sun4u/sys/clock.h for details. 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 500*7c478bd9Sstevel@tonic-gate (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "#itlb-entries", (caddr_t)&tlbsize); 503*7c478bd9Sstevel@tonic-gate ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ 504*7c478bd9Sstevel@tonic-gate cpunode->itlb_size = (ushort_t)tlbsize; 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "#dtlb-entries", (caddr_t)&tlbsize); 507*7c478bd9Sstevel@tonic-gate ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ 508*7c478bd9Sstevel@tonic-gate cpunode->dtlb_size = (ushort_t)tlbsize; 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate cpunode->nodeid = node; 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate if (cmpnode != OBP_NONODE) { 513*7c478bd9Sstevel@tonic-gate /* 514*7c478bd9Sstevel@tonic-gate * If the CPU has a level 3 cache, then it will be the 515*7c478bd9Sstevel@tonic-gate * external cache. Otherwise the level 2 cache is the 516*7c478bd9Sstevel@tonic-gate * external cache. 517*7c478bd9Sstevel@tonic-gate */ 518*7c478bd9Sstevel@tonic-gate size = 0; 519*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "l3-cache-size", (caddr_t)&size); 520*7c478bd9Sstevel@tonic-gate if (size <= 0) 521*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "l2-cache-size", (caddr_t)&size); 522*7c478bd9Sstevel@tonic-gate ASSERT(size != 0); 523*7c478bd9Sstevel@tonic-gate cpunode->ecache_size = size; 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate size = 0; 526*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "l3-cache-line-size", (caddr_t)&size); 527*7c478bd9Sstevel@tonic-gate if (size <= 0) 528*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "l2-cache-line-size", 529*7c478bd9Sstevel@tonic-gate (caddr_t)&size); 530*7c478bd9Sstevel@tonic-gate ASSERT(size != 0); 531*7c478bd9Sstevel@tonic-gate cpunode->ecache_linesize = size; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate size = 0; 534*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "l2-cache-associativity", (caddr_t)&size); 535*7c478bd9Sstevel@tonic-gate ASSERT(size != 0); 536*7c478bd9Sstevel@tonic-gate cpunode->ecache_associativity = size; 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate cmp_add_cpu(portid, cpuid); 539*7c478bd9Sstevel@tonic-gate } else { 540*7c478bd9Sstevel@tonic-gate size = 0; 541*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "ecache-size", (caddr_t)&size); 542*7c478bd9Sstevel@tonic-gate ASSERT(size != 0); 543*7c478bd9Sstevel@tonic-gate cpunode->ecache_size = size; 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate size = 0; 546*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "ecache-line-size", (caddr_t)&size); 547*7c478bd9Sstevel@tonic-gate ASSERT(size != 0); 548*7c478bd9Sstevel@tonic-gate cpunode->ecache_linesize = size; 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate size = 0; 551*7c478bd9Sstevel@tonic-gate (void) GETPROP(node, "ecache-associativity", (caddr_t)&size); 552*7c478bd9Sstevel@tonic-gate ASSERT(size != 0); 553*7c478bd9Sstevel@tonic-gate cpunode->ecache_associativity = size; 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate /* by default set msram to non-mirrored one */ 557*7c478bd9Sstevel@tonic-gate cpunode->msram = ECACHE_CPU_NON_MIRROR; 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate if (GETPROPLEN(node, "msram") != -1) { 560*7c478bd9Sstevel@tonic-gate cpunode->msram = ECACHE_CPU_MIRROR; 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate if (GETPROPLEN(node, "msram-observed") != -1) { 564*7c478bd9Sstevel@tonic-gate cpunode->msram = ECACHE_CPU_MIRROR; 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate if (ncpunode == 0) { 568*7c478bd9Sstevel@tonic-gate cpu_fiximp(node); 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate cpunode->ecache_setsize = 572*7c478bd9Sstevel@tonic-gate cpunode->ecache_size / cpunode->ecache_associativity; 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate adj_ecache_setsize(cpunode->ecache_setsize); 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate ncpunode++; 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate int 580*7c478bd9Sstevel@tonic-gate get_portid_ddi(dev_info_t *dip, dev_info_t **cmpp) 581*7c478bd9Sstevel@tonic-gate { 582*7c478bd9Sstevel@tonic-gate int portid; 583*7c478bd9Sstevel@tonic-gate char dev_type[OBP_MAXPROPNAME]; 584*7c478bd9Sstevel@tonic-gate int len = OBP_MAXPROPNAME; 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate if (cmpp != NULL) 587*7c478bd9Sstevel@tonic-gate *cmpp = NULL; 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 590*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "portid", -1)) != -1) 591*7c478bd9Sstevel@tonic-gate return (portid); 592*7c478bd9Sstevel@tonic-gate if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 593*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "upa-portid", -1)) != -1) 594*7c478bd9Sstevel@tonic-gate return (portid); 595*7c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 596*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type, 597*7c478bd9Sstevel@tonic-gate &len) != 0) 598*7c478bd9Sstevel@tonic-gate return (-1); 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate /* On a CMP core, the "portid" is in the parent */ 601*7c478bd9Sstevel@tonic-gate if (strcmp(dev_type, "cpu") == 0) { 602*7c478bd9Sstevel@tonic-gate dip = ddi_get_parent(dip); 603*7c478bd9Sstevel@tonic-gate if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 604*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "portid", -1)) != -1) { 605*7c478bd9Sstevel@tonic-gate if (cmpp != NULL) 606*7c478bd9Sstevel@tonic-gate *cmpp = dip; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate return (portid); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate return (-1); 613*7c478bd9Sstevel@tonic-gate } 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate /* 616*7c478bd9Sstevel@tonic-gate * A hotplug version of fill_cpu(). (Doesn't assume that there's a node 617*7c478bd9Sstevel@tonic-gate * in the PROM device tree for this CPU.) We still need the PROM version 618*7c478bd9Sstevel@tonic-gate * since it is called very early in the boot cycle before (before 619*7c478bd9Sstevel@tonic-gate * setup_ddi()). Sigh...someday this will all be cleaned up. 620*7c478bd9Sstevel@tonic-gate */ 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate void 623*7c478bd9Sstevel@tonic-gate fill_cpu_ddi(dev_info_t *dip) 624*7c478bd9Sstevel@tonic-gate { 625*7c478bd9Sstevel@tonic-gate extern int cpu_get_cpu_unum(int, char *, int, int *); 626*7c478bd9Sstevel@tonic-gate struct cpu_node *cpunode; 627*7c478bd9Sstevel@tonic-gate processorid_t cpuid; 628*7c478bd9Sstevel@tonic-gate int portid; 629*7c478bd9Sstevel@tonic-gate int len; 630*7c478bd9Sstevel@tonic-gate int tlbsize; 631*7c478bd9Sstevel@tonic-gate dev_info_t *cmpnode; 632*7c478bd9Sstevel@tonic-gate char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN]; 633*7c478bd9Sstevel@tonic-gate char *namebufp; 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate if ((portid = get_portid_ddi(dip, &cmpnode)) == -1) { 636*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "portid not found"); 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate if ((cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 640*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "cpuid", -1)) == -1) { 641*7c478bd9Sstevel@tonic-gate cpuid = portid; 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate if (cpuid < 0 || cpuid >= NCPU) { 645*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu dip %p: cpuid %d out of range", 646*7c478bd9Sstevel@tonic-gate (void *) dip, cpuid); 647*7c478bd9Sstevel@tonic-gate return; 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate cpunode = &cpunodes[cpuid]; 651*7c478bd9Sstevel@tonic-gate cpunode->portid = portid; 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &len) != 0) { 654*7c478bd9Sstevel@tonic-gate cpunode->fru_fmri[0] = '\0'; 655*7c478bd9Sstevel@tonic-gate } else { 656*7c478bd9Sstevel@tonic-gate (void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri), 657*7c478bd9Sstevel@tonic-gate "%s%s", CPU_FRU_FMRI, unum); 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate len = sizeof (namebuf); 661*7c478bd9Sstevel@tonic-gate (void) ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 662*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, (cmpnode ? "compatible" : "name"), 663*7c478bd9Sstevel@tonic-gate (caddr_t)namebuf, &len); 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate namebufp = namebuf; 666*7c478bd9Sstevel@tonic-gate if (strncmp(namebufp, "SUNW,", 5) == 0) 667*7c478bd9Sstevel@tonic-gate namebufp += 5; 668*7c478bd9Sstevel@tonic-gate (void) strcpy(cpunode->name, namebufp); 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate cpunode->implementation = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 671*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "implementation#", 0); 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate cpunode->version = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 674*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "mask#", 0); 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate if (IS_CHEETAH(cpunode->implementation)) { 677*7c478bd9Sstevel@tonic-gate /* remap mask reg */ 678*7c478bd9Sstevel@tonic-gate cpunode->version = REMAP_CHEETAH_MASK(cpunode->version); 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate cpunode->clock_freq = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 682*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "clock-frequency", 0); 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->clock_freq != 0); 685*7c478bd9Sstevel@tonic-gate /* 686*7c478bd9Sstevel@tonic-gate * Compute scaling factor based on rate of %tick. This is used 687*7c478bd9Sstevel@tonic-gate * to convert from ticks derived from %tick to nanoseconds. See 688*7c478bd9Sstevel@tonic-gate * comment in sun4u/sys/clock.h for details. 689*7c478bd9Sstevel@tonic-gate */ 690*7c478bd9Sstevel@tonic-gate cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 691*7c478bd9Sstevel@tonic-gate (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 694*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#itlb-entries", 0); 695*7c478bd9Sstevel@tonic-gate ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ 696*7c478bd9Sstevel@tonic-gate cpunode->itlb_size = (ushort_t)tlbsize; 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 699*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#dtlb-entries", 0); 700*7c478bd9Sstevel@tonic-gate ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ 701*7c478bd9Sstevel@tonic-gate cpunode->dtlb_size = (ushort_t)tlbsize; 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate cpunode->nodeid = ddi_get_nodeid(dip); 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate if (cmpnode != NULL) { 706*7c478bd9Sstevel@tonic-gate /* 707*7c478bd9Sstevel@tonic-gate * If the CPU has a level 3 cache, then that is it's 708*7c478bd9Sstevel@tonic-gate * external cache. Otherwise the external cache must 709*7c478bd9Sstevel@tonic-gate * be the level 2 cache. 710*7c478bd9Sstevel@tonic-gate */ 711*7c478bd9Sstevel@tonic-gate cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, 712*7c478bd9Sstevel@tonic-gate dip, DDI_PROP_DONTPASS, "l3-cache-size", 0); 713*7c478bd9Sstevel@tonic-gate if (cpunode->ecache_size == 0) 714*7c478bd9Sstevel@tonic-gate cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, 715*7c478bd9Sstevel@tonic-gate dip, DDI_PROP_DONTPASS, "l2-cache-size", 0); 716*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->ecache_size != 0); 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY, 719*7c478bd9Sstevel@tonic-gate dip, DDI_PROP_DONTPASS, "l3-cache-line-size", 0); 720*7c478bd9Sstevel@tonic-gate if (cpunode->ecache_linesize == 0) 721*7c478bd9Sstevel@tonic-gate cpunode->ecache_linesize = 722*7c478bd9Sstevel@tonic-gate ddi_prop_get_int(DDI_DEV_T_ANY, dip, 723*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "l2-cache-line-size", 0); 724*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->ecache_linesize != 0); 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY, 727*7c478bd9Sstevel@tonic-gate dip, DDI_PROP_DONTPASS, "l2-cache-associativity", 0); 728*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->ecache_associativity != 0); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate cmp_add_cpu(portid, cpuid); 731*7c478bd9Sstevel@tonic-gate } else { 732*7c478bd9Sstevel@tonic-gate cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, 733*7c478bd9Sstevel@tonic-gate dip, DDI_PROP_DONTPASS, "ecache-size", 0); 734*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->ecache_size != 0); 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY, 737*7c478bd9Sstevel@tonic-gate dip, DDI_PROP_DONTPASS, "ecache-line-size", 0); 738*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->ecache_linesize != 0); 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY, 741*7c478bd9Sstevel@tonic-gate dip, DDI_PROP_DONTPASS, "ecache-associativity", 0); 742*7c478bd9Sstevel@tonic-gate ASSERT(cpunode->ecache_associativity != 0); 743*7c478bd9Sstevel@tonic-gate } 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate /* by default set msram to non-mirrored one */ 746*7c478bd9Sstevel@tonic-gate cpunode->msram = ECACHE_CPU_NON_MIRROR; 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "msram")) { 749*7c478bd9Sstevel@tonic-gate cpunode->msram = ECACHE_CPU_MIRROR; 750*7c478bd9Sstevel@tonic-gate } else if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 751*7c478bd9Sstevel@tonic-gate "msram-observed")) { 752*7c478bd9Sstevel@tonic-gate cpunode->msram = ECACHE_CPU_MIRROR; 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate ASSERT(ncpunode > 0); /* fiximp not req'd */ 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate cpunode->ecache_setsize = 758*7c478bd9Sstevel@tonic-gate cpunode->ecache_size / cpunode->ecache_associativity; 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate adj_ecache_setsize(cpunode->ecache_setsize); 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate ncpunode++; 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate void 766*7c478bd9Sstevel@tonic-gate empty_cpu(int cpuid) 767*7c478bd9Sstevel@tonic-gate { 768*7c478bd9Sstevel@tonic-gate bzero(&cpunodes[cpuid], sizeof (struct cpu_node)); 769*7c478bd9Sstevel@tonic-gate ncpunode--; 770*7c478bd9Sstevel@tonic-gate } 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate #ifdef SF_ERRATA_30 /* call causes fp-disabled */ 773*7c478bd9Sstevel@tonic-gate int spitfire_call_bug = 0; 774*7c478bd9Sstevel@tonic-gate #endif 775*7c478bd9Sstevel@tonic-gate #ifdef SF_V9_TABLE_28 /* fp over/underflow traps may cause wrong fsr.cexc */ 776*7c478bd9Sstevel@tonic-gate int spitfire_bb_fsr_bug = 0; 777*7c478bd9Sstevel@tonic-gate #endif 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate #ifdef JALAPENO_ERRATA_85 780*7c478bd9Sstevel@tonic-gate /* 781*7c478bd9Sstevel@tonic-gate * Set the values here assuming we're running 2.4 or later Jalapenos. If 782*7c478bd9Sstevel@tonic-gate * not, they'll be reset below. Either way, the default can be overridden 783*7c478bd9Sstevel@tonic-gate * when we read /etc/system later in boot. 784*7c478bd9Sstevel@tonic-gate */ 785*7c478bd9Sstevel@tonic-gate int jp_errata_85_allow_slow_scrub = 1; 786*7c478bd9Sstevel@tonic-gate int jp_errata_85_enable = 0; 787*7c478bd9Sstevel@tonic-gate #endif /* JALAPENO_ERRATA_85 */ 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate static void 790*7c478bd9Sstevel@tonic-gate check_cpus_ver(void) 791*7c478bd9Sstevel@tonic-gate { 792*7c478bd9Sstevel@tonic-gate int i; 793*7c478bd9Sstevel@tonic-gate int impl, cpuid = getprocessorid(); 794*7c478bd9Sstevel@tonic-gate int min_supported_rev; 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate ASSERT(cpunodes[cpuid].nodeid != 0); 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate impl = cpunodes[cpuid].implementation; 799*7c478bd9Sstevel@tonic-gate switch (impl) { 800*7c478bd9Sstevel@tonic-gate default: 801*7c478bd9Sstevel@tonic-gate min_supported_rev = 0; 802*7c478bd9Sstevel@tonic-gate break; 803*7c478bd9Sstevel@tonic-gate case SPITFIRE_IMPL: 804*7c478bd9Sstevel@tonic-gate min_supported_rev = SPITFIRE_MINREV_SUPPORTED; 805*7c478bd9Sstevel@tonic-gate break; 806*7c478bd9Sstevel@tonic-gate case CHEETAH_IMPL: 807*7c478bd9Sstevel@tonic-gate min_supported_rev = CHEETAH_MINREV_SUPPORTED; 808*7c478bd9Sstevel@tonic-gate break; 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 812*7c478bd9Sstevel@tonic-gate if (cpunodes[i].nodeid == 0) 813*7c478bd9Sstevel@tonic-gate continue; 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate if (IS_SPITFIRE(impl)) { 816*7c478bd9Sstevel@tonic-gate if (cpunodes[i].version < min_supported_rev) { 817*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 818*7c478bd9Sstevel@tonic-gate "UltraSPARC versions older than %d.%d" 819*7c478bd9Sstevel@tonic-gate " are no longer supported (cpu #%d)", 820*7c478bd9Sstevel@tonic-gate SPITFIRE_MAJOR_VERSION(min_supported_rev), 821*7c478bd9Sstevel@tonic-gate SPITFIRE_MINOR_VERSION(min_supported_rev), i); 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate /* 825*7c478bd9Sstevel@tonic-gate * Min supported rev is 2.1 but we've seen problems 826*7c478bd9Sstevel@tonic-gate * with that so we still want to warn if we see one. 827*7c478bd9Sstevel@tonic-gate */ 828*7c478bd9Sstevel@tonic-gate if (cpunodes[i].version < 0x22) { 829*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 830*7c478bd9Sstevel@tonic-gate "UltraSPARC versions older than " 831*7c478bd9Sstevel@tonic-gate "2.2 are not supported (cpu #%d)", i); 832*7c478bd9Sstevel@tonic-gate #ifdef SF_ERRATA_30 /* call causes fp-disabled */ 833*7c478bd9Sstevel@tonic-gate spitfire_call_bug = 1; 834*7c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_30 */ 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate #ifdef SF_V9_TABLE_28 /* fp over/underflow traps may cause wrong fsr.cexc */ 840*7c478bd9Sstevel@tonic-gate if (IS_SPITFIRE(impl) || IS_BLACKBIRD(impl)) 841*7c478bd9Sstevel@tonic-gate spitfire_bb_fsr_bug = 1; 842*7c478bd9Sstevel@tonic-gate #endif /* SF_V9_TABLE_28 */ 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate if (IS_CHEETAH(impl)) { 845*7c478bd9Sstevel@tonic-gate if (cpunodes[i].version < min_supported_rev) { 846*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 847*7c478bd9Sstevel@tonic-gate "UltraSPARC-III versions older than %d.%d" 848*7c478bd9Sstevel@tonic-gate " are no longer supported (cpu #%d)", 849*7c478bd9Sstevel@tonic-gate CHEETAH_MAJOR_VERSION(min_supported_rev), 850*7c478bd9Sstevel@tonic-gate CHEETAH_MINOR_VERSION(min_supported_rev), i); 851*7c478bd9Sstevel@tonic-gate } 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate #ifdef JALAPENO_ERRATA_85 856*7c478bd9Sstevel@tonic-gate if (IS_JALAPENO(impl) && (cpunodes[i].version < 0x24)) { 857*7c478bd9Sstevel@tonic-gate jp_errata_85_allow_slow_scrub = 0; 858*7c478bd9Sstevel@tonic-gate jp_errata_85_enable = 1; 859*7c478bd9Sstevel@tonic-gate } 860*7c478bd9Sstevel@tonic-gate #endif /* JALAPENO_ERRATA_85 */ 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate } 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate /* 865*7c478bd9Sstevel@tonic-gate * Check for a legal set of CPUs. 866*7c478bd9Sstevel@tonic-gate */ 867*7c478bd9Sstevel@tonic-gate static void 868*7c478bd9Sstevel@tonic-gate check_cpus_set(void) 869*7c478bd9Sstevel@tonic-gate { 870*7c478bd9Sstevel@tonic-gate int i; 871*7c478bd9Sstevel@tonic-gate int impl; 872*7c478bd9Sstevel@tonic-gate int npanther = 0; 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate impl = cpunodes[getprocessorid()].implementation; 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate switch (impl) { 877*7c478bd9Sstevel@tonic-gate case CHEETAH_PLUS_IMPL: 878*7c478bd9Sstevel@tonic-gate case JAGUAR_IMPL: 879*7c478bd9Sstevel@tonic-gate case PANTHER_IMPL: 880*7c478bd9Sstevel@tonic-gate /* 881*7c478bd9Sstevel@tonic-gate * Check for a legal heterogeneous set of CPUs. 882*7c478bd9Sstevel@tonic-gate */ 883*7c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 884*7c478bd9Sstevel@tonic-gate if (cpunodes[i].nodeid == 0) 885*7c478bd9Sstevel@tonic-gate continue; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate if (IS_PANTHER(cpunodes[i].implementation)) { 888*7c478bd9Sstevel@tonic-gate npanther += 1; 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate if (!(IS_CHEETAH_PLUS(cpunodes[i].implementation) || 892*7c478bd9Sstevel@tonic-gate IS_JAGUAR(cpunodes[i].implementation) || 893*7c478bd9Sstevel@tonic-gate IS_PANTHER(cpunodes[i].implementation))) { 894*7c478bd9Sstevel@tonic-gate use_mp = 0; 895*7c478bd9Sstevel@tonic-gate break; 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate } 898*7c478bd9Sstevel@tonic-gate break; 899*7c478bd9Sstevel@tonic-gate default: 900*7c478bd9Sstevel@tonic-gate /* 901*7c478bd9Sstevel@tonic-gate * Check for a homogeneous set of CPUs. 902*7c478bd9Sstevel@tonic-gate */ 903*7c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 904*7c478bd9Sstevel@tonic-gate if (cpunodes[i].nodeid == 0) 905*7c478bd9Sstevel@tonic-gate continue; 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate if (cpunodes[i].implementation != impl) { 908*7c478bd9Sstevel@tonic-gate use_mp = 0; 909*7c478bd9Sstevel@tonic-gate break; 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate break; 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate /* 916*7c478bd9Sstevel@tonic-gate * Change from mmu_page_sizes from 4 to 6 for totally-Panther domains, 917*7c478bd9Sstevel@tonic-gate * where npanther == ncpunode. 918*7c478bd9Sstevel@tonic-gate */ 919*7c478bd9Sstevel@tonic-gate if (&mmu_init_mmu_page_sizes) { 920*7c478bd9Sstevel@tonic-gate (void) mmu_init_mmu_page_sizes(npanther); 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate /* 924*7c478bd9Sstevel@tonic-gate * Set max cpus we can have based on ncpunode and use_mp 925*7c478bd9Sstevel@tonic-gate */ 926*7c478bd9Sstevel@tonic-gate if (use_mp) { 927*7c478bd9Sstevel@tonic-gate int (*set_max_ncpus)(void); 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate set_max_ncpus = (int (*)(void)) 930*7c478bd9Sstevel@tonic-gate kobj_getsymvalue("set_platform_max_ncpus", 0); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate if (set_max_ncpus) { 933*7c478bd9Sstevel@tonic-gate max_ncpus = set_max_ncpus(); 934*7c478bd9Sstevel@tonic-gate if (max_ncpus < ncpunode) 935*7c478bd9Sstevel@tonic-gate max_ncpus = ncpunode; 936*7c478bd9Sstevel@tonic-gate boot_max_ncpus = ncpunode; 937*7c478bd9Sstevel@tonic-gate } else { 938*7c478bd9Sstevel@tonic-gate max_ncpus = ncpunode; 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate } else { 941*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "MP not supported on mismatched modules," 942*7c478bd9Sstevel@tonic-gate " booting UP only"); 943*7c478bd9Sstevel@tonic-gate 944*7c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 945*7c478bd9Sstevel@tonic-gate if (cpunodes[i].nodeid == 0) 946*7c478bd9Sstevel@tonic-gate continue; 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cpu%d: %s version 0x%x", i, 949*7c478bd9Sstevel@tonic-gate cpunodes[i].name, cpunodes[i].version); 950*7c478bd9Sstevel@tonic-gate } 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate max_ncpus = 1; 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate /* 957*7c478bd9Sstevel@tonic-gate * The first sysio must always programmed up for the system clock and error 958*7c478bd9Sstevel@tonic-gate * handling purposes, referenced by v_sysio_addr in machdep.c. 959*7c478bd9Sstevel@tonic-gate */ 960*7c478bd9Sstevel@tonic-gate static void 961*7c478bd9Sstevel@tonic-gate have_sbus(dnode_t node) 962*7c478bd9Sstevel@tonic-gate { 963*7c478bd9Sstevel@tonic-gate int size; 964*7c478bd9Sstevel@tonic-gate uint_t portid; 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate size = GETPROPLEN(node, "upa-portid"); 967*7c478bd9Sstevel@tonic-gate if (size == -1 || size > sizeof (portid)) 968*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "upa-portid size"); 969*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "upa-portid", (caddr_t)&portid) == -1) 970*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "upa-portid"); 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate niobus++; 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate /* 975*7c478bd9Sstevel@tonic-gate * need one physical TSB 976*7c478bd9Sstevel@tonic-gate */ 977*7c478bd9Sstevel@tonic-gate niommu_tsbs++; 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate #define IOMMU_PER_SCHIZO 2 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate /* 984*7c478bd9Sstevel@tonic-gate * The first psycho must always programmed up for the system clock and error 985*7c478bd9Sstevel@tonic-gate * handling purposes. 986*7c478bd9Sstevel@tonic-gate */ 987*7c478bd9Sstevel@tonic-gate static void 988*7c478bd9Sstevel@tonic-gate have_pci(dnode_t node) 989*7c478bd9Sstevel@tonic-gate { 990*7c478bd9Sstevel@tonic-gate int size; 991*7c478bd9Sstevel@tonic-gate uint_t portid; 992*7c478bd9Sstevel@tonic-gate char compatible[OBP_MAXDRVNAME]; 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate size = GETPROPLEN(node, "portid"); 995*7c478bd9Sstevel@tonic-gate if (size == -1) size = GETPROPLEN(node, "upa-portid"); 996*7c478bd9Sstevel@tonic-gate if (size == -1) 997*7c478bd9Sstevel@tonic-gate return; 998*7c478bd9Sstevel@tonic-gate if (size > sizeof (portid)) 999*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "portid size wrong"); 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "portid", (caddr_t)&portid) == -1) 1002*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "upa-portid", (caddr_t)&portid) == -1) 1003*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "portid not found"); 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate niobus++; 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate /* 1009*7c478bd9Sstevel@tonic-gate * Need two physical TSBs for Schizo compatible nodes, 1010*7c478bd9Sstevel@tonic-gate * one otherwise. 1011*7c478bd9Sstevel@tonic-gate */ 1012*7c478bd9Sstevel@tonic-gate compatible[0] = '\0'; 1013*7c478bd9Sstevel@tonic-gate (void) prom_getprop(node, OBP_COMPATIBLE, compatible); 1014*7c478bd9Sstevel@tonic-gate if (strcmp(compatible, "pci108e,8001") == 0) 1015*7c478bd9Sstevel@tonic-gate niommu_tsbs += IOMMU_PER_SCHIZO; 1016*7c478bd9Sstevel@tonic-gate else 1017*7c478bd9Sstevel@tonic-gate niommu_tsbs++; 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate /* 1021*7c478bd9Sstevel@tonic-gate * The first eeprom is used as the TOD clock, referenced 1022*7c478bd9Sstevel@tonic-gate * by v_eeprom_addr in locore.s. 1023*7c478bd9Sstevel@tonic-gate */ 1024*7c478bd9Sstevel@tonic-gate static void 1025*7c478bd9Sstevel@tonic-gate have_eeprom(dnode_t node) 1026*7c478bd9Sstevel@tonic-gate { 1027*7c478bd9Sstevel@tonic-gate int size; 1028*7c478bd9Sstevel@tonic-gate uint32_t eaddr; 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate /* 1031*7c478bd9Sstevel@tonic-gate * "todmostek" module will be selected based on finding a "model" 1032*7c478bd9Sstevel@tonic-gate * property value of "mk48t59" in the "eeprom" node. 1033*7c478bd9Sstevel@tonic-gate */ 1034*7c478bd9Sstevel@tonic-gate if (tod_module_name == NULL) { 1035*7c478bd9Sstevel@tonic-gate char buf[MAXSYSNAME]; 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate if ((GETPROP(node, "model", buf) != -1) && 1038*7c478bd9Sstevel@tonic-gate (strcmp(buf, "mk48t59") == 0)) 1039*7c478bd9Sstevel@tonic-gate tod_module_name = "todmostek"; 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate /* 1043*7c478bd9Sstevel@tonic-gate * If we have found two distinct eeprom's, then we're done. 1044*7c478bd9Sstevel@tonic-gate */ 1045*7c478bd9Sstevel@tonic-gate if (v_eeprom_addr && v_timecheck_addr != v_eeprom_addr) 1046*7c478bd9Sstevel@tonic-gate return; 1047*7c478bd9Sstevel@tonic-gate 1048*7c478bd9Sstevel@tonic-gate /* 1049*7c478bd9Sstevel@tonic-gate * multiple eeproms may exist but at least 1050*7c478bd9Sstevel@tonic-gate * one must have an "address" property 1051*7c478bd9Sstevel@tonic-gate */ 1052*7c478bd9Sstevel@tonic-gate if ((size = GETPROPLEN(node, OBP_ADDRESS)) == -1) 1053*7c478bd9Sstevel@tonic-gate return; 1054*7c478bd9Sstevel@tonic-gate if (size != sizeof (eaddr)) 1055*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "eeprom addr size"); 1056*7c478bd9Sstevel@tonic-gate if (GETPROP(node, OBP_ADDRESS, (caddr_t)&eaddr) == -1) 1057*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "eeprom addr"); 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate /* 1060*7c478bd9Sstevel@tonic-gate * If we have a chosen eeprom and it is not this node, keep looking. 1061*7c478bd9Sstevel@tonic-gate */ 1062*7c478bd9Sstevel@tonic-gate if (chosen_eeprom != NULL && chosen_eeprom != node) { 1063*7c478bd9Sstevel@tonic-gate v_timecheck_addr = (caddr_t)eaddr; 1064*7c478bd9Sstevel@tonic-gate return; 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate v_eeprom_addr = (caddr_t)eaddr; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate /* 1070*7c478bd9Sstevel@tonic-gate * If we don't find an I/O board to use to check the clock, 1071*7c478bd9Sstevel@tonic-gate * we'll fall back on whichever TOD is available. 1072*7c478bd9Sstevel@tonic-gate */ 1073*7c478bd9Sstevel@tonic-gate if (v_timecheck_addr == NULL) 1074*7c478bd9Sstevel@tonic-gate v_timecheck_addr = v_eeprom_addr; 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate /* 1077*7c478bd9Sstevel@tonic-gate * Does this eeprom have watchdog support? 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate if (GETPROPLEN(node, WATCHDOG_ENABLE) != -1) 1080*7c478bd9Sstevel@tonic-gate watchdog_available = 1; 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate static void 1084*7c478bd9Sstevel@tonic-gate have_rtc(dnode_t node) 1085*7c478bd9Sstevel@tonic-gate { 1086*7c478bd9Sstevel@tonic-gate int size; 1087*7c478bd9Sstevel@tonic-gate uint32_t eaddr; 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate /* 1090*7c478bd9Sstevel@tonic-gate * "ds1287" module will be selected based on finding a "model" 1091*7c478bd9Sstevel@tonic-gate * property value of "ds1287" in the "rtc" node. 1092*7c478bd9Sstevel@tonic-gate */ 1093*7c478bd9Sstevel@tonic-gate if (tod_module_name == NULL) { 1094*7c478bd9Sstevel@tonic-gate char buf[MAXSYSNAME]; 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate if (GETPROP(node, "model", buf) != -1) { 1097*7c478bd9Sstevel@tonic-gate if ((strcmp(buf, "m5819p") == 0) || 1098*7c478bd9Sstevel@tonic-gate (strcmp(buf, "m5823") == 0)) 1099*7c478bd9Sstevel@tonic-gate tod_module_name = "todm5823"; 1100*7c478bd9Sstevel@tonic-gate else if (strcmp(buf, "ds1287") == 0) 1101*7c478bd9Sstevel@tonic-gate tod_module_name = "todds1287"; 1102*7c478bd9Sstevel@tonic-gate } 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate /* 1106*7c478bd9Sstevel@tonic-gate * XXX - drives on if address prop doesn't exist, later falls 1107*7c478bd9Sstevel@tonic-gate * over in tod module 1108*7c478bd9Sstevel@tonic-gate */ 1109*7c478bd9Sstevel@tonic-gate if ((size = GETPROPLEN(node, OBP_ADDRESS)) == -1) 1110*7c478bd9Sstevel@tonic-gate return; 1111*7c478bd9Sstevel@tonic-gate if (size != sizeof (eaddr)) 1112*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "rtc addr size"); 1113*7c478bd9Sstevel@tonic-gate if (GETPROP(node, OBP_ADDRESS, (caddr_t)&eaddr) == -1) 1114*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "rtc addr"); 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate v_rtc_addr_reg = (caddr_t)eaddr; 1117*7c478bd9Sstevel@tonic-gate v_rtc_data_reg = (volatile unsigned char *)eaddr + 1; 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* 1120*7c478bd9Sstevel@tonic-gate * Does this rtc have watchdog support? 1121*7c478bd9Sstevel@tonic-gate */ 1122*7c478bd9Sstevel@tonic-gate if (GETPROPLEN(node, WATCHDOG_ENABLE) != -1) 1123*7c478bd9Sstevel@tonic-gate watchdog_available = 1; 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate static void 1127*7c478bd9Sstevel@tonic-gate have_pmc(dnode_t node) 1128*7c478bd9Sstevel@tonic-gate { 1129*7c478bd9Sstevel@tonic-gate uint32_t vaddr; 1130*7c478bd9Sstevel@tonic-gate dnode_t root; 1131*7c478bd9Sstevel@tonic-gate 1132*7c478bd9Sstevel@tonic-gate /* 1133*7c478bd9Sstevel@tonic-gate * Watchdog property is in the root node. 1134*7c478bd9Sstevel@tonic-gate */ 1135*7c478bd9Sstevel@tonic-gate root = prom_nextnode((dnode_t)0); 1136*7c478bd9Sstevel@tonic-gate if (GETPROPLEN(root, WATCHDOG_ENABLE) != -1) { 1137*7c478bd9Sstevel@tonic-gate /* 1138*7c478bd9Sstevel@tonic-gate * The hardware watchdog timer resides within logical 1139*7c478bd9Sstevel@tonic-gate * unit 8 of SuperI/O. The address property of the node 1140*7c478bd9Sstevel@tonic-gate * contains the virtual address that we use to program 1141*7c478bd9Sstevel@tonic-gate * the timer. 1142*7c478bd9Sstevel@tonic-gate */ 1143*7c478bd9Sstevel@tonic-gate if (GETPROP(node, OBP_ADDRESS, (caddr_t)&vaddr) == -1) { 1144*7c478bd9Sstevel@tonic-gate watchdog_available = 0; 1145*7c478bd9Sstevel@tonic-gate return; 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate v_pmc_addr_reg = (volatile uint8_t *)vaddr; 1148*7c478bd9Sstevel@tonic-gate v_pmc_data_reg = (volatile uint8_t *)vaddr + 1; 1149*7c478bd9Sstevel@tonic-gate watchdog_available = 1; 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate static void 1154*7c478bd9Sstevel@tonic-gate have_auxio(dnode_t node) 1155*7c478bd9Sstevel@tonic-gate { 1156*7c478bd9Sstevel@tonic-gate size_t size, n; 1157*7c478bd9Sstevel@tonic-gate uint32_t addr[5]; 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate /* 1160*7c478bd9Sstevel@tonic-gate * Get the size of the auzio's address property. 1161*7c478bd9Sstevel@tonic-gate * On some platforms, the address property contains one 1162*7c478bd9Sstevel@tonic-gate * entry and on others it contains five entries. 1163*7c478bd9Sstevel@tonic-gate * In all cases, the first entries are compatible. 1164*7c478bd9Sstevel@tonic-gate * 1165*7c478bd9Sstevel@tonic-gate * This routine gets the address property for the auxio 1166*7c478bd9Sstevel@tonic-gate * node and stores the first entry in v_auxio_addr which 1167*7c478bd9Sstevel@tonic-gate * is used by the routine set_auxioreg in sun4u/ml/locore.s. 1168*7c478bd9Sstevel@tonic-gate */ 1169*7c478bd9Sstevel@tonic-gate if ((size = GETPROPLEN(node, OBP_ADDRESS)) == -1) 1170*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "no auxio address property"); 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate switch (n = (size / sizeof (addr[0]))) { 1173*7c478bd9Sstevel@tonic-gate case 1: 1174*7c478bd9Sstevel@tonic-gate break; 1175*7c478bd9Sstevel@tonic-gate case 5: 1176*7c478bd9Sstevel@tonic-gate break; 1177*7c478bd9Sstevel@tonic-gate default: 1178*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "auxio addr has %lu entries?", n); 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate 1181*7c478bd9Sstevel@tonic-gate if (GETPROP(node, OBP_ADDRESS, (caddr_t)addr) == -1) 1182*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "auxio addr"); 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate v_auxio_addr = (caddr_t)addr[0]; /* make into a C pointer */ 1185*7c478bd9Sstevel@tonic-gate } 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate static void 1188*7c478bd9Sstevel@tonic-gate have_tod(dnode_t node) 1189*7c478bd9Sstevel@tonic-gate { 1190*7c478bd9Sstevel@tonic-gate static char tod_name[MAXSYSNAME]; 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate if (GETPROP(node, OBP_NAME, (caddr_t)tod_name) == -1) 1193*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "tod name"); 1194*7c478bd9Sstevel@tonic-gate /* 1195*7c478bd9Sstevel@tonic-gate * This is a node with "device_type" property value of "tod". 1196*7c478bd9Sstevel@tonic-gate * Name of the tod module is the name from the node. 1197*7c478bd9Sstevel@tonic-gate */ 1198*7c478bd9Sstevel@tonic-gate tod_module_name = tod_name; 1199*7c478bd9Sstevel@tonic-gate } 1200