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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2019 Peter Tribble. 29 * Copyright 2019 Joyent, Inc. 30 * Copyright 2023 Oxide Computer Company 31 */ 32 33 /* 34 * CPU support routines for DR 35 */ 36 37 #include <sys/note.h> 38 #include <sys/debug.h> 39 #include <sys/types.h> 40 #include <sys/errno.h> 41 #include <sys/cred.h> 42 #include <sys/dditypes.h> 43 #include <sys/devops.h> 44 #include <sys/modctl.h> 45 #include <sys/poll.h> 46 #include <sys/conf.h> 47 #include <sys/ddi.h> 48 #include <sys/sunddi.h> 49 #include <sys/sunndi.h> 50 #include <sys/ndi_impldefs.h> 51 #include <sys/stat.h> 52 #include <sys/kmem.h> 53 #include <sys/processor.h> 54 #include <sys/cpuvar.h> 55 #include <sys/mem_config.h> 56 #include <sys/promif.h> 57 #include <sys/x_call.h> 58 #include <sys/cpu_sgnblk_defs.h> 59 #include <sys/membar.h> 60 #include <sys/stack.h> 61 #include <sys/sysmacros.h> 62 #include <sys/machsystm.h> 63 #include <sys/spitregs.h> 64 65 #include <sys/archsystm.h> 66 #include <vm/hat_sfmmu.h> 67 #include <sys/pte.h> 68 #include <sys/mmu.h> 69 #include <sys/x_call.h> 70 #include <sys/cpu_module.h> 71 #include <sys/cpu_impl.h> 72 73 #include <sys/autoconf.h> 74 #include <sys/cmn_err.h> 75 76 #include <sys/dr.h> 77 #include <sys/dr_util.h> 78 79 /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */ 80 static char *dr_ie_fmt = "dr_cpu.c %d"; 81 82 int 83 dr_cpu_unit_is_sane(dr_board_t *bp, dr_cpu_unit_t *cp) 84 { 85 #ifdef DEBUG 86 processorid_t cpuid; 87 88 /* 89 * cpuid and unit number should never be different 90 * than they were at discovery/connect time 91 */ 92 ASSERT(drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid) == 0); 93 94 ASSERT(cp->sbc_cm.sbdev_bp == bp); 95 ASSERT(cp->sbc_cm.sbdev_type == SBD_COMP_CPU); 96 ASSERT(cp->sbc_cpu_id == cpuid); 97 #else 98 _NOTE(ARGUNUSED(bp)) 99 _NOTE(ARGUNUSED(cp)) 100 #endif 101 102 return (1); 103 } 104 105 static int 106 dr_errno2ecode(int error) 107 { 108 int rv; 109 110 switch (error) { 111 case EBUSY: 112 rv = ESBD_BUSY; 113 break; 114 case EINVAL: 115 rv = ESBD_INVAL; 116 break; 117 case EALREADY: 118 rv = ESBD_ALREADY; 119 break; 120 case ENODEV: 121 rv = ESBD_NODEV; 122 break; 123 case ENOMEM: 124 rv = ESBD_NOMEM; 125 break; 126 default: 127 rv = ESBD_INVAL; 128 } 129 130 return (rv); 131 } 132 133 static void 134 dr_cpu_set_prop(dr_cpu_unit_t *cp) 135 { 136 sbd_error_t *err; 137 dev_info_t *dip; 138 uint64_t clock_freq; 139 int ecache_size = 0; 140 char *cache_str = NULL; 141 142 err = drmach_get_dip(cp->sbc_cm.sbdev_id, &dip); 143 if (err) { 144 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 145 return; 146 } 147 148 if (dip == NULL) { 149 DR_DEV_INTERNAL_ERROR(&cp->sbc_cm); 150 return; 151 } 152 153 /* read in the CPU speed */ 154 155 /* 156 * If the property is not found in the CPU node, it has to be 157 * kept in the core or cmp node so we just keep looking. 158 */ 159 clock_freq = (unsigned int)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 160 "clock-frequency", 0); 161 162 ASSERT(clock_freq != 0); 163 164 /* 165 * The ecache property string is not the same 166 * for all CPU implementations. 167 */ 168 169 switch (cp->sbc_cpu_impl) { 170 case BLACKBIRD_IMPL: 171 case CHEETAH_IMPL: 172 case CHEETAH_PLUS_IMPL: 173 cache_str = "ecache-size"; 174 break; 175 case JAGUAR_IMPL: 176 case OLYMPUS_C_IMPL: 177 case JUPITER_IMPL: 178 cache_str = "l2-cache-size"; 179 break; 180 case PANTHER_IMPL: 181 cache_str = "l3-cache-size"; 182 break; 183 default: 184 cmn_err(CE_WARN, "Unknown cpu implementation=0x%x", 185 cp->sbc_cpu_impl); 186 ASSERT(0); 187 break; 188 } 189 190 if (cache_str != NULL) { 191 /* read in the ecache size */ 192 /* 193 * If the property is not found in the CPU node, 194 * it has to be kept in the core or cmp node so 195 * we just keep looking. 196 */ 197 198 ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 199 cache_str, 0); 200 } 201 202 ASSERT(ecache_size != 0); 203 204 /* convert to the proper units */ 205 cp->sbc_speed = (clock_freq + 500000) / 1000000; 206 cp->sbc_ecache = ecache_size / (1024 * 1024); 207 } 208 209 void 210 dr_init_cpu_unit(dr_cpu_unit_t *cp) 211 { 212 sbd_error_t *err; 213 dr_state_t new_state; 214 int cpuid; 215 int impl; 216 217 if (DR_DEV_IS_ATTACHED(&cp->sbc_cm)) { 218 new_state = DR_STATE_CONFIGURED; 219 cp->sbc_cm.sbdev_cond = SBD_COND_OK; 220 } else if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) { 221 new_state = DR_STATE_CONNECTED; 222 cp->sbc_cm.sbdev_cond = SBD_COND_OK; 223 } else { 224 new_state = DR_STATE_EMPTY; 225 cp->sbc_cm.sbdev_cond = SBD_COND_UNKNOWN; 226 } 227 228 if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) { 229 err = drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid); 230 if (err) { 231 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 232 new_state = DR_STATE_FATAL; 233 goto done; 234 } 235 236 err = drmach_cpu_get_impl(cp->sbc_cm.sbdev_id, &impl); 237 if (err) { 238 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 239 new_state = DR_STATE_FATAL; 240 goto done; 241 } 242 } else { 243 cp->sbc_cpu_id = -1; 244 cp->sbc_cpu_impl = -1; 245 goto done; 246 } 247 248 cp->sbc_cpu_id = cpuid; 249 cp->sbc_cpu_impl = impl; 250 251 /* if true at init time, it must always be true */ 252 ASSERT(dr_cpu_unit_is_sane(cp->sbc_cm.sbdev_bp, cp)); 253 254 mutex_enter(&cpu_lock); 255 if ((cpuid >= 0) && cpu[cpuid]) 256 cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags; 257 else 258 cp->sbc_cpu_flags = P_OFFLINE | P_POWEROFF; 259 mutex_exit(&cpu_lock); 260 261 dr_cpu_set_prop(cp); 262 263 done: 264 /* delay transition until fully initialized */ 265 dr_device_transition(&cp->sbc_cm, new_state); 266 } 267 268 int 269 dr_pre_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 270 { 271 int i; 272 int curr_cpu; 273 int next_cpu; 274 static fn_t f = "dr_pre_attach_cpu"; 275 276 PR_CPU("%s...\n", f); 277 278 for (next_cpu = 0, i = 0; i < devnum; i++) { 279 dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 280 281 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 282 283 /* 284 * Print a console message for each attachment 285 * point. For CMP devices, this means that only 286 * one message should be printed, no matter how 287 * many cores are actually present. 288 */ 289 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, 290 SBD_COMP_CPU); 291 if (curr_cpu >= next_cpu) { 292 cmn_err(CE_CONT, "OS configure %s", 293 up->sbc_cm.sbdev_path); 294 next_cpu = curr_cpu + 1; 295 } 296 297 if (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED) { 298 /* 299 * If we're coming from the UNCONFIGURED 300 * state then the cpu's sigblock will 301 * still be mapped in. Need to unmap it 302 * before continuing with attachment. 303 */ 304 PR_CPU("%s: unmapping sigblk for cpu %d\n", f, 305 up->sbc_cpu_id); 306 } 307 } 308 309 /* 310 * Block out status threads while creating 311 * devinfo tree branches 312 */ 313 dr_lock_status(hp->h_bd); 314 ndi_devi_enter(ddi_root_node()); 315 mutex_enter(&cpu_lock); 316 317 return (0); 318 } 319 320 /*ARGSUSED*/ 321 void 322 dr_attach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) 323 { 324 sbd_error_t *err; 325 processorid_t cpuid; 326 int rv; 327 328 ASSERT(MUTEX_HELD(&cpu_lock)); 329 330 err = drmach_configure(cp->sbdev_id, 0); 331 if (err) { 332 DRERR_SET_C(&cp->sbdev_error, &err); 333 return; 334 } 335 336 err = drmach_cpu_get_id(cp->sbdev_id, &cpuid); 337 if (err) { 338 DRERR_SET_C(&cp->sbdev_error, &err); 339 340 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 341 if (err) 342 sbd_err_clear(&err); 343 } else if ((rv = cpu_configure(cpuid)) != 0) { 344 dr_dev_err(CE_WARN, cp, dr_errno2ecode(rv)); 345 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 346 if (err) 347 sbd_err_clear(&err); 348 } 349 } 350 351 /* 352 * dr_post_attach_cpu 353 * 354 * sbd error policy: Does not stop on error. Processes all units in list. 355 */ 356 int 357 dr_post_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 358 { 359 int i; 360 int errflag = 0; 361 static fn_t f = "dr_post_attach_cpu"; 362 363 PR_CPU("%s...\n", f); 364 365 /* Startup and online newly-attached CPUs */ 366 for (i = 0; i < devnum; i++) { 367 dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 368 struct cpu *cp; 369 370 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 371 372 cp = cpu_get(up->sbc_cpu_id); 373 if (cp == NULL) { 374 cmn_err(CE_WARN, "%s: cpu_get failed for cpu %d", 375 f, up->sbc_cpu_id); 376 continue; 377 } 378 379 if (cpu_is_poweredoff(cp)) { 380 if (cpu_poweron(cp) != 0) { 381 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTART); 382 errflag = 1; 383 } 384 PR_CPU("%s: cpu %d powered ON\n", f, up->sbc_cpu_id); 385 } 386 387 if (cpu_is_offline(cp)) { 388 PR_CPU("%s: onlining cpu %d...\n", f, up->sbc_cpu_id); 389 390 if (cpu_online(cp, 0) != 0) { 391 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_ONLINE); 392 errflag = 1; 393 } 394 } 395 396 } 397 398 mutex_exit(&cpu_lock); 399 ndi_devi_exit(ddi_root_node()); 400 dr_unlock_status(hp->h_bd); 401 402 if (errflag) 403 return (-1); 404 else 405 return (0); 406 } 407 408 /* 409 * dr_pre_release_cpu 410 * 411 * sbd error policy: Stops on first error. 412 */ 413 int 414 dr_pre_release_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 415 { 416 int c, cix, i, lastoffline = -1, rv = 0; 417 processorid_t cpuid; 418 struct cpu *cp; 419 dr_cpu_unit_t *up; 420 dr_devset_t devset; 421 sbd_dev_stat_t *ds; 422 static fn_t f = "dr_pre_release_cpu"; 423 int cpu_flags = 0; 424 425 devset = DR_DEVS_PRESENT(hp->h_bd); 426 427 /* allocate status struct storage. */ 428 ds = (sbd_dev_stat_t *) kmem_zalloc(sizeof (sbd_dev_stat_t) * 429 MAX_CPU_UNITS_PER_BOARD, KM_SLEEP); 430 431 cix = dr_cpu_status(hp, devset, ds); 432 433 mutex_enter(&cpu_lock); 434 435 for (i = 0; i < devnum; i++) { 436 up = (dr_cpu_unit_t *)devlist[i]; 437 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 438 439 /* 440 * The STARCAT platform borrows cpus for use by POST in 441 * iocage testing. These cpus cannot be unconfigured 442 * while they are in use for the iocage. 443 * This check determines if a CPU is currently in use 444 * for iocage testing, and if so, returns a "Device busy" 445 * error. 446 */ 447 for (c = 0; c < cix; c++) { 448 if (ds[c].d_cpu.cs_unit == up->sbc_cm.sbdev_unum) { 449 if (ds[c].d_cpu.cs_busy) { 450 dr_dev_err(CE_WARN, &up->sbc_cm, 451 ESBD_BUSY); 452 rv = -1; 453 break; 454 } 455 } 456 } 457 if (c < cix) 458 break; 459 cpuid = up->sbc_cpu_id; 460 if ((cp = cpu_get(cpuid)) == NULL) { 461 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 462 rv = -1; 463 break; 464 } 465 466 /* used by dr_cancel_cpu during error flow */ 467 up->sbc_cpu_flags = cp->cpu_flags; 468 469 if (CPU_ACTIVE(cp)) { 470 if (dr_cmd_flags(hp) & SBD_FLAG_FORCE) 471 cpu_flags = CPU_FORCED; 472 473 PR_CPU("%s: offlining cpu %d\n", f, cpuid); 474 if (cpu_offline(cp, cpu_flags)) { 475 PR_CPU("%s: failed to offline cpu %d\n", f, 476 cpuid); 477 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 478 if (disp_bound_threads(cp, 0)) { 479 cmn_err(CE_WARN, "%s: thread(s) bound " 480 "to cpu %d", f, cp->cpu_id); 481 } 482 rv = -1; 483 break; 484 } else 485 lastoffline = i; 486 } 487 488 if (!rv) { 489 sbd_error_t *err; 490 491 err = drmach_release(up->sbc_cm.sbdev_id); 492 if (err) { 493 DRERR_SET_C(&up->sbc_cm.sbdev_error, &err); 494 rv = -1; 495 break; 496 } 497 } 498 } 499 500 mutex_exit(&cpu_lock); 501 502 if (rv) { 503 /* 504 * Need to unwind others since at this level (pre-release) 505 * the device state has not yet transitioned and failures 506 * will prevent us from reaching the "post" release 507 * function where states are normally transitioned. 508 */ 509 for (i = lastoffline; i >= 0; i--) { 510 up = (dr_cpu_unit_t *)devlist[i]; 511 (void) dr_cancel_cpu(up); 512 } 513 } 514 515 kmem_free(ds, sizeof (sbd_dev_stat_t) * MAX_CPU_UNITS_PER_BOARD); 516 return (rv); 517 } 518 519 /* 520 * dr_pre_detach_cpu 521 * 522 * sbd error policy: Stops on first error. 523 */ 524 int 525 dr_pre_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 526 { 527 _NOTE(ARGUNUSED(hp)) 528 529 int i; 530 int curr_cpu; 531 int next_cpu; 532 int cpu_flags = 0; 533 static fn_t f = "dr_pre_detach_cpu"; 534 535 PR_CPU("%s...\n", f); 536 537 /* 538 * Block out status threads while destroying devinfo tree 539 * branches 540 */ 541 dr_lock_status(hp->h_bd); 542 mutex_enter(&cpu_lock); 543 544 for (next_cpu = 0, i = 0; i < devnum; i++) { 545 dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 546 struct cpu *cp; 547 548 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 549 550 cp = cpu_get(up->sbc_cpu_id); 551 if (cp == NULL) 552 continue; 553 554 /* 555 * Print a console message for each attachment 556 * point. For CMP devices, this means that only 557 * one message should be printed, no matter how 558 * many cores are actually present. 559 */ 560 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, 561 SBD_COMP_CPU); 562 if (curr_cpu >= next_cpu) { 563 cmn_err(CE_CONT, "OS unconfigure %s\n", 564 up->sbc_cm.sbdev_path); 565 next_cpu = curr_cpu + 1; 566 } 567 568 /* 569 * CPUs were offlined during Release. 570 */ 571 if (cpu_is_poweredoff(cp)) { 572 PR_CPU("%s: cpu %d already powered OFF\n", 573 f, up->sbc_cpu_id); 574 continue; 575 } 576 577 if (!cpu_is_offline(cp)) { 578 if (dr_cmd_flags(hp) & SBD_FLAG_FORCE) 579 cpu_flags = CPU_FORCED; 580 /* cpu was onlined after release. Offline it again */ 581 PR_CPU("%s: offlining cpu %d\n", f, up->sbc_cpu_id); 582 if (cpu_offline(cp, cpu_flags)) { 583 PR_CPU("%s: failed to offline cpu %d\n", 584 f, up->sbc_cpu_id); 585 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 586 if (disp_bound_threads(cp, 0)) { 587 cmn_err(CE_WARN, "%s: thread(s) bound " 588 "to cpu %d", f, cp->cpu_id); 589 } 590 goto err; 591 } 592 } 593 if (cpu_poweroff(cp) != 0) { 594 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTOP); 595 goto err; 596 } else { 597 PR_CPU("%s: cpu %d powered OFF\n", f, up->sbc_cpu_id); 598 } 599 } 600 601 return (0); 602 603 err: 604 mutex_exit(&cpu_lock); 605 dr_unlock_status(hp->h_bd); 606 return (-1); 607 } 608 609 /*ARGSUSED*/ 610 void 611 dr_detach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) 612 { 613 sbd_error_t *err; 614 processorid_t cpuid; 615 int rv; 616 617 ASSERT(MUTEX_HELD(&cpu_lock)); 618 619 err = drmach_cpu_get_id(cp->sbdev_id, &cpuid); 620 if (err) { 621 DRERR_SET_C(&cp->sbdev_error, &err); 622 } else if ((rv = cpu_unconfigure(cpuid)) != 0) { 623 dr_dev_err(CE_IGNORE, cp, dr_errno2ecode(rv)); 624 } else { 625 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 626 if (err) { 627 DRERR_SET_C(&cp->sbdev_error, &err); 628 } 629 } 630 } 631 632 /*ARGSUSED1*/ 633 int 634 dr_post_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 635 { 636 static fn_t f = "dr_post_detach_cpu"; 637 638 PR_CPU("%s...\n", f); 639 hp->h_ndi = 0; 640 641 mutex_exit(&cpu_lock); 642 dr_unlock_status(hp->h_bd); 643 644 return (0); 645 } 646 647 static void 648 dr_fill_cpu_stat(dr_cpu_unit_t *cp, drmach_status_t *pstat, sbd_cpu_stat_t *csp) 649 { 650 ASSERT(cp && pstat && csp); 651 652 /* Fill in the common status information */ 653 bzero((caddr_t)csp, sizeof (*csp)); 654 csp->cs_type = cp->sbc_cm.sbdev_type; 655 csp->cs_unit = cp->sbc_cm.sbdev_unum; 656 (void) strncpy(csp->cs_name, pstat->type, sizeof (csp->cs_name)); 657 csp->cs_cond = cp->sbc_cm.sbdev_cond; 658 csp->cs_busy = cp->sbc_cm.sbdev_busy | pstat->busy; 659 csp->cs_time = cp->sbc_cm.sbdev_time; 660 csp->cs_ostate = cp->sbc_cm.sbdev_ostate; 661 csp->cs_suspend = 0; 662 663 /* CPU specific status data */ 664 csp->cs_cpuid = cp->sbc_cpu_id; 665 666 /* 667 * If the speed and ecache properties have not been 668 * cached yet, read them in from the device tree. 669 */ 670 if ((cp->sbc_speed == 0) || (cp->sbc_ecache == 0)) 671 dr_cpu_set_prop(cp); 672 673 /* use the cached speed and ecache values */ 674 csp->cs_speed = cp->sbc_speed; 675 csp->cs_ecache = cp->sbc_ecache; 676 677 mutex_enter(&cpu_lock); 678 if (!cpu_get(csp->cs_cpuid)) { 679 /* ostate must be UNCONFIGURED */ 680 csp->cs_cm.c_ostate = SBD_STAT_UNCONFIGURED; 681 } 682 mutex_exit(&cpu_lock); 683 } 684 685 static void 686 dr_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, sbd_cmp_stat_t *psp) 687 { 688 int core; 689 690 ASSERT(csp && psp && (ncores >= 1)); 691 692 bzero((caddr_t)psp, sizeof (*psp)); 693 694 /* 695 * Fill in the common status information based 696 * on the data for the first core. 697 */ 698 psp->ps_type = SBD_COMP_CMP; 699 psp->ps_unit = DR_UNUM2SBD_UNUM(csp->cs_unit, SBD_COMP_CMP); 700 (void) strncpy(psp->ps_name, csp->cs_name, sizeof (psp->ps_name)); 701 psp->ps_cond = csp->cs_cond; 702 psp->ps_busy = csp->cs_busy; 703 psp->ps_time = csp->cs_time; 704 psp->ps_ostate = csp->cs_ostate; 705 psp->ps_suspend = csp->cs_suspend; 706 707 /* CMP specific status data */ 708 *psp->ps_cpuid = csp->cs_cpuid; 709 psp->ps_ncores = 1; 710 psp->ps_speed = csp->cs_speed; 711 psp->ps_ecache = csp->cs_ecache; 712 713 /* 714 * Walk through the data for the remaining cores. 715 * Make any adjustments to the common status data, 716 * or the shared CMP specific data if necessary. 717 */ 718 for (core = 1; core < ncores; core++) { 719 720 /* 721 * The following properties should be the same 722 * for all the cores of the CMP. 723 */ 724 ASSERT(psp->ps_unit == DR_UNUM2SBD_UNUM(csp[core].cs_unit, 725 SBD_COMP_CMP)); 726 ASSERT(psp->ps_speed == csp[core].cs_speed); 727 728 psp->ps_cpuid[core] = csp[core].cs_cpuid; 729 psp->ps_ncores++; 730 731 /* 732 * Jaguar has a split ecache, so the ecache 733 * for each core must be added together to 734 * get the total ecache for the whole chip. 735 */ 736 if (IS_JAGUAR(impl)) { 737 psp->ps_ecache += csp[core].cs_ecache; 738 } 739 740 /* adjust time if necessary */ 741 if (csp[core].cs_time > psp->ps_time) { 742 psp->ps_time = csp[core].cs_time; 743 } 744 745 psp->ps_busy |= csp[core].cs_busy; 746 747 /* 748 * If any of the cores are configured, the 749 * entire CMP is marked as configured. 750 */ 751 if (csp[core].cs_ostate == SBD_STAT_CONFIGURED) { 752 psp->ps_ostate = csp[core].cs_ostate; 753 } 754 } 755 } 756 757 int 758 dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) 759 { 760 int cmp; 761 int core; 762 int ncpu; 763 dr_board_t *bp; 764 sbd_cpu_stat_t cstat[MAX_CORES_PER_CMP]; 765 int impl; 766 767 bp = hp->h_bd; 768 ncpu = 0; 769 770 devset &= DR_DEVS_PRESENT(bp); 771 772 /* 773 * Treat every CPU as a CMP. In the case where the 774 * device is not a CMP, treat it as a CMP with only 775 * one core. 776 */ 777 for (cmp = 0; cmp < MAX_CMP_UNITS_PER_BOARD; cmp++) { 778 779 int ncores; 780 dr_cpu_unit_t *cp; 781 drmach_status_t pstat; 782 sbd_error_t *err; 783 sbd_cmp_stat_t *psp; 784 785 if ((devset & DEVSET(SBD_COMP_CMP, cmp)) == 0) { 786 continue; 787 } 788 789 ncores = 0; 790 791 for (core = 0; core < MAX_CORES_PER_CMP; core++) { 792 793 cp = dr_get_cpu_unit(bp, DR_CMP_CORE_UNUM(cmp, core)); 794 795 if (cp->sbc_cm.sbdev_state == DR_STATE_EMPTY) { 796 /* present, but not fully initialized */ 797 continue; 798 } 799 800 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, cp)); 801 802 /* skip if not present */ 803 if (cp->sbc_cm.sbdev_id == (drmachid_t)0) { 804 continue; 805 } 806 807 /* fetch platform status */ 808 err = drmach_status(cp->sbc_cm.sbdev_id, &pstat); 809 if (err) { 810 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 811 continue; 812 } 813 814 dr_fill_cpu_stat(cp, &pstat, &cstat[ncores++]); 815 /* 816 * We should set impl here because the last core 817 * found might be EMPTY or not present. 818 */ 819 impl = cp->sbc_cpu_impl; 820 } 821 822 if (ncores == 0) { 823 continue; 824 } 825 826 /* 827 * Store the data to the outgoing array. If the 828 * device is a CMP, combine all the data for the 829 * cores into a single stat structure. 830 * 831 * The check for a CMP device uses the last core 832 * found, assuming that all cores will have the 833 * same implementation. 834 */ 835 836 if (CPU_IMPL_IS_CMP(impl)) { 837 psp = (sbd_cmp_stat_t *)dsp; 838 dr_fill_cmp_stat(cstat, ncores, impl, psp); 839 } else { 840 ASSERT(ncores == 1); 841 bcopy(cstat, dsp, sizeof (sbd_cpu_stat_t)); 842 } 843 844 dsp++; 845 ncpu++; 846 } 847 848 return (ncpu); 849 } 850 851 /* 852 * Cancel previous release operation for cpu. 853 * For cpus this means simply bringing cpus that 854 * were offline back online. Note that they had 855 * to have been online at the time there were 856 * released. 857 */ 858 int 859 dr_cancel_cpu(dr_cpu_unit_t *up) 860 { 861 int rv = 0; 862 static fn_t f = "dr_cancel_cpu"; 863 864 ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up)); 865 866 if (cpu_flagged_active(up->sbc_cpu_flags)) { 867 struct cpu *cp; 868 869 /* 870 * CPU had been online, go ahead 871 * bring it back online. 872 */ 873 PR_CPU("%s: bringing cpu %d back ONLINE\n", f, up->sbc_cpu_id); 874 875 mutex_enter(&cpu_lock); 876 cp = cpu[up->sbc_cpu_id]; 877 878 if (cpu_is_poweredoff(cp)) { 879 if (cpu_poweron(cp)) { 880 cmn_err(CE_WARN, "%s: failed to power-on " 881 "cpu %d", f, up->sbc_cpu_id); 882 rv = -1; 883 } 884 } 885 886 if (cpu_is_offline(cp)) { 887 if (cpu_online(cp, 0)) { 888 cmn_err(CE_WARN, "%s: failed to online cpu %d", 889 f, up->sbc_cpu_id); 890 rv = -1; 891 } 892 } 893 894 if (cpu_is_online(cp)) { 895 if (cpu_flagged_nointr(up->sbc_cpu_flags)) { 896 if (cpu_intr_disable(cp) != 0) { 897 cmn_err(CE_WARN, "%s: failed to " 898 "disable interrupts on cpu %d", f, 899 up->sbc_cpu_id); 900 } 901 } 902 } 903 904 mutex_exit(&cpu_lock); 905 } 906 907 return (rv); 908 } 909 910 int 911 dr_disconnect_cpu(dr_cpu_unit_t *up) 912 { 913 sbd_error_t *err; 914 static fn_t f = "dr_disconnect_cpu"; 915 916 PR_CPU("%s...\n", f); 917 918 ASSERT((up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) || 919 (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED)); 920 921 ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up)); 922 923 if (up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) { 924 /* 925 * Cpus were never brought in and so are still 926 * effectively disconnected, so nothing to do here. 927 */ 928 PR_CPU("%s: cpu %d never brought in\n", f, up->sbc_cpu_id); 929 return (0); 930 } 931 932 err = drmach_cpu_disconnect(up->sbc_cm.sbdev_id); 933 if (err == NULL) 934 return (0); 935 else { 936 DRERR_SET_C(&up->sbc_cm.sbdev_error, &err); 937 return (-1); 938 } 939 /*NOTREACHED*/ 940 } 941