1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/errno.h> 30 #include <sys/types.h> 31 #include <sys/param.h> 32 #include <sys/cpu.h> 33 #include <sys/cpuvar.h> 34 #include <sys/clock.h> 35 #include <sys/promif.h> 36 #include <sys/promimpl.h> 37 #include <sys/systm.h> 38 #include <sys/machsystm.h> 39 #include <sys/debug.h> 40 #include <sys/sunddi.h> 41 #include <sys/modctl.h> 42 #include <sys/cpu_module.h> 43 #include <sys/kobj.h> 44 #include <sys/cmp.h> 45 #include <sys/async.h> 46 #include <vm/page.h> 47 48 /* 49 * The OpenBoot Standalone Interface supplies the kernel with 50 * implementation dependent parameters through the devinfo/property mechanism 51 */ 52 typedef enum { XDRBOOL, XDRINT, XDRSTRING } xdrs; 53 54 /* 55 * structure describing properties that we are interested in querying the 56 * OBP for. 57 */ 58 struct getprop_info { 59 char *name; 60 xdrs type; 61 uint_t *var; 62 }; 63 64 /* 65 * structure used to convert between a string returned by the OBP & a type 66 * used within the kernel. We prefer to paramaterize rather than type. 67 */ 68 struct convert_info { 69 char *name; 70 uint_t var; 71 char *realname; 72 }; 73 74 /* 75 * structure describing nodes that we are interested in querying the OBP for 76 * properties. 77 */ 78 struct node_info { 79 char *name; 80 int size; 81 struct getprop_info *prop; 82 struct getprop_info *prop_end; 83 unsigned int *value; 84 }; 85 86 /* 87 * macro definitions for routines that form the OBP interface 88 */ 89 #define NEXT prom_nextnode 90 #define CHILD prom_childnode 91 #define GETPROP prom_getprop 92 #define GETPROPLEN prom_getproplen 93 94 /* 0=quiet; 1=verbose; 2=debug */ 95 int debug_fillsysinfo = 0; 96 #define VPRINTF if (debug_fillsysinfo) prom_printf 97 98 int ncpunode; 99 struct cpu_node cpunodes[NCPU]; 100 101 void fill_cpu(dnode_t); 102 void plat_fill_mc(dnode_t); 103 #pragma weak plat_fill_mc 104 105 uint64_t system_clock_freq; 106 int niobus = 0; 107 uint_t niommu_tsbs = 0; 108 109 /* 110 * Hardware watchdog support. 111 */ 112 #define CHOSEN_EEPROM "eeprom" 113 static dnode_t chosen_eeprom; 114 115 /* 116 * If this variable is non-zero, cpr should return "not supported" when 117 * it is queried even though it would normally be supported on this platform. 118 */ 119 int cpr_supported_override; 120 121 /* 122 * Some platforms may need to support CPR even in the absence of the 123 * energystar-v* property (Enchilada server, for example). If this 124 * variable is non-zero, cpr should proceed even in the absence 125 * of the energystar-v* property. 126 */ 127 int cpr_platform_enable = 0; 128 129 /* 130 * Some nodes have functions that need to be called when they're seen. 131 */ 132 static void have_pci(dnode_t); 133 134 static struct wkdevice { 135 char *wk_namep; 136 void (*wk_func)(dnode_t); 137 caddr_t *wk_vaddrp; 138 ushort_t wk_flags; 139 #define V_OPTIONAL 0x0000 140 #define V_MUSTHAVE 0x0001 141 #define V_MAPPED 0x0002 142 #define V_MULTI 0x0003 /* optional, may be more than one */ 143 } wkdevice[] = { 144 { "pci", have_pci, NULL, V_MULTI }, 145 { 0, }, 146 }; 147 148 static void map_wellknown(dnode_t); 149 150 void 151 map_wellknown_devices() 152 { 153 struct wkdevice *wkp; 154 phandle_t ieeprom; 155 dnode_t root; 156 uint_t stick_freq; 157 158 /* 159 * if there is a chosen eeprom, note it (for have_eeprom()) 160 */ 161 if (GETPROPLEN(prom_chosennode(), CHOSEN_EEPROM) == 162 sizeof (phandle_t) && 163 GETPROP(prom_chosennode(), CHOSEN_EEPROM, (caddr_t)&ieeprom) != -1) 164 chosen_eeprom = (dnode_t)prom_decode_int(ieeprom); 165 166 root = prom_nextnode((dnode_t)0); 167 /* 168 * Get System clock frequency from root node if it exists. 169 */ 170 if (GETPROP(root, "stick-frequency", (caddr_t)&stick_freq) != -1) 171 system_clock_freq = stick_freq; 172 173 map_wellknown(NEXT((dnode_t)0)); 174 175 /* 176 * See if it worked 177 */ 178 for (wkp = wkdevice; wkp->wk_namep; ++wkp) { 179 if (wkp->wk_flags == V_MUSTHAVE) { 180 cmn_err(CE_PANIC, "map_wellknown_devices: required " 181 "device %s not mapped", wkp->wk_namep); 182 } 183 } 184 } 185 186 /* 187 * map_wellknown - map known devices & registers 188 */ 189 static void 190 map_wellknown(dnode_t curnode) 191 { 192 extern int status_okay(int, char *, int); 193 char tmp_name[MAXSYSNAME]; 194 static void fill_address(dnode_t, char *); 195 int sok; 196 197 #ifdef VPRINTF 198 VPRINTF("map_wellknown(%x)\n", curnode); 199 #endif /* VPRINTF */ 200 201 for (curnode = CHILD(curnode); curnode; curnode = NEXT(curnode)) { 202 /* 203 * prune subtree if status property indicating not okay 204 */ 205 sok = status_okay((int)curnode, (char *)NULL, 0); 206 if (!sok) { 207 char devtype_buf[OBP_MAXPROPNAME]; 208 int size; 209 210 #ifdef VPRINTF 211 VPRINTF("map_wellknown: !okay status property\n"); 212 #endif /* VPRINTF */ 213 /* 214 * a status property indicating bad memory will be 215 * associated with a node which has a "device_type" 216 * property with a value of "memory-controller" 217 */ 218 if ((size = GETPROPLEN(curnode, 219 OBP_DEVICETYPE)) == -1) 220 continue; 221 if (size > OBP_MAXPROPNAME) { 222 cmn_err(CE_CONT, "node %x '%s' prop too " 223 "big\n", curnode, OBP_DEVICETYPE); 224 continue; 225 } 226 if (GETPROP(curnode, OBP_DEVICETYPE, 227 devtype_buf) == -1) { 228 cmn_err(CE_CONT, "node %x '%s' get failed\n", 229 curnode, OBP_DEVICETYPE); 230 continue; 231 } 232 if (strcmp(devtype_buf, "memory-controller") != 0) 233 continue; 234 /* 235 * ...else fall thru and process the node... 236 */ 237 } 238 bzero(tmp_name, MAXSYSNAME); 239 if (GETPROP(curnode, OBP_NAME, (caddr_t)tmp_name) != -1) 240 fill_address(curnode, tmp_name); 241 if (GETPROP(curnode, OBP_DEVICETYPE, tmp_name) != -1 && 242 strcmp(tmp_name, "cpu") == 0) { 243 fill_cpu(curnode); 244 } 245 246 if (sok && (strcmp(tmp_name, "memory-controller") == 0) && 247 (&plat_fill_mc != NULL)) 248 plat_fill_mc(curnode); 249 map_wellknown(curnode); 250 } 251 } 252 253 static void 254 fill_address(dnode_t curnode, char *namep) 255 { 256 struct wkdevice *wkp; 257 int size; 258 uint32_t vaddr; 259 260 for (wkp = wkdevice; wkp->wk_namep; ++wkp) { 261 if (strcmp(wkp->wk_namep, namep) != 0) 262 continue; 263 if (wkp->wk_flags == V_MAPPED) 264 return; 265 if (wkp->wk_vaddrp != NULL) { 266 if ((size = GETPROPLEN(curnode, OBP_ADDRESS)) == -1) { 267 cmn_err(CE_CONT, "device %s size %d\n", 268 namep, size); 269 continue; 270 } 271 if (size != sizeof (vaddr)) { 272 cmn_err(CE_CONT, "device %s address prop too " 273 "big\n", namep); 274 continue; 275 } 276 if (GETPROP(curnode, OBP_ADDRESS, 277 (caddr_t)&vaddr) == -1) { 278 cmn_err(CE_CONT, "device %s not mapped\n", 279 namep); 280 continue; 281 } 282 283 /* make into a native pointer */ 284 *wkp->wk_vaddrp = (caddr_t)vaddr; 285 #ifdef VPRINTF 286 VPRINTF("fill_address: %s mapped to %x\n", namep, 287 *wkp->wk_vaddrp); 288 #endif /* VPRINTF */ 289 } 290 if (wkp->wk_func != NULL) 291 (*wkp->wk_func)(curnode); 292 /* 293 * If this one is optional and there may be more than 294 * one, don't set V_MAPPED, which would cause us to skip it 295 * next time around 296 */ 297 if (wkp->wk_flags != V_MULTI) 298 wkp->wk_flags = V_MAPPED; 299 } 300 } 301 302 void 303 fill_cpu(dnode_t node) 304 { 305 struct cpu_node *cpunode; 306 processorid_t cpuid; 307 uint_t clk_freq; 308 char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN]; 309 char *namebufp; 310 311 if (GETPROP(node, "cpuid", (caddr_t)&cpuid) == -1) { 312 if (GETPROP(node, "reg", (caddr_t)&cpuid) == -1) 313 cmn_err(CE_PANIC, "reg prop not found in cpu node"); 314 cpuid = PROM_CFGHDL_TO_CPUID(cpuid); 315 } 316 317 if (cpuid < 0 || cpuid >= NCPU) { 318 cmn_err(CE_CONT, "cpu (dnode %x): out of range cpuid %d - " 319 "cpu excluded from configuration\n", node, cpuid); 320 return; 321 } 322 323 cpunode = &cpunodes[cpuid]; 324 cpunode->cpuid = cpuid; 325 cpunode->device_id = cpuid; 326 327 unum[0] = '\0'; 328 (void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri), 329 "%s%s", CPU_FRU_FMRI, unum); 330 (void) GETPROP(node, "compatible", namebuf); 331 namebufp = namebuf; 332 if (strncmp(namebufp, "SUNW,", 5) == 0) 333 namebufp += 5; 334 (void) strcpy(cpunode->name, namebufp); 335 336 if (GETPROP(node, "clock-frequency", (caddr_t)&clk_freq) == -1) { 337 /* 338 * If we didn't find it in the CPU node, look in the root node. 339 */ 340 dnode_t root = prom_nextnode((dnode_t)0); 341 if (GETPROP(root, "clock-frequency", (caddr_t)&clk_freq) == -1) 342 clk_freq = 0; 343 } 344 cpunode->clock_freq = clk_freq; 345 346 ASSERT(cpunode->clock_freq != 0); 347 /* 348 * Compute scaling factor based on rate of %tick. This is used 349 * to convert from ticks derived from %tick to nanoseconds. See 350 * comment in sun4u/sys/clock.h for details. 351 */ 352 cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 353 (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 354 355 356 cpunode->nodeid = node; 357 358 /* 359 * Call cpu module specific code to fill in the cpu properities 360 */ 361 cpu_fiximp(cpunode); 362 } 363 364 #define IOMMU_PER_SCHIZO 2 365 366 /* 367 * The first psycho must always programmed up for the system clock and error 368 * handling purposes. 369 */ 370 static void 371 have_pci(dnode_t node) 372 { 373 int size; 374 uint_t portid; 375 char compatible[OBP_MAXDRVNAME]; 376 377 size = GETPROPLEN(node, "portid"); 378 if (size == -1) size = GETPROPLEN(node, "upa-portid"); 379 if (size == -1) 380 return; 381 if (size > sizeof (portid)) 382 cmn_err(CE_PANIC, "portid size wrong"); 383 384 if (GETPROP(node, "portid", (caddr_t)&portid) == -1) 385 if (GETPROP(node, "upa-portid", (caddr_t)&portid) == -1) 386 cmn_err(CE_PANIC, "portid not found"); 387 388 niobus++; 389 390 391 /* 392 * Need two physical TSBs for Schizo-compatible nodes, 393 * one otherwise. 394 */ 395 compatible[0] = '\0'; 396 (void) prom_getprop(node, OBP_COMPATIBLE, compatible); 397 if (strcmp(compatible, "pci108e,8001") == 0) 398 niommu_tsbs += IOMMU_PER_SCHIZO; 399 else 400 niommu_tsbs++; 401 } 402 403 404 int 405 get_cpu_pagesizes(void) 406 { 407 /* 408 * XXXQ Get supported page sizes information from the PD 409 * and return a bit mask indicating which page sizes are 410 * supported. 411 * 412 * Return 0 when no information is available. 413 */ 414 415 return (0); /* XXXQ for now return 0 as no PD */ 416 } 417