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