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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 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/param.h> 30 #include <sys/systm.h> 31 #include <sys/sysmacros.h> 32 #include <sys/sunddi.h> 33 #include <sys/esunddi.h> 34 35 #include <sys/platform_module.h> 36 #include <sys/errno.h> 37 #include <sys/cpu_sgnblk_defs.h> 38 #include <sys/rmc_comm_dp.h> 39 #include <sys/rmc_comm_drvintf.h> 40 #include <sys/modctl.h> 41 #include <sys/lgrp.h> 42 #include <sys/memnode.h> 43 #include <sys/promif.h> 44 45 /* Anything related to shared i2c access applies to Seattle only */ 46 #define SHARED_MI2CV_PATH "/i2c@1f,530000" 47 static dev_info_t *shared_mi2cv_dip; 48 static kmutex_t mi2cv_mutex; 49 50 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *); 51 static void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); 52 int (*rmc_req_now)(rmc_comm_msg_t *, uint8_t) = NULL; 53 54 void 55 startup_platform(void) 56 { 57 mutex_init(&mi2cv_mutex, NULL, NULL, NULL); 58 } 59 60 int 61 set_platform_tsb_spares() 62 { 63 return (0); 64 } 65 66 void 67 set_platform_defaults(void) 68 { 69 extern char *tod_module_name; 70 /* Set appropriate tod module */ 71 if (tod_module_name == NULL) 72 tod_module_name = "todm5823"; 73 74 cpu_sgn_func = cpu_sgn_update; 75 } 76 77 /* 78 * Definitions for accessing the pci config space of the isa node 79 * of Southbridge. 80 */ 81 static ddi_acc_handle_t isa_handle = NULL; /* handle for isa pci space */ 82 83 /* 84 * Definition for accessing rmclomv 85 */ 86 #define RMCLOMV_PATHNAME "/pseudo/rmclomv@0" 87 88 void 89 load_platform_drivers(void) 90 { 91 dev_info_t *rmclomv_dip; 92 /* 93 * It is OK to return error because 'us' driver is not available 94 * in all clusters (e.g. missing in Core cluster). 95 */ 96 (void) i_ddi_attach_hw_nodes("us"); 97 98 99 /* 100 * mc-us3i must stay loaded for plat_get_mem_unum() 101 */ 102 if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS) 103 cmn_err(CE_WARN, "mc-us3i driver failed to install"); 104 (void) ddi_hold_driver(ddi_name_to_major("mc-us3i")); 105 106 /* 107 * load the power button driver 108 */ 109 if (i_ddi_attach_hw_nodes("power") != DDI_SUCCESS) 110 cmn_err(CE_WARN, "power button driver failed to install"); 111 else 112 (void) ddi_hold_driver(ddi_name_to_major("power")); 113 114 /* 115 * load the GPIO driver for the ALOM reset and watchdog lines 116 */ 117 if (i_ddi_attach_hw_nodes("pmugpio") != DDI_SUCCESS) 118 cmn_err(CE_WARN, "pmugpio failed to install"); 119 else { 120 extern int watchdog_enable, watchdog_available; 121 extern int disable_watchdog_on_exit; 122 123 /* 124 * Disable an active h/w watchdog timer upon exit to OBP. 125 */ 126 disable_watchdog_on_exit = 1; 127 128 watchdog_enable = 1; 129 watchdog_available = 1; 130 } 131 (void) ddi_hold_driver(ddi_name_to_major("pmugpio")); 132 133 /* 134 * Figure out which mi2cv dip is shared with OBP for the nvram 135 * device, so the lock can be acquired. 136 */ 137 shared_mi2cv_dip = e_ddi_hold_devi_by_path(SHARED_MI2CV_PATH, 0); 138 /* 139 * Load the environmentals driver (rmclomv) 140 * 141 * We need this driver to handle events from the RMC when state 142 * changes occur in the environmental data. 143 */ 144 if (i_ddi_attach_hw_nodes("rmc_comm") != DDI_SUCCESS) { 145 cmn_err(CE_WARN, "rmc_comm failed to install"); 146 } else { 147 (void) ddi_hold_driver(ddi_name_to_major("rmc_comm")); 148 149 rmclomv_dip = e_ddi_hold_devi_by_path(RMCLOMV_PATHNAME, 0); 150 if (rmclomv_dip == NULL) { 151 cmn_err(CE_WARN, "Could not install rmclomv driver\n"); 152 } 153 } 154 155 /* 156 * create a handle to the rmc_comm_request_nowait() function 157 * inside the rmc_comm module. 158 * 159 * The Seattle/Boston todm5823 driver will use this handle to 160 * use the rmc_comm_request_nowait() function to send time/date 161 * updates to ALOM. 162 */ 163 rmc_req_now = (int (*)(rmc_comm_msg_t *, uint8_t)) 164 modgetsymvalue("rmc_comm_request_nowait", 0); 165 } 166 167 /* 168 * This routine is needed if a device error or timeout occurs before the 169 * driver is loaded. 170 */ 171 /*ARGSUSED*/ 172 int 173 plat_ide_chipreset(dev_info_t *dip, int chno) 174 { 175 int ret = DDI_SUCCESS; 176 177 if (isa_handle == NULL) { 178 return (DDI_FAILURE); 179 } 180 181 /* 182 * This will be filled in with the reset logic 183 * for the ULI1573 when that becomes available. 184 * currently this is just a stub. 185 */ 186 return (ret); 187 } 188 189 190 /*ARGSUSED*/ 191 int 192 plat_cpu_poweron(struct cpu *cp) 193 { 194 return (ENOTSUP); /* not supported on this platform */ 195 } 196 197 /*ARGSUSED*/ 198 int 199 plat_cpu_poweroff(struct cpu *cp) 200 { 201 return (ENOTSUP); /* not supported on this platform */ 202 } 203 204 /*ARGSUSED*/ 205 void 206 plat_freelist_process(int mnode) 207 { 208 } 209 210 char *platform_module_list[] = { 211 "mi2cv", 212 "pca9556", 213 (char *)0 214 }; 215 216 /*ARGSUSED*/ 217 void 218 plat_tod_fault(enum tod_fault_type tod_bad) 219 { 220 } 221 222 /*ARGSUSED*/ 223 int 224 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id, 225 int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp) 226 { 227 if (flt_in_memory && (p2get_mem_unum != NULL)) 228 return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8), 229 buf, buflen, lenp)); 230 else 231 return (ENOTSUP); 232 } 233 234 /* 235 * This platform hook gets called from mc_add_mem_unum_label() in the mc-us3i 236 * driver giving each platform the opportunity to add platform 237 * specific label information to the unum for ECC error logging purposes. 238 */ 239 /*ARGSUSED*/ 240 void 241 plat_add_mem_unum_label(char *unum, int mcid, int bank, int dimm) 242 { 243 char old_unum[UNUM_NAMLEN]; 244 int printed; 245 int buflen = UNUM_NAMLEN; 246 strcpy(old_unum, unum); 247 printed = snprintf(unum, buflen, "MB/P%d/B%d", mcid, bank); 248 buflen -= printed; 249 unum += printed; 250 251 if (dimm != -1) { 252 printed = snprintf(unum, buflen, "/D%d", dimm); 253 buflen -= printed; 254 unum += printed; 255 } 256 257 snprintf(unum, buflen, ": %s", old_unum); 258 } 259 260 /*ARGSUSED*/ 261 int 262 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) 263 { 264 if (snprintf(buf, buflen, "MB") >= buflen) { 265 return (ENOSPC); 266 } else { 267 *lenp = strlen(buf); 268 return (0); 269 } 270 } 271 272 /* 273 * Our nodename has been set, pass it along to the RMC. 274 */ 275 void 276 plat_nodename_set(void) 277 { 278 rmc_comm_msg_t req; /* request */ 279 int (*rmc_req_res)(rmc_comm_msg_t *, rmc_comm_msg_t *, time_t) = NULL; 280 281 /* 282 * find the symbol for the mailbox routine 283 */ 284 rmc_req_res = (int (*)(rmc_comm_msg_t *, rmc_comm_msg_t *, time_t)) 285 modgetsymvalue("rmc_comm_request_response", 0); 286 287 if (rmc_req_res == NULL) { 288 return; 289 } 290 291 /* 292 * construct the message telling the RMC our nodename 293 */ 294 req.msg_type = DP_SET_CPU_NODENAME; 295 req.msg_len = strlen(utsname.nodename) + 1; 296 req.msg_bytes = 0; 297 req.msg_buf = (caddr_t)utsname.nodename; 298 299 /* 300 * ship it 301 */ 302 (void) (rmc_req_res)(&req, NULL, 2000); 303 } 304 305 sig_state_t current_sgn; 306 307 /* 308 * cpu signatures - we're only interested in the overall system 309 * "signature" on this platform - not individual cpu signatures 310 */ 311 /*ARGSUSED*/ 312 static void 313 cpu_sgn_update(ushort_t sig, uchar_t state, uchar_t sub_state, int cpuid) 314 { 315 dp_cpu_signature_t signature; 316 rmc_comm_msg_t req; /* request */ 317 int (*rmc_req_res)(rmc_comm_msg_t *, rmc_comm_msg_t *, time_t) = NULL; 318 int (*rmc_req_now)(rmc_comm_msg_t *, uint8_t) = NULL; 319 320 321 /* 322 * Differentiate a panic reboot from a non-panic reboot in the 323 * setting of the substate of the signature. 324 * 325 * If the new substate is REBOOT and we're rebooting due to a panic, 326 * then set the new substate to a special value indicating a panic 327 * reboot, SIGSUBST_PANIC_REBOOT. 328 * 329 * A panic reboot is detected by a current (previous) signature 330 * state of SIGST_EXIT, and a new signature substate of SIGSUBST_REBOOT. 331 * The domain signature state SIGST_EXIT is used as the panic flow 332 * progresses. 333 * 334 * At the end of the panic flow, the reboot occurs but we should know 335 * one that was involuntary, something that may be quite useful to know 336 * at OBP level. 337 */ 338 if (state == SIGST_EXIT && sub_state == SIGSUBST_REBOOT) { 339 if (current_sgn.state_t.state == SIGST_EXIT && 340 current_sgn.state_t.sub_state != SIGSUBST_REBOOT) 341 sub_state = SIGSUBST_PANIC_REBOOT; 342 } 343 344 /* 345 * offline and detached states only apply to a specific cpu 346 * so ignore them. 347 */ 348 if (state == SIGST_OFFLINE || state == SIGST_DETACHED) { 349 return; 350 } 351 352 current_sgn.signature = CPU_SIG_BLD(sig, state, sub_state); 353 354 /* 355 * find the symbol for the mailbox routine 356 */ 357 rmc_req_res = (int (*)(rmc_comm_msg_t *, rmc_comm_msg_t *, time_t)) 358 modgetsymvalue("rmc_comm_request_response", 0); 359 if (rmc_req_res == NULL) { 360 return; 361 } 362 363 /* 364 * find the symbol for the mailbox routine 365 */ 366 rmc_req_now = (int (*)(rmc_comm_msg_t *, uint8_t)) 367 modgetsymvalue("rmc_comm_request_nowait", 0); 368 if (rmc_req_now == NULL) { 369 return; 370 } 371 372 signature.cpu_id = -1; 373 signature.sig = sig; 374 signature.states = state; 375 signature.sub_state = sub_state; 376 req.msg_type = DP_SET_CPU_SIGNATURE; 377 req.msg_len = (int)(sizeof (signature)); 378 req.msg_bytes = 0; 379 req.msg_buf = (caddr_t)&signature; 380 381 /* 382 * ship it 383 * - note that for panic or reboot need to send with nowait/urgent 384 */ 385 if (state == SIGST_EXIT && (sub_state == SIGSUBST_HALT || 386 sub_state == SIGSUBST_REBOOT || sub_state == SIGSUBST_ENVIRON || 387 sub_state == SIGSUBST_PANIC_REBOOT)) 388 (void) (rmc_req_now)(&req, RMC_COMM_DREQ_URGENT); 389 else 390 (void) (rmc_req_res)(&req, NULL, 2000); 391 } 392 393 /* 394 * Fiesta support for lgroups. 395 * 396 * On fiesta platform, an lgroup platform handle == CPU id 397 */ 398 399 /* 400 * Macro for extracting the CPU number from the CPU id 401 */ 402 #define CPUID_TO_LGRP(id) ((id) & 0x7) 403 #define PLATFORM_MC_SHIFT 36 404 405 /* 406 * Return the platform handle for the lgroup containing the given CPU 407 */ 408 void * 409 plat_lgrp_cpu_to_hand(processorid_t id) 410 { 411 return ((void *)(uintptr_t)CPUID_TO_LGRP(id)); 412 } 413 414 /* 415 * Platform specific lgroup initialization 416 */ 417 void 418 plat_lgrp_init(void) 419 { 420 pnode_t curnode; 421 char tmp_name[MAXSYSNAME]; 422 int portid; 423 int cpucnt = 0; 424 int max_portid = -1; 425 extern uint32_t lgrp_expand_proc_thresh; 426 extern uint32_t lgrp_expand_proc_diff; 427 extern pgcnt_t lgrp_mem_free_thresh; 428 extern uint32_t lgrp_loadavg_tolerance; 429 extern uint32_t lgrp_loadavg_max_effect; 430 extern uint32_t lgrp_load_thresh; 431 extern lgrp_mem_policy_t lgrp_mem_policy_root; 432 433 /* 434 * Count the number of CPUs installed to determine if 435 * NUMA optimization should be enabled or not. 436 * 437 * All CPU nodes reside in the root node and have a 438 * device type "cpu". 439 */ 440 curnode = prom_rootnode(); 441 for (curnode = prom_childnode(curnode); curnode; 442 curnode = prom_nextnode(curnode)) { 443 bzero(tmp_name, MAXSYSNAME); 444 if (prom_getproplen(curnode, OBP_NAME) < MAXSYSNAME) { 445 if (prom_getprop(curnode, OBP_NAME, 446 (caddr_t)tmp_name) == -1 || prom_getprop(curnode, 447 OBP_DEVICETYPE, tmp_name) == -1 || strcmp(tmp_name, 448 "cpu") != 0) 449 continue; 450 451 cpucnt++; 452 if (prom_getprop(curnode, "portid", (caddr_t)&portid) != 453 -1 && portid > max_portid) 454 max_portid = portid; 455 } 456 } 457 if (cpucnt <= 1) 458 max_mem_nodes = 1; 459 else if (max_portid >= 0 && max_portid < MAX_MEM_NODES) 460 max_mem_nodes = max_portid + 1; 461 462 /* 463 * Set tuneables for fiesta architecture 464 * 465 * lgrp_expand_proc_thresh is the minimum load on the lgroups 466 * this process is currently running on before considering 467 * expanding threads to another lgroup. 468 * 469 * lgrp_expand_proc_diff determines how much less the remote lgroup 470 * must be loaded before expanding to it. 471 * 472 * Optimize for memory bandwidth by spreading multi-threaded 473 * program to different lgroups. 474 */ 475 lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1; 476 lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2; 477 lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2; 478 lgrp_mem_free_thresh = 1; /* home lgrp must have some memory */ 479 lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1; 480 lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT; 481 lgrp_load_thresh = 0; 482 483 mem_node_pfn_shift = PLATFORM_MC_SHIFT - MMU_PAGESHIFT; 484 } 485 486 /* 487 * Return latency between "from" and "to" lgroups 488 * 489 * This latency number can only be used for relative comparison 490 * between lgroups on the running system, cannot be used across platforms, 491 * and may not reflect the actual latency. It is platform and implementation 492 * specific, so platform gets to decide its value. It would be nice if the 493 * number was at least proportional to make comparisons more meaningful though. 494 * NOTE: The numbers below are supposed to be load latencies for uncached 495 * memory divided by 10. 496 */ 497 int 498 plat_lgrp_latency(void *from, void *to) 499 { 500 /* 501 * Return remote latency when there are more than two lgroups 502 * (root and child) and getting latency between two different 503 * lgroups or root is involved 504 */ 505 if (lgrp_optimizations() && (from != to || from == 506 (void *) LGRP_DEFAULT_HANDLE || to == (void *) LGRP_DEFAULT_HANDLE)) 507 return (17); 508 else 509 return (12); 510 } 511 512 int 513 plat_pfn_to_mem_node(pfn_t pfn) 514 { 515 ASSERT(max_mem_nodes > 1); 516 return (pfn >> mem_node_pfn_shift); 517 } 518 519 /* 520 * Assign memnode to lgroups 521 */ 522 void 523 plat_fill_mc(pnode_t nodeid) 524 { 525 int portid; 526 527 /* 528 * Memory controller portid == global CPU id 529 */ 530 if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) == -1) || 531 (portid < 0)) 532 return; 533 534 if (portid < max_mem_nodes) 535 plat_assign_lgrphand_to_mem_node((lgrp_handle_t)portid, portid); 536 } 537 538 /* ARGSUSED */ 539 void 540 plat_build_mem_nodes(u_longlong_t *list, size_t nelems) 541 { 542 size_t elem; 543 pfn_t basepfn; 544 pgcnt_t npgs; 545 546 /* 547 * Boot install lists are arranged <addr, len>, <addr, len>, ... 548 */ 549 for (elem = 0; elem < nelems; elem += 2) { 550 basepfn = btop(list[elem]); 551 npgs = btop(list[elem+1]); 552 mem_node_add_slice(basepfn, basepfn + npgs - 1); 553 } 554 } 555 556 /* 557 * Common locking enter code 558 */ 559 void 560 plat_setprop_enter(void) 561 { 562 mutex_enter(&mi2cv_mutex); 563 } 564 565 /* 566 * Common locking exit code 567 */ 568 void 569 plat_setprop_exit(void) 570 { 571 mutex_exit(&mi2cv_mutex); 572 } 573 574 /* 575 * Called by mi2cv driver 576 */ 577 void 578 plat_shared_i2c_enter(dev_info_t *i2cnexus_dip) 579 { 580 if (i2cnexus_dip == shared_mi2cv_dip) { 581 plat_setprop_enter(); 582 } 583 } 584 585 /* 586 * Called by mi2cv driver 587 */ 588 void 589 plat_shared_i2c_exit(dev_info_t *i2cnexus_dip) 590 { 591 if (i2cnexus_dip == shared_mi2cv_dip) { 592 plat_setprop_exit(); 593 } 594 } 595 /* 596 * Called by todm5823 driver 597 */ 598 void 599 plat_rmc_comm_req(struct rmc_comm_msg *request) 600 { 601 if (rmc_req_now) 602 (void) rmc_req_now(request, 0); 603 } 604