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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * sun4v CPU DR Module 29 */ 30 31 #include <sys/modctl.h> 32 #include <sys/processor.h> 33 #include <sys/cpuvar.h> 34 #include <sys/cpupart.h> 35 #include <sys/sunddi.h> 36 #include <sys/sunndi.h> 37 #include <sys/note.h> 38 #include <sys/sysevent/dr.h> 39 #include <sys/hypervisor_api.h> 40 #include <sys/mach_descrip.h> 41 #include <sys/mdesc.h> 42 #include <sys/ds.h> 43 #include <sys/drctl.h> 44 #include <sys/dr_util.h> 45 #include <sys/dr_cpu.h> 46 #include <sys/promif.h> 47 #include <sys/machsystm.h> 48 49 50 static struct modlmisc modlmisc = { 51 &mod_miscops, 52 "sun4v CPU DR" 53 }; 54 55 static struct modlinkage modlinkage = { 56 MODREV_1, 57 (void *)&modlmisc, 58 NULL 59 }; 60 61 typedef int (*fn_t)(processorid_t, int *, boolean_t); 62 63 /* 64 * Global DS Handle 65 */ 66 static ds_svc_hdl_t ds_handle; 67 68 /* 69 * Supported DS Capability Versions 70 */ 71 static ds_ver_t dr_cpu_vers[] = { { 1, 0 } }; 72 #define DR_CPU_NVERS (sizeof (dr_cpu_vers) / sizeof (dr_cpu_vers[0])) 73 74 /* 75 * DS Capability Description 76 */ 77 static ds_capability_t dr_cpu_cap = { 78 DR_CPU_DS_ID, /* svc_id */ 79 dr_cpu_vers, /* vers */ 80 DR_CPU_NVERS /* nvers */ 81 }; 82 83 /* 84 * DS Callbacks 85 */ 86 static void dr_cpu_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 87 static void dr_cpu_unreg_handler(ds_cb_arg_t arg); 88 static void dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 89 90 /* 91 * DS Client Ops Vector 92 */ 93 static ds_clnt_ops_t dr_cpu_ops = { 94 dr_cpu_reg_handler, /* ds_reg_cb */ 95 dr_cpu_unreg_handler, /* ds_unreg_cb */ 96 dr_cpu_data_handler, /* ds_data_cb */ 97 NULL /* cb_arg */ 98 }; 99 100 /* 101 * Operation Results 102 * 103 * Used internally to gather results while an operation on a 104 * list of CPUs is in progress. In particular, it is used to 105 * keep track of which CPUs have already failed so that they are 106 * not processed further, and the manner in which they failed. 107 */ 108 typedef struct { 109 uint32_t cpuid; 110 uint32_t result; 111 uint32_t status; 112 char *string; 113 } dr_cpu_res_t; 114 115 #define DR_CPU_MAX_ERR_LEN 64 /* maximum error string length */ 116 117 /* 118 * Internal Functions 119 */ 120 static int dr_cpu_init(void); 121 static int dr_cpu_fini(void); 122 123 static int dr_cpu_list_wrk(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *); 124 static int dr_cpu_list_status(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *); 125 126 static int dr_cpu_unconfigure(processorid_t, int *status, boolean_t force); 127 static int dr_cpu_configure(processorid_t, int *status, boolean_t force); 128 static int dr_cpu_status(processorid_t, int *status); 129 130 static void dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res); 131 static void dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres); 132 static int dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res); 133 134 static dr_cpu_res_t *dr_cpu_res_array_init(dr_cpu_hdr_t *, drctl_rsrc_t *, int); 135 static void dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres); 136 static size_t dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res, 137 dr_cpu_hdr_t **respp); 138 139 static int dr_cpu_probe(processorid_t newcpuid); 140 static int dr_cpu_deprobe(processorid_t cpuid); 141 142 static dev_info_t *dr_cpu_find_node(processorid_t cpuid); 143 static mde_cookie_t dr_cpu_find_node_md(processorid_t, md_t *, mde_cookie_t *); 144 145 int 146 _init(void) 147 { 148 int status; 149 150 /* check that CPU DR is enabled */ 151 if (dr_is_disabled(DR_TYPE_CPU)) { 152 cmn_err(CE_CONT, "!CPU DR is disabled\n"); 153 return (-1); 154 } 155 156 if ((status = dr_cpu_init()) != 0) { 157 cmn_err(CE_NOTE, "CPU DR initialization failed"); 158 return (status); 159 } 160 161 if ((status = mod_install(&modlinkage)) != 0) { 162 (void) dr_cpu_fini(); 163 } 164 165 return (status); 166 } 167 168 int 169 _info(struct modinfo *modinfop) 170 { 171 return (mod_info(&modlinkage, modinfop)); 172 } 173 174 int dr_cpu_allow_unload; 175 176 int 177 _fini(void) 178 { 179 int status; 180 181 if (dr_cpu_allow_unload == 0) 182 return (EBUSY); 183 184 if ((status = mod_remove(&modlinkage)) == 0) { 185 (void) dr_cpu_fini(); 186 } 187 188 return (status); 189 } 190 191 static int 192 dr_cpu_init(void) 193 { 194 int rv; 195 196 if ((rv = ds_cap_init(&dr_cpu_cap, &dr_cpu_ops)) != 0) { 197 cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv); 198 return (-1); 199 } 200 201 return (0); 202 } 203 204 static int 205 dr_cpu_fini(void) 206 { 207 int rv; 208 209 if ((rv = ds_cap_fini(&dr_cpu_cap)) != 0) { 210 cmn_err(CE_NOTE, "ds_cap_fini failed: %d", rv); 211 return (-1); 212 } 213 214 return (0); 215 } 216 217 static void 218 dr_cpu_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 219 { 220 DR_DBG_CPU("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg, 221 ver->major, ver->minor, hdl); 222 223 ds_handle = hdl; 224 } 225 226 static void 227 dr_cpu_unreg_handler(ds_cb_arg_t arg) 228 { 229 DR_DBG_CPU("unreg_handler: arg=0x%p\n", arg); 230 231 ds_handle = DS_INVALID_HDL; 232 } 233 234 static void 235 dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 236 { 237 _NOTE(ARGUNUSED(arg)) 238 239 dr_cpu_hdr_t *req = buf; 240 dr_cpu_hdr_t err_resp; 241 dr_cpu_hdr_t *resp = &err_resp; 242 int resp_len = 0; 243 int rv; 244 245 /* 246 * Sanity check the message 247 */ 248 if (buflen < sizeof (dr_cpu_hdr_t)) { 249 DR_DBG_CPU("incoming message short: expected at least %ld " 250 "bytes, received %ld\n", sizeof (dr_cpu_hdr_t), buflen); 251 goto done; 252 } 253 254 if (req == NULL) { 255 DR_DBG_CPU("empty message: expected at least %ld bytes\n", 256 sizeof (dr_cpu_hdr_t)); 257 goto done; 258 } 259 260 DR_DBG_CPU("incoming request:\n"); 261 DR_DBG_DUMP_MSG(buf, buflen); 262 263 if (req->num_records > NCPU) { 264 DR_DBG_CPU("CPU list too long: %d when %d is the maximum\n", 265 req->num_records, NCPU); 266 goto done; 267 } 268 269 if (req->num_records == 0) { 270 DR_DBG_CPU("No CPU specified for operation\n"); 271 goto done; 272 } 273 274 /* 275 * Process the command 276 */ 277 switch (req->msg_type) { 278 case DR_CPU_CONFIGURE: 279 case DR_CPU_UNCONFIGURE: 280 case DR_CPU_FORCE_UNCONFIG: 281 if ((rv = dr_cpu_list_wrk(req, &resp, &resp_len)) != 0) { 282 DR_DBG_CPU("%s%s failed (%d)\n", 283 (req->msg_type == DR_CPU_CONFIGURE) ? 284 "CPU configure" : "CPU unconfigure", 285 (req->msg_type == DR_CPU_FORCE_UNCONFIG) ? 286 " (forced)" : "", rv); 287 } 288 break; 289 290 case DR_CPU_STATUS: 291 if ((rv = dr_cpu_list_status(req, &resp, &resp_len)) != 0) 292 DR_DBG_CPU("CPU status failed (%d)\n", rv); 293 break; 294 295 default: 296 cmn_err(CE_NOTE, "unsupported DR operation (%d)", 297 req->msg_type); 298 break; 299 } 300 301 done: 302 /* check if an error occurred */ 303 if (resp == &err_resp) { 304 resp->req_num = (req) ? req->req_num : 0; 305 resp->msg_type = DR_CPU_ERROR; 306 resp->num_records = 0; 307 resp_len = sizeof (dr_cpu_hdr_t); 308 } 309 310 DR_DBG_CPU("outgoing response:\n"); 311 DR_DBG_DUMP_MSG(resp, resp_len); 312 313 /* send back the response */ 314 if (ds_cap_send(ds_handle, resp, resp_len) != 0) { 315 DR_DBG_CPU("ds_send failed\n"); 316 } 317 318 /* free any allocated memory */ 319 if (resp != &err_resp) { 320 kmem_free(resp, resp_len); 321 } 322 } 323 324 /* 325 * Common routine to config or unconfig multiple cpus. The unconfig 326 * case checks with the OS to see if the removal of cpus will be 327 * permitted, but can be overridden by the "force" version of the 328 * command. Otherwise, the logic for both cases is identical. 329 * 330 * Note: Do not modify result buffer or length on error. 331 */ 332 static int 333 dr_cpu_list_wrk(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len) 334 { 335 int rv; 336 int idx; 337 int count; 338 fn_t dr_fn; 339 int se_hint; 340 boolean_t force = B_FALSE; 341 uint32_t *req_cpus; 342 dr_cpu_res_t *res; 343 int drctl_cmd; 344 int drctl_flags = 0; 345 drctl_rsrc_t *drctl_req; 346 size_t drctl_req_len; 347 drctl_rsrc_t *drctl_res; 348 size_t drctl_res_len = 0; 349 drctl_cookie_t drctl_res_ck; 350 351 static const char me[] = "dr_cpu_list_wrk"; 352 353 ASSERT((req != NULL) && (req->num_records != 0)); 354 355 count = req->num_records; 356 357 /* 358 * Extract all information that is specific 359 * to the various types of operations. 360 */ 361 switch (req->msg_type) { 362 case DR_CPU_CONFIGURE: 363 dr_fn = dr_cpu_configure; 364 drctl_cmd = DRCTL_CPU_CONFIG_REQUEST; 365 se_hint = SE_HINT_INSERT; 366 break; 367 case DR_CPU_FORCE_UNCONFIG: 368 drctl_flags = DRCTL_FLAG_FORCE; 369 force = B_TRUE; 370 _NOTE(FALLTHROUGH) 371 case DR_CPU_UNCONFIGURE: 372 dr_fn = dr_cpu_unconfigure; 373 drctl_cmd = DRCTL_CPU_UNCONFIG_REQUEST; 374 se_hint = SE_HINT_REMOVE; 375 break; 376 default: 377 /* Programming error if we reach this. */ 378 cmn_err(CE_NOTE, "%s: bad msg_type %d\n", me, req->msg_type); 379 ASSERT(0); 380 return (-1); 381 } 382 383 /* the incoming array of cpuids to operate on */ 384 req_cpus = DR_CPU_CMD_CPUIDS(req); 385 386 /* allocate drctl request msg based on incoming resource count */ 387 drctl_req_len = sizeof (drctl_rsrc_t) * count; 388 drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); 389 390 /* copy the cpuids for the drctl call from the incoming request msg */ 391 for (idx = 0; idx < count; idx++) 392 drctl_req[idx].res_cpu_id = req_cpus[idx]; 393 394 if ((rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, 395 count, &drctl_res, &drctl_res_len, &drctl_res_ck)) != 0) { 396 DR_DBG_CPU("%s: drctl_config_init returned: %d\n", me, rv); 397 kmem_free(drctl_req, drctl_req_len); 398 return (-1); 399 } 400 401 ASSERT((drctl_res != NULL) && (drctl_res_len != 0)); 402 403 /* create the result scratch array */ 404 res = dr_cpu_res_array_init(req, drctl_res, count); 405 406 /* 407 * For unconfigure, check if there are any conditions 408 * that will cause the operation to fail. These are 409 * performed before the actual unconfigure attempt so 410 * that a meaningful error message can be generated. 411 */ 412 if (req->msg_type != DR_CPU_CONFIGURE) 413 dr_cpu_check_cpus(req, res); 414 415 /* perform the specified operation on each of the CPUs */ 416 for (idx = 0; idx < count; idx++) { 417 int result; 418 int status; 419 420 /* 421 * If no action will be taken against the current 422 * CPU, update the drctl resource information to 423 * ensure that it gets recovered properly during 424 * the drctl fini() call. 425 */ 426 if (res[idx].result != DR_CPU_RES_OK) { 427 drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE; 428 continue; 429 } 430 431 /* call the function to perform the actual operation */ 432 result = (*dr_fn)(req_cpus[idx], &status, force); 433 434 /* save off results of the operation */ 435 res[idx].result = result; 436 res[idx].status = status; 437 438 /* save result for drctl fini() reusing init() msg memory */ 439 drctl_req[idx].status = (result != DR_CPU_RES_OK) ? 440 DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS; 441 442 DR_DBG_CPU("%s: cpuid %d status %d result %d off '%s'\n", 443 me, req_cpus[idx], drctl_req[idx].status, result, 444 (res[idx].string) ? res[idx].string : ""); 445 } 446 447 if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0) 448 DR_DBG_CPU("%s: drctl_config_fini returned: %d\n", me, rv); 449 450 /* 451 * Operation completed without any fatal errors. 452 * Pack the response for transmission. 453 */ 454 *resp_len = dr_cpu_pack_response(req, res, resp); 455 456 /* notify interested parties about the operation */ 457 dr_generate_event(DR_TYPE_CPU, se_hint); 458 459 /* 460 * Deallocate any scratch memory. 461 */ 462 kmem_free(drctl_res, drctl_res_len); 463 kmem_free(drctl_req, drctl_req_len); 464 465 dr_cpu_res_array_fini(res, count); 466 467 return (0); 468 } 469 470 /* 471 * Allocate and initialize a result array based on the initial 472 * drctl operation. A valid result array is always returned. 473 */ 474 static dr_cpu_res_t * 475 dr_cpu_res_array_init(dr_cpu_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc) 476 { 477 int idx; 478 dr_cpu_res_t *res; 479 char *err_str; 480 size_t err_len; 481 482 /* allocate zero filled buffer to initialize fields */ 483 res = kmem_zalloc(nrsrc * sizeof (dr_cpu_res_t), KM_SLEEP); 484 485 /* 486 * Fill in the result information for each resource. 487 */ 488 for (idx = 0; idx < nrsrc; idx++) { 489 res[idx].cpuid = rsrc[idx].res_cpu_id; 490 res[idx].result = DR_CPU_RES_OK; 491 492 if (rsrc[idx].status == DRCTL_STATUS_ALLOW) 493 continue; 494 495 /* 496 * Update the state information for this CPU. 497 */ 498 res[idx].result = DR_CPU_RES_BLOCKED; 499 res[idx].status = (req->msg_type == DR_CPU_CONFIGURE) ? 500 DR_CPU_STAT_UNCONFIGURED : DR_CPU_STAT_CONFIGURED; 501 502 /* 503 * If an error string exists, copy it out of the 504 * message buffer. This eliminates any dependency 505 * on the memory allocated for the message buffer 506 * itself. 507 */ 508 if (rsrc[idx].offset != NULL) { 509 err_str = (char *)rsrc + rsrc[idx].offset; 510 err_len = strlen(err_str) + 1; 511 512 res[idx].string = kmem_alloc(err_len, KM_SLEEP); 513 bcopy(err_str, res[idx].string, err_len); 514 } 515 } 516 517 return (res); 518 } 519 520 static void 521 dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres) 522 { 523 int idx; 524 size_t str_len; 525 526 for (idx = 0; idx < nres; idx++) { 527 /* deallocate the error string if present */ 528 if (res[idx].string) { 529 str_len = strlen(res[idx].string) + 1; 530 kmem_free(res[idx].string, str_len); 531 } 532 } 533 534 /* deallocate the result array itself */ 535 kmem_free(res, sizeof (dr_cpu_res_t) * nres); 536 } 537 538 /* 539 * Allocate and pack a response message for transmission based 540 * on the specified result array. A valid response message and 541 * valid size information is always returned. 542 */ 543 static size_t 544 dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res, dr_cpu_hdr_t **respp) 545 { 546 int idx; 547 dr_cpu_hdr_t *resp; 548 dr_cpu_stat_t *resp_stat; 549 size_t resp_len; 550 uint32_t curr_off; 551 caddr_t curr_str; 552 size_t str_len; 553 size_t stat_len; 554 int nstat = req->num_records; 555 556 /* 557 * Calculate the size of the response message 558 * and allocate an appropriately sized buffer. 559 */ 560 resp_len = 0; 561 562 /* add the header size */ 563 resp_len += sizeof (dr_cpu_hdr_t); 564 565 /* add the stat array size */ 566 stat_len = sizeof (dr_cpu_stat_t) * nstat; 567 resp_len += stat_len; 568 569 /* add the size of any error strings */ 570 for (idx = 0; idx < nstat; idx++) { 571 if (res[idx].string != NULL) { 572 resp_len += strlen(res[idx].string) + 1; 573 } 574 } 575 576 /* allocate the message buffer */ 577 resp = kmem_zalloc(resp_len, KM_SLEEP); 578 579 /* 580 * Fill in the header information. 581 */ 582 resp->req_num = req->req_num; 583 resp->msg_type = DR_CPU_OK; 584 resp->num_records = nstat; 585 586 /* 587 * Fill in the stat information. 588 */ 589 resp_stat = DR_CPU_RESP_STATS(resp); 590 591 /* string offsets start immediately after stat array */ 592 curr_off = sizeof (dr_cpu_hdr_t) + stat_len; 593 curr_str = (char *)resp_stat + stat_len; 594 595 for (idx = 0; idx < nstat; idx++) { 596 resp_stat[idx].cpuid = res[idx].cpuid; 597 resp_stat[idx].result = res[idx].result; 598 resp_stat[idx].status = res[idx].status; 599 600 if (res[idx].string != NULL) { 601 /* copy over the error string */ 602 str_len = strlen(res[idx].string) + 1; 603 bcopy(res[idx].string, curr_str, str_len); 604 resp_stat[idx].string_off = curr_off; 605 606 curr_off += str_len; 607 curr_str += str_len; 608 } 609 } 610 611 /* buffer should be exactly filled */ 612 ASSERT(curr_off == resp_len); 613 614 *respp = resp; 615 return (resp_len); 616 } 617 618 /* 619 * Check for conditions that will prevent a CPU from being offlined. 620 * This provides the opportunity to generate useful information to 621 * help diagnose the failure rather than letting the offline attempt 622 * fail in a more generic way. 623 */ 624 static void 625 dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res) 626 { 627 int idx; 628 cpu_t *cp; 629 uint32_t *cpuids; 630 631 ASSERT((req->msg_type == DR_CPU_UNCONFIGURE) || 632 (req->msg_type == DR_CPU_FORCE_UNCONFIG)); 633 634 DR_DBG_CPU("dr_cpu_check_cpus...\n"); 635 636 /* array of cpuids start just after the header */ 637 cpuids = DR_CPU_CMD_CPUIDS(req); 638 639 mutex_enter(&cpu_lock); 640 641 /* 642 * Always check processor set membership first. The 643 * last CPU in a processor set will fail to offline 644 * even if the operation if forced, so any failures 645 * should always be reported. 646 */ 647 dr_cpu_check_psrset(cpuids, res, req->num_records); 648 649 /* process each cpu that is part of the request */ 650 for (idx = 0; idx < req->num_records; idx++) { 651 652 /* nothing to check if the CPU has already failed */ 653 if (res[idx].result != DR_CPU_RES_OK) 654 continue; 655 656 if ((cp = cpu_get(cpuids[idx])) == NULL) 657 continue; 658 659 /* 660 * Only check if there are bound threads if the 661 * operation is not a forced unconfigure. In a 662 * forced request, threads are automatically 663 * unbound before they are offlined. 664 */ 665 if (req->msg_type == DR_CPU_UNCONFIGURE) { 666 /* 667 * The return value is only interesting if other 668 * checks are added to this loop and a decision 669 * is needed on whether to continue checking. 670 */ 671 (void) dr_cpu_check_bound_thr(cp, &res[idx]); 672 } 673 } 674 675 mutex_exit(&cpu_lock); 676 } 677 678 /* 679 * Examine the processor set configuration for the specified 680 * CPUs and see if the unconfigure operation would result in 681 * trying to remove the last CPU in any processor set. 682 */ 683 static void 684 dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres) 685 { 686 int cpu_idx; 687 int set_idx; 688 cpu_t *cp; 689 cpupart_t *cpp; 690 char err_str[DR_CPU_MAX_ERR_LEN]; 691 size_t err_len; 692 struct { 693 cpupart_t *cpp; 694 int ncpus; 695 } *psrset; 696 697 ASSERT(MUTEX_HELD(&cpu_lock)); 698 699 /* 700 * Allocate a scratch array to count the CPUs in 701 * the various processor sets. A CPU always belongs 702 * to exactly one processor set, so by definition, 703 * the scratch array never needs to be larger than 704 * the number of CPUs. 705 */ 706 psrset = kmem_zalloc(sizeof (*psrset) * nres, KM_SLEEP); 707 708 for (cpu_idx = 0; cpu_idx < nres; cpu_idx++) { 709 710 /* skip any CPUs that have already failed */ 711 if (res[cpu_idx].result != DR_CPU_RES_OK) 712 continue; 713 714 if ((cp = cpu_get(cpuids[cpu_idx])) == NULL) 715 continue; 716 717 cpp = cp->cpu_part; 718 719 /* lookup the set this CPU belongs to */ 720 for (set_idx = 0; set_idx < nres; set_idx++) { 721 722 /* matching set found */ 723 if (cpp == psrset[set_idx].cpp) 724 break; 725 726 /* set not found, start a new entry */ 727 if (psrset[set_idx].cpp == NULL) { 728 psrset[set_idx].cpp = cpp; 729 psrset[set_idx].ncpus = cpp->cp_ncpus; 730 break; 731 } 732 } 733 734 ASSERT(set_idx != nres); 735 736 /* 737 * Remove the current CPU from the set total but only 738 * generate an error for the last CPU. The correct CPU 739 * will get the error because the unconfigure attempts 740 * will occur in the same order in which the CPUs are 741 * examined in this loop. 742 */ 743 if (--psrset[set_idx].ncpus == 0) { 744 /* 745 * Fill in the various pieces of information 746 * to report that the operation will fail. 747 */ 748 res[cpu_idx].result = DR_CPU_RES_BLOCKED; 749 res[cpu_idx].status = DR_CPU_STAT_CONFIGURED; 750 751 (void) snprintf(err_str, DR_CPU_MAX_ERR_LEN, 752 "last online cpu in processor set %d", cpp->cp_id); 753 754 err_len = strlen(err_str) + 1; 755 756 res[cpu_idx].string = kmem_alloc(err_len, KM_SLEEP); 757 bcopy(err_str, res[cpu_idx].string, err_len); 758 759 DR_DBG_CPU("cpu %d: %s\n", cpuids[cpu_idx], err_str); 760 } 761 } 762 763 kmem_free(psrset, sizeof (*psrset) * nres); 764 } 765 766 /* 767 * Check if any threads are bound to the specified CPU. If the 768 * condition is true, DR_CPU_RES_BLOCKED is returned and an error 769 * string is generated and placed in the specified result structure. 770 * Otherwise, DR_CPU_RES_OK is returned. 771 */ 772 static int 773 dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res) 774 { 775 int nbound; 776 proc_t *pp; 777 kthread_t *tp; 778 char err_str[DR_CPU_MAX_ERR_LEN]; 779 size_t err_len; 780 781 /* 782 * Error string allocation makes an assumption 783 * that no blocking condition has been identified. 784 */ 785 ASSERT(res->result == DR_CPU_RES_OK); 786 ASSERT(res->string == NULL); 787 788 ASSERT(MUTEX_HELD(&cpu_lock)); 789 790 mutex_enter(&pidlock); 791 792 nbound = 0; 793 794 /* 795 * Walk the active processes, checking if each 796 * thread belonging to the process is bound. 797 */ 798 for (pp = practive; (pp != NULL) && (nbound <= 1); pp = pp->p_next) { 799 mutex_enter(&pp->p_lock); 800 801 tp = pp->p_tlist; 802 803 if ((tp == NULL) || (pp->p_flag & SSYS)) { 804 mutex_exit(&pp->p_lock); 805 continue; 806 } 807 808 do { 809 if (tp->t_bind_cpu != cp->cpu_id) 810 continue; 811 812 /* 813 * Update the running total of bound 814 * threads. Continue the search until 815 * it can be determined if more than 816 * one thread is bound to the CPU. 817 */ 818 if (++nbound > 1) 819 break; 820 821 } while ((tp = tp->t_forw) != pp->p_tlist); 822 823 mutex_exit(&pp->p_lock); 824 } 825 826 mutex_exit(&pidlock); 827 828 if (nbound) { 829 /* 830 * Threads are bound to the CPU. Fill in 831 * various pieces of information to report 832 * that the operation will fail. 833 */ 834 res->result = DR_CPU_RES_BLOCKED; 835 res->status = DR_CPU_STAT_CONFIGURED; 836 837 (void) snprintf(err_str, DR_CPU_MAX_ERR_LEN, "cpu has bound " 838 "thread%s", (nbound > 1) ? "s" : ""); 839 840 err_len = strlen(err_str) + 1; 841 842 res->string = kmem_alloc(err_len, KM_SLEEP); 843 bcopy(err_str, res->string, err_len); 844 845 DR_DBG_CPU("cpu %d: %s\n", cp->cpu_id, err_str); 846 } 847 848 return (res->result); 849 } 850 851 /* 852 * Do not modify result buffer or length on error. 853 */ 854 static int 855 dr_cpu_list_status(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len) 856 { 857 int idx; 858 int result; 859 int status; 860 int rlen; 861 uint32_t *cpuids; 862 dr_cpu_hdr_t *rp; 863 dr_cpu_stat_t *stat; 864 md_t *mdp = NULL; 865 int num_nodes; 866 int listsz; 867 mde_cookie_t *listp = NULL; 868 mde_cookie_t cpunode; 869 boolean_t walk_md = B_FALSE; 870 871 /* the incoming array of cpuids to configure */ 872 cpuids = DR_CPU_CMD_CPUIDS(req); 873 874 /* allocate a response message */ 875 rlen = sizeof (dr_cpu_hdr_t); 876 rlen += req->num_records * sizeof (dr_cpu_stat_t); 877 rp = kmem_zalloc(rlen, KM_SLEEP); 878 879 /* fill in the known data */ 880 rp->req_num = req->req_num; 881 rp->msg_type = DR_CPU_STATUS; 882 rp->num_records = req->num_records; 883 884 /* stat array for the response */ 885 stat = DR_CPU_RESP_STATS(rp); 886 887 /* get the status for each of the CPUs */ 888 for (idx = 0; idx < req->num_records; idx++) { 889 890 result = dr_cpu_status(cpuids[idx], &status); 891 892 if (result == DR_CPU_RES_FAILURE) 893 walk_md = B_TRUE; 894 895 /* save off results of the status */ 896 stat[idx].cpuid = cpuids[idx]; 897 stat[idx].result = result; 898 stat[idx].status = status; 899 } 900 901 if (walk_md == B_FALSE) 902 goto done; 903 904 /* 905 * At least one of the cpus did not have a CPU 906 * structure. So, consult the MD to determine if 907 * they are present. 908 */ 909 910 if ((mdp = md_get_handle()) == NULL) { 911 DR_DBG_CPU("unable to initialize MD\n"); 912 goto done; 913 } 914 915 num_nodes = md_node_count(mdp); 916 ASSERT(num_nodes > 0); 917 918 listsz = num_nodes * sizeof (mde_cookie_t); 919 listp = kmem_zalloc(listsz, KM_SLEEP); 920 921 for (idx = 0; idx < req->num_records; idx++) { 922 923 if (stat[idx].result != DR_CPU_RES_FAILURE) 924 continue; 925 926 /* check the MD for the current cpuid */ 927 cpunode = dr_cpu_find_node_md(stat[idx].cpuid, mdp, listp); 928 929 stat[idx].result = DR_CPU_RES_OK; 930 931 if (cpunode == MDE_INVAL_ELEM_COOKIE) { 932 stat[idx].status = DR_CPU_STAT_NOT_PRESENT; 933 } else { 934 stat[idx].status = DR_CPU_STAT_UNCONFIGURED; 935 } 936 } 937 938 kmem_free(listp, listsz); 939 940 (void) md_fini_handle(mdp); 941 942 done: 943 *resp = rp; 944 *resp_len = rlen; 945 946 return (0); 947 } 948 949 static int 950 dr_cpu_configure(processorid_t cpuid, int *status, boolean_t force) 951 { 952 _NOTE(ARGUNUSED(force)) 953 struct cpu *cp; 954 int rv = 0; 955 956 DR_DBG_CPU("dr_cpu_configure...\n"); 957 958 /* 959 * Build device tree node for the CPU 960 */ 961 if ((rv = dr_cpu_probe(cpuid)) != 0) { 962 DR_DBG_CPU("failed to probe CPU %d (%d)\n", cpuid, rv); 963 if (rv == EINVAL) { 964 *status = DR_CPU_STAT_NOT_PRESENT; 965 return (DR_CPU_RES_NOT_IN_MD); 966 } 967 *status = DR_CPU_STAT_UNCONFIGURED; 968 return (DR_CPU_RES_FAILURE); 969 } 970 971 mutex_enter(&cpu_lock); 972 973 /* 974 * Configure the CPU 975 */ 976 if ((cp = cpu_get(cpuid)) == NULL) { 977 978 if ((rv = cpu_configure(cpuid)) != 0) { 979 DR_DBG_CPU("failed to configure CPU %d (%d)\n", 980 cpuid, rv); 981 rv = DR_CPU_RES_FAILURE; 982 *status = DR_CPU_STAT_UNCONFIGURED; 983 goto done; 984 } 985 986 DR_DBG_CPU("CPU %d configured\n", cpuid); 987 988 /* CPU struct should exist now */ 989 cp = cpu_get(cpuid); 990 } 991 992 ASSERT(cp); 993 994 /* 995 * Power on the CPU. In sun4v, this brings the stopped 996 * CPU into the guest from the Hypervisor. 997 */ 998 if (cpu_is_poweredoff(cp)) { 999 1000 if ((rv = cpu_poweron(cp)) != 0) { 1001 DR_DBG_CPU("failed to power on CPU %d (%d)\n", 1002 cpuid, rv); 1003 rv = DR_CPU_RES_FAILURE; 1004 *status = DR_CPU_STAT_UNCONFIGURED; 1005 goto done; 1006 } 1007 1008 DR_DBG_CPU("CPU %d powered on\n", cpuid); 1009 } 1010 1011 /* 1012 * Online the CPU 1013 */ 1014 if (cpu_is_offline(cp)) { 1015 1016 if ((rv = cpu_online(cp)) != 0) { 1017 DR_DBG_CPU("failed to online CPU %d (%d)\n", 1018 cpuid, rv); 1019 rv = DR_CPU_RES_FAILURE; 1020 /* offline is still configured */ 1021 *status = DR_CPU_STAT_CONFIGURED; 1022 goto done; 1023 } 1024 1025 DR_DBG_CPU("CPU %d online\n", cpuid); 1026 } 1027 1028 rv = DR_CPU_RES_OK; 1029 *status = DR_CPU_STAT_CONFIGURED; 1030 1031 done: 1032 mutex_exit(&cpu_lock); 1033 1034 return (rv); 1035 } 1036 1037 static int 1038 dr_cpu_unconfigure(processorid_t cpuid, int *status, boolean_t force) 1039 { 1040 struct cpu *cp; 1041 int rv = 0; 1042 int cpu_flags; 1043 1044 DR_DBG_CPU("dr_cpu_unconfigure%s...\n", (force) ? " (force)" : ""); 1045 1046 mutex_enter(&cpu_lock); 1047 1048 cp = cpu_get(cpuid); 1049 1050 if (cp == NULL) { 1051 1052 /* 1053 * The OS CPU structures are already torn down, 1054 * Attempt to deprobe the CPU to make sure the 1055 * device tree is up to date. 1056 */ 1057 if (dr_cpu_deprobe(cpuid) != 0) { 1058 DR_DBG_CPU("failed to deprobe CPU %d\n", cpuid); 1059 rv = DR_CPU_RES_FAILURE; 1060 *status = DR_CPU_STAT_UNCONFIGURED; 1061 goto done; 1062 } 1063 1064 goto done; 1065 } 1066 1067 ASSERT(cp->cpu_id == cpuid); 1068 1069 /* 1070 * Offline the CPU 1071 */ 1072 if (cpu_is_active(cp)) { 1073 1074 /* set the force flag correctly */ 1075 cpu_flags = (force) ? CPU_FORCED : 0; 1076 1077 if ((rv = cpu_offline(cp, cpu_flags)) != 0) { 1078 DR_DBG_CPU("failed to offline CPU %d (%d)\n", 1079 cpuid, rv); 1080 1081 rv = DR_CPU_RES_FAILURE; 1082 *status = DR_CPU_STAT_CONFIGURED; 1083 goto done; 1084 } 1085 1086 DR_DBG_CPU("CPU %d offline\n", cpuid); 1087 } 1088 1089 /* 1090 * Power off the CPU. In sun4v, this puts the running 1091 * CPU into the stopped state in the Hypervisor. 1092 */ 1093 if (!cpu_is_poweredoff(cp)) { 1094 1095 if ((rv = cpu_poweroff(cp)) != 0) { 1096 DR_DBG_CPU("failed to power off CPU %d (%d)\n", 1097 cpuid, rv); 1098 rv = DR_CPU_RES_FAILURE; 1099 *status = DR_CPU_STAT_CONFIGURED; 1100 goto done; 1101 } 1102 1103 DR_DBG_CPU("CPU %d powered off\n", cpuid); 1104 } 1105 1106 /* 1107 * Unconfigure the CPU 1108 */ 1109 if ((rv = cpu_unconfigure(cpuid)) != 0) { 1110 DR_DBG_CPU("failed to unconfigure CPU %d (%d)\n", cpuid, rv); 1111 rv = DR_CPU_RES_FAILURE; 1112 *status = DR_CPU_STAT_UNCONFIGURED; 1113 goto done; 1114 } 1115 1116 DR_DBG_CPU("CPU %d unconfigured\n", cpuid); 1117 1118 /* 1119 * Tear down device tree. 1120 */ 1121 if ((rv = dr_cpu_deprobe(cpuid)) != 0) { 1122 DR_DBG_CPU("failed to deprobe CPU %d (%d)\n", cpuid, rv); 1123 rv = DR_CPU_RES_FAILURE; 1124 *status = DR_CPU_STAT_UNCONFIGURED; 1125 goto done; 1126 } 1127 1128 rv = DR_CPU_RES_OK; 1129 *status = DR_CPU_STAT_UNCONFIGURED; 1130 1131 done: 1132 mutex_exit(&cpu_lock); 1133 1134 return (rv); 1135 } 1136 1137 /* 1138 * Determine the state of a CPU. If the CPU structure is not present, 1139 * it does not attempt to determine whether or not the CPU is in the 1140 * MD. It is more efficient to do this at the higher level for all 1141 * CPUs since it may not even be necessary to search the MD if all 1142 * the CPUs are accounted for. Returns DR_CPU_RES_OK if the CPU 1143 * structure is present, and DR_CPU_RES_FAILURE otherwise as a signal 1144 * that an MD walk is necessary. 1145 */ 1146 static int 1147 dr_cpu_status(processorid_t cpuid, int *status) 1148 { 1149 int rv; 1150 struct cpu *cp; 1151 1152 DR_DBG_CPU("dr_cpu_status...\n"); 1153 1154 mutex_enter(&cpu_lock); 1155 1156 if ((cp = cpu_get(cpuid)) == NULL) { 1157 /* need to check if cpu is in the MD */ 1158 rv = DR_CPU_RES_FAILURE; 1159 goto done; 1160 } 1161 1162 if (cpu_is_poweredoff(cp)) { 1163 /* 1164 * The CPU is powered off, so it is considered 1165 * unconfigured from the service entity point of 1166 * view. The CPU is not available to the system 1167 * and intervention by the service entity would 1168 * be required to change that. 1169 */ 1170 *status = DR_CPU_STAT_UNCONFIGURED; 1171 } else { 1172 /* 1173 * The CPU is powered on, so it is considered 1174 * configured from the service entity point of 1175 * view. It is available for use by the system 1176 * and service entities are not concerned about 1177 * the operational status (offline, online, etc.) 1178 * of the CPU in terms of DR. 1179 */ 1180 *status = DR_CPU_STAT_CONFIGURED; 1181 } 1182 1183 rv = DR_CPU_RES_OK; 1184 1185 done: 1186 mutex_exit(&cpu_lock); 1187 1188 return (rv); 1189 } 1190 1191 typedef struct { 1192 md_t *mdp; 1193 mde_cookie_t cpunode; 1194 dev_info_t *dip; 1195 } cb_arg_t; 1196 1197 #define STR_ARR_LEN 5 1198 1199 static int 1200 new_cpu_node(dev_info_t *new_node, void *arg, uint_t flags) 1201 { 1202 _NOTE(ARGUNUSED(flags)) 1203 1204 char *compat; 1205 uint64_t freq; 1206 uint64_t cpuid = 0; 1207 int regbuf[4]; 1208 int len = 0; 1209 cb_arg_t *cba; 1210 char *str_arr[STR_ARR_LEN]; 1211 char *curr; 1212 int idx = 0; 1213 1214 DR_DBG_CPU("new_cpu_node...\n"); 1215 1216 cba = (cb_arg_t *)arg; 1217 1218 /* 1219 * Add 'name' property 1220 */ 1221 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, 1222 "name", "cpu") != DDI_SUCCESS) { 1223 DR_DBG_CPU("new_cpu_node: failed to create 'name' property\n"); 1224 return (DDI_WALK_ERROR); 1225 } 1226 1227 /* 1228 * Add 'compatible' property 1229 */ 1230 if (md_get_prop_data(cba->mdp, cba->cpunode, "compatible", 1231 (uint8_t **)(&compat), &len)) { 1232 DR_DBG_CPU("new_cpu_node: failed to read 'compatible' property " 1233 "from MD\n"); 1234 return (DDI_WALK_ERROR); 1235 } 1236 1237 DR_DBG_CPU("'compatible' len is %d\n", len); 1238 1239 /* parse the MD string array */ 1240 curr = compat; 1241 while (curr < (compat + len)) { 1242 1243 DR_DBG_CPU("adding '%s' to 'compatible' property\n", curr); 1244 1245 str_arr[idx++] = curr; 1246 curr += strlen(curr) + 1; 1247 1248 if (idx == STR_ARR_LEN) { 1249 DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN); 1250 break; 1251 } 1252 } 1253 1254 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node, 1255 "compatible", str_arr, idx) != DDI_SUCCESS) { 1256 DR_DBG_CPU("new_cpu_node: failed to create 'compatible' " 1257 "property\n"); 1258 return (DDI_WALK_ERROR); 1259 } 1260 1261 /* 1262 * Add 'device_type' property 1263 */ 1264 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, 1265 "device_type", "cpu") != DDI_SUCCESS) { 1266 DR_DBG_CPU("new_cpu_node: failed to create 'device_type' " 1267 "property\n"); 1268 return (DDI_WALK_ERROR); 1269 } 1270 1271 /* 1272 * Add 'clock-frequency' property 1273 */ 1274 if (md_get_prop_val(cba->mdp, cba->cpunode, "clock-frequency", &freq)) { 1275 DR_DBG_CPU("new_cpu_node: failed to read 'clock-frequency' " 1276 "property from MD\n"); 1277 return (DDI_WALK_ERROR); 1278 } 1279 1280 if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node, 1281 "clock-frequency", freq) != DDI_SUCCESS) { 1282 DR_DBG_CPU("new_cpu_node: failed to create 'clock-frequency' " 1283 "property\n"); 1284 return (DDI_WALK_ERROR); 1285 } 1286 1287 /* 1288 * Add 'reg' (cpuid) property 1289 */ 1290 if (md_get_prop_val(cba->mdp, cba->cpunode, "id", &cpuid)) { 1291 DR_DBG_CPU("new_cpu_node: failed to read 'id' property " 1292 "from MD\n"); 1293 return (DDI_WALK_ERROR); 1294 } 1295 1296 DR_DBG_CPU("new cpuid=0x%lx\n", cpuid); 1297 1298 bzero(regbuf, 4 * sizeof (int)); 1299 regbuf[0] = 0xc0000000 | cpuid; 1300 1301 if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_node, 1302 "reg", regbuf, 4) != DDI_SUCCESS) { 1303 DR_DBG_CPU("new_cpu_node: failed to create 'reg' property\n"); 1304 return (DDI_WALK_ERROR); 1305 } 1306 1307 cba->dip = new_node; 1308 1309 return (DDI_WALK_TERMINATE); 1310 } 1311 1312 static int 1313 dr_cpu_probe(processorid_t cpuid) 1314 { 1315 dev_info_t *pdip; 1316 dev_info_t *dip; 1317 devi_branch_t br; 1318 md_t *mdp = NULL; 1319 int num_nodes; 1320 int rv = 0; 1321 int listsz; 1322 mde_cookie_t *listp = NULL; 1323 cb_arg_t cba; 1324 mde_cookie_t cpunode; 1325 1326 if ((dip = dr_cpu_find_node(cpuid)) != NULL) { 1327 /* nothing to do */ 1328 e_ddi_branch_rele(dip); 1329 return (0); 1330 } 1331 1332 if ((mdp = md_get_handle()) == NULL) { 1333 DR_DBG_CPU("unable to initialize machine description\n"); 1334 return (-1); 1335 } 1336 1337 num_nodes = md_node_count(mdp); 1338 ASSERT(num_nodes > 0); 1339 1340 listsz = num_nodes * sizeof (mde_cookie_t); 1341 listp = kmem_zalloc(listsz, KM_SLEEP); 1342 1343 cpunode = dr_cpu_find_node_md(cpuid, mdp, listp); 1344 1345 if (cpunode == MDE_INVAL_ELEM_COOKIE) { 1346 rv = EINVAL; 1347 goto done; 1348 } 1349 1350 /* pass in MD cookie for CPU */ 1351 cba.mdp = mdp; 1352 cba.cpunode = cpunode; 1353 1354 br.arg = (void *)&cba; 1355 br.type = DEVI_BRANCH_SID; 1356 br.create.sid_branch_create = new_cpu_node; 1357 br.devi_branch_callback = NULL; 1358 pdip = ddi_root_node(); 1359 1360 if ((rv = e_ddi_branch_create(pdip, &br, NULL, 0))) { 1361 DR_DBG_CPU("e_ddi_branch_create failed: %d\n", rv); 1362 rv = -1; 1363 goto done; 1364 } 1365 1366 DR_DBG_CPU("CPU %d probed\n", cpuid); 1367 1368 rv = 0; 1369 1370 done: 1371 if (listp) 1372 kmem_free(listp, listsz); 1373 1374 if (mdp) 1375 (void) md_fini_handle(mdp); 1376 1377 return (rv); 1378 } 1379 1380 static int 1381 dr_cpu_deprobe(processorid_t cpuid) 1382 { 1383 dev_info_t *fdip = NULL; 1384 dev_info_t *dip; 1385 1386 if ((dip = dr_cpu_find_node(cpuid)) == NULL) { 1387 DR_DBG_CPU("cpuid %d already deprobed\n", cpuid); 1388 return (0); 1389 } 1390 1391 ASSERT(e_ddi_branch_held(dip)); 1392 1393 if (e_ddi_branch_destroy(dip, &fdip, 0)) { 1394 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1395 1396 /* 1397 * If non-NULL, fdip is held and must be released. 1398 */ 1399 if (fdip != NULL) { 1400 (void) ddi_pathname(fdip, path); 1401 ddi_release_devi(fdip); 1402 } else { 1403 (void) ddi_pathname(dip, path); 1404 } 1405 cmn_err(CE_NOTE, "node removal failed: %s (%p)", 1406 path, (fdip) ? (void *)fdip : (void *)dip); 1407 1408 kmem_free(path, MAXPATHLEN); 1409 1410 return (-1); 1411 } 1412 1413 DR_DBG_CPU("CPU %d deprobed\n", cpuid); 1414 1415 return (0); 1416 } 1417 1418 typedef struct { 1419 processorid_t cpuid; 1420 dev_info_t *dip; 1421 } dr_search_arg_t; 1422 1423 static int 1424 dr_cpu_check_node(dev_info_t *dip, void *arg) 1425 { 1426 char *name; 1427 processorid_t cpuid; 1428 dr_search_arg_t *sarg = (dr_search_arg_t *)arg; 1429 1430 if (dip == ddi_root_node()) { 1431 return (DDI_WALK_CONTINUE); 1432 } 1433 1434 name = ddi_node_name(dip); 1435 1436 if (strcmp(name, "cpu") != 0) { 1437 return (DDI_WALK_PRUNECHILD); 1438 } 1439 1440 cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1441 "reg", -1); 1442 1443 cpuid = PROM_CFGHDL_TO_CPUID(cpuid); 1444 1445 DR_DBG_CPU("found cpuid=0x%x, looking for 0x%x\n", cpuid, sarg->cpuid); 1446 1447 if (cpuid == sarg->cpuid) { 1448 DR_DBG_CPU("matching node\n"); 1449 1450 /* matching node must be returned held */ 1451 if (!e_ddi_branch_held(dip)) 1452 e_ddi_branch_hold(dip); 1453 1454 sarg->dip = dip; 1455 return (DDI_WALK_TERMINATE); 1456 } 1457 1458 return (DDI_WALK_CONTINUE); 1459 } 1460 1461 /* 1462 * Walk the device tree to find the dip corresponding to the cpuid 1463 * passed in. If present, the dip is returned held. The caller must 1464 * release the hold on the dip once it is no longer required. If no 1465 * matching node if found, NULL is returned. 1466 */ 1467 static dev_info_t * 1468 dr_cpu_find_node(processorid_t cpuid) 1469 { 1470 dr_search_arg_t arg; 1471 1472 DR_DBG_CPU("dr_cpu_find_node...\n"); 1473 1474 arg.cpuid = cpuid; 1475 arg.dip = NULL; 1476 1477 ddi_walk_devs(ddi_root_node(), dr_cpu_check_node, &arg); 1478 1479 ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip))); 1480 1481 return ((arg.dip) ? arg.dip : NULL); 1482 } 1483 1484 /* 1485 * Look up a particular cpuid in the MD. Returns the mde_cookie_t 1486 * representing that CPU if present, and MDE_INVAL_ELEM_COOKIE 1487 * otherwise. It is assumed the scratch array has already been 1488 * allocated so that it can accommodate the worst case scenario, 1489 * every node in the MD. 1490 */ 1491 static mde_cookie_t 1492 dr_cpu_find_node_md(processorid_t cpuid, md_t *mdp, mde_cookie_t *listp) 1493 { 1494 int idx; 1495 int nnodes; 1496 mde_cookie_t rootnode; 1497 uint64_t cpuid_prop; 1498 mde_cookie_t result = MDE_INVAL_ELEM_COOKIE; 1499 1500 rootnode = md_root_node(mdp); 1501 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 1502 1503 /* 1504 * Scan the DAG for all the CPU nodes 1505 */ 1506 nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), 1507 md_find_name(mdp, "fwd"), listp); 1508 1509 if (nnodes < 0) { 1510 DR_DBG_CPU("Scan for CPUs failed\n"); 1511 return (result); 1512 } 1513 1514 DR_DBG_CPU("dr_cpu_find_node_md: found %d CPUs in the MD\n", nnodes); 1515 1516 /* 1517 * Find the CPU of interest 1518 */ 1519 for (idx = 0; idx < nnodes; idx++) { 1520 1521 if (md_get_prop_val(mdp, listp[idx], "id", &cpuid_prop)) { 1522 DR_DBG_CPU("Missing 'id' property for CPU node %d\n", 1523 idx); 1524 break; 1525 } 1526 1527 if (cpuid_prop == cpuid) { 1528 /* found a match */ 1529 DR_DBG_CPU("dr_cpu_find_node_md: found CPU %d " 1530 "in MD\n", cpuid); 1531 result = listp[idx]; 1532 break; 1533 } 1534 } 1535 1536 if (result == MDE_INVAL_ELEM_COOKIE) { 1537 DR_DBG_CPU("CPU %d not in MD\n", cpuid); 1538 } 1539 1540 return (result); 1541 } 1542