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