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 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2016 by Delphix. All rights reserved. 24 */ 25 26 #include <sys/systm.h> 27 #include <sys/types.h> 28 #include <sys/param.h> 29 #include <sys/thread.h> 30 #include <sys/cpuvar.h> 31 #include <sys/kmem.h> 32 #include <sys/cmn_err.h> 33 #include <sys/policy.h> 34 #include <sys/group.h> 35 #include <sys/pg.h> 36 #include <sys/pghw.h> 37 #include <sys/cpu_pm.h> 38 #include <sys/cap_util.h> 39 40 /* 41 * Processor Groups: Hardware sharing relationship layer 42 * 43 * This file implements an extension to Processor Groups to capture 44 * hardware sharing relationships existing between logical CPUs. Examples of 45 * hardware sharing relationships include shared caches on some CMT 46 * procesoor architectures, or shared local memory controllers on NUMA 47 * based system architectures. 48 * 49 * The pghw_t structure represents the extended PG. The first member 50 * of the structure is the generic pg_t with the pghw specific members 51 * following. The generic pg_t *must* remain the first member of the 52 * structure as the code uses casting of structure references to access 53 * the generic pg_t structure elements. 54 * 55 * In addition to the generic CPU grouping, physical PGs have a hardware 56 * sharing relationship enumerated "type", and an instance id. The enumerated 57 * type is defined by the pghw_type_t enumeration, while the instance id 58 * uniquely identifies the sharing instance from among others of the same 59 * hardware sharing type. 60 * 61 * The physical PGs are organized into an overall hierarchy, and are tracked 62 * in a number of different per CPU, and per pghw_type_t type groups. 63 * As an example: 64 * 65 * ------------- 66 * | pg_hw | 67 * | (group_t) | 68 * ------------- 69 * || ============================ 70 * ||\\-----------------------// \\ \\ 71 * || | hwset (PGC_HW_CHIP) | ------------- ------------- 72 * || | (group_t) | | pghw_t | | pghw_t | 73 * || ----------------------- | chip 0 | | chip 1 | 74 * || ------------- ------------- 75 * || \\ \\ \\ \\ \\ \\ \\ \\ 76 * || cpu cpu cpu cpu cpu cpu cpu cpu 77 * || 78 * || ============================ 79 * ||\\-----------------------// \\ \\ 80 * || | hwset (PGC_HW_IPIPE)| ------------- ------------- 81 * || | (group_t) | | pghw_t | | pghw_t | 82 * || ----------------------- | ipipe 0 | | ipipe 1 | 83 * || ------------- ------------- 84 * || \\ \\ \\ \\ 85 * || cpu cpu cpu cpu 86 * ... 87 * 88 * 89 * The top level pg_hw is a group of "hwset" groups. Each hwset holds of group 90 * of physical PGs of the same hardware sharing type. Within each hwset, the 91 * PG's instance id uniquely identifies the grouping relationshsip among other 92 * groupings of the same sharing type. The instance id for a grouping is 93 * platform defined, and in some cases may be used by platform code as a handle 94 * to search for a particular relationship instance. 95 * 96 * Each physical PG (by virtue of the embedded pg_t) contains a group of CPUs 97 * that participate in the sharing relationship. Each CPU also has associated 98 * with it a grouping tracking the PGs in which the CPU belongs. This can be 99 * used to iterate over the various relationships in which the CPU participates 100 * (the CPU's chip, cache, lgroup, etc.). 101 * 102 * The hwsets are created dynamically as new hardware sharing relationship types 103 * are instantiated. They are never destroyed, as once a given relationship 104 * type appears in the system, it is quite likely that at least one instance of 105 * that relationship will always persist as long as the system is running. 106 */ 107 108 static group_t *pg_hw; /* top level pg hw group */ 109 110 /* 111 * Physical PG kstats 112 */ 113 struct pghw_kstat { 114 kstat_named_t pg_id; 115 kstat_named_t pg_class; 116 kstat_named_t pg_ncpus; 117 kstat_named_t pg_instance_id; 118 kstat_named_t pg_hw; 119 kstat_named_t pg_policy; 120 } pghw_kstat = { 121 { "id", KSTAT_DATA_INT32 }, 122 { "pg_class", KSTAT_DATA_STRING }, 123 { "ncpus", KSTAT_DATA_UINT32 }, 124 { "instance_id", KSTAT_DATA_UINT32 }, 125 { "hardware", KSTAT_DATA_STRING }, 126 { "policy", KSTAT_DATA_STRING }, 127 }; 128 129 kmutex_t pghw_kstat_lock; 130 131 /* 132 * Capacity and Utilization PG kstats 133 * 134 * These kstats are updated one at a time, so we can have a single scratch space 135 * to fill the data. 136 * 137 * kstat fields: 138 * 139 * pg_id PG ID for PG described by this kstat 140 * 141 * pg_parent Parent PG ID. The value -1 means "no parent". 142 * 143 * pg_ncpus Number of CPUs within this PG 144 * 145 * pg_cpus String describing CPUs within this PG 146 * 147 * pg_relationship Name of sharing relationship for this PG 148 * 149 * pg_generation Generation value that increases whenever any CPU leaves 150 * or joins PG. Two kstat snapshots for the same 151 * CPU may only be compared if they have the same 152 * generation 153 * 154 * pg_hw_util Running value of PG utilization for the sharing 155 * relationship 156 * 157 * pg_hw_util_time_running 158 * Total time spent collecting CU data. The time may be 159 * less than wall time if CU counters were stopped for 160 * some time. 161 * 162 * pg_hw_util_time_stopped Total time the CU counters were stopped. 163 * 164 * pg_hw_util_rate Utilization rate, expressed in operations per second. 165 * 166 * pg_hw_util_rate_max Maximum observed value of utilization rate. 167 */ 168 struct pghw_cu_kstat { 169 kstat_named_t pg_id; 170 kstat_named_t pg_parent_id; 171 kstat_named_t pg_ncpus; 172 kstat_named_t pg_generation; 173 kstat_named_t pg_hw_util; 174 kstat_named_t pg_hw_util_time_running; 175 kstat_named_t pg_hw_util_time_stopped; 176 kstat_named_t pg_hw_util_rate; 177 kstat_named_t pg_hw_util_rate_max; 178 kstat_named_t pg_cpus; 179 kstat_named_t pg_relationship; 180 } pghw_cu_kstat = { 181 { "pg_id", KSTAT_DATA_INT32 }, 182 { "parent_pg_id", KSTAT_DATA_INT32 }, 183 { "ncpus", KSTAT_DATA_UINT32 }, 184 { "generation", KSTAT_DATA_UINT32 }, 185 { "hw_util", KSTAT_DATA_UINT64 }, 186 { "hw_util_time_running", KSTAT_DATA_UINT64 }, 187 { "hw_util_time_stopped", KSTAT_DATA_UINT64 }, 188 { "hw_util_rate", KSTAT_DATA_UINT64 }, 189 { "hw_util_rate_max", KSTAT_DATA_UINT64 }, 190 { "cpus", KSTAT_DATA_STRING }, 191 { "relationship", KSTAT_DATA_STRING }, 192 }; 193 194 /* 195 * Calculate the string size to represent NCPUS. Allow 5 digits for each CPU ID 196 * plus one space per CPU plus NUL byte in the end. This is only an estimate, 197 * since we try to compress CPU ranges as x-y. In the worst case the string 198 * representation of CPUs may be truncated. 199 */ 200 #define CPUSTR_LEN(ncpus) ((ncpus) * 6) 201 202 /* 203 * Maximum length of the string that represents list of CPUs 204 */ 205 static int pg_cpulist_maxlen = 0; 206 207 static void pghw_kstat_create(pghw_t *); 208 static int pghw_kstat_update(kstat_t *, int); 209 static int pghw_cu_kstat_update(kstat_t *, int); 210 static int cpu2id(void *); 211 212 /* 213 * hwset operations 214 */ 215 static group_t *pghw_set_create(pghw_type_t); 216 static void pghw_set_add(group_t *, pghw_t *); 217 static void pghw_set_remove(group_t *, pghw_t *); 218 219 static void pghw_cpulist_alloc(pghw_t *); 220 static int cpu2id(void *); 221 static pgid_t pghw_parent_id(pghw_t *); 222 223 /* 224 * Initialize the physical portion of a hardware PG 225 */ 226 void 227 pghw_init(pghw_t *pg, cpu_t *cp, pghw_type_t hw) 228 { 229 group_t *hwset; 230 231 if ((hwset = pghw_set_lookup(hw)) == NULL) { 232 /* 233 * Haven't seen this hardware type yet 234 */ 235 hwset = pghw_set_create(hw); 236 } 237 238 pghw_set_add(hwset, pg); 239 pg->pghw_hw = hw; 240 pg->pghw_generation = 0; 241 pg->pghw_instance = 242 pg_plat_hw_instance_id(cp, hw); 243 pghw_kstat_create(pg); 244 245 /* 246 * Hardware sharing relationship specific initialization 247 */ 248 switch (pg->pghw_hw) { 249 case PGHW_POW_ACTIVE: 250 pg->pghw_handle = 251 (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_ACTIVE); 252 break; 253 case PGHW_POW_IDLE: 254 pg->pghw_handle = 255 (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_IDLE); 256 break; 257 default: 258 pg->pghw_handle = (pghw_handle_t)NULL; 259 } 260 } 261 262 /* 263 * Teardown the physical portion of a physical PG 264 */ 265 void 266 pghw_fini(pghw_t *pg) 267 { 268 group_t *hwset; 269 270 pghw_cmt_fini(pg); 271 272 hwset = pghw_set_lookup(pg->pghw_hw); 273 ASSERT(hwset != NULL); 274 275 pghw_set_remove(hwset, pg); 276 pg->pghw_instance = (id_t)PGHW_INSTANCE_ANON; 277 pg->pghw_hw = (pghw_type_t)-1; 278 279 if (pg->pghw_kstat != NULL) 280 kstat_delete(pg->pghw_kstat); 281 282 } 283 284 /* 285 * PG is removed from CMT hierarchy 286 */ 287 void 288 pghw_cmt_fini(pghw_t *pg) 289 { 290 /* 291 * Destroy string representation of CPUs 292 */ 293 if (pg->pghw_cpulist != NULL) { 294 kmem_free(pg->pghw_cpulist, 295 pg->pghw_cpulist_len); 296 pg->pghw_cpulist = NULL; 297 } 298 299 /* 300 * Destroy CU kstats 301 */ 302 if (pg->pghw_cu_kstat != NULL) { 303 kstat_delete(pg->pghw_cu_kstat); 304 pg->pghw_cu_kstat = NULL; 305 } 306 } 307 308 /* 309 * Find an existing physical PG in which to place 310 * the given CPU for the specified hardware sharing 311 * relationship 312 */ 313 pghw_t * 314 pghw_place_cpu(cpu_t *cp, pghw_type_t hw) 315 { 316 group_t *hwset; 317 318 if ((hwset = pghw_set_lookup(hw)) == NULL) { 319 return (NULL); 320 } 321 322 return ((pghw_t *)pg_cpu_find_pg(cp, hwset)); 323 } 324 325 /* 326 * Find the pg representing the hw sharing relationship in which 327 * cp belongs 328 */ 329 pghw_t * 330 pghw_find_pg(cpu_t *cp, pghw_type_t hw) 331 { 332 group_iter_t i; 333 pghw_t *pg; 334 335 group_iter_init(&i); 336 while ((pg = group_iterate(&cp->cpu_pg->pgs, &i)) != NULL) { 337 if (pg->pghw_hw == hw) 338 return (pg); 339 } 340 return (NULL); 341 } 342 343 /* 344 * Find the PG of the given hardware sharing relationship 345 * type with the given instance id 346 */ 347 pghw_t * 348 pghw_find_by_instance(id_t id, pghw_type_t hw) 349 { 350 group_iter_t i; 351 group_t *set; 352 pghw_t *pg; 353 354 set = pghw_set_lookup(hw); 355 if (!set) 356 return (NULL); 357 358 group_iter_init(&i); 359 while ((pg = group_iterate(set, &i)) != NULL) { 360 if (pg->pghw_instance == id) 361 return (pg); 362 } 363 return (NULL); 364 } 365 366 /* 367 * CPUs physical ID cache creation / destruction 368 * The cache's elements are initialized to the CPU's id 369 */ 370 void 371 pghw_physid_create(cpu_t *cp) 372 { 373 int i; 374 375 cp->cpu_physid = kmem_alloc(sizeof (cpu_physid_t), KM_SLEEP); 376 377 for (i = 0; i < (sizeof (cpu_physid_t) / sizeof (id_t)); i++) { 378 ((id_t *)cp->cpu_physid)[i] = cp->cpu_id; 379 } 380 } 381 382 void 383 pghw_physid_destroy(cpu_t *cp) 384 { 385 if (cp->cpu_physid) { 386 kmem_free(cp->cpu_physid, sizeof (cpu_physid_t)); 387 cp->cpu_physid = NULL; 388 } 389 } 390 391 /* 392 * Create a new, empty hwset. 393 * This routine may block, and must not be called from any 394 * paused CPU context. 395 */ 396 static group_t * 397 pghw_set_create(pghw_type_t hw) 398 { 399 group_t *g; 400 int ret; 401 402 /* 403 * Create the top level PG hw group if it doesn't already exist 404 * This is a "set" of hardware sets, that is ordered (and indexed) 405 * by the pghw_type_t enum. 406 */ 407 if (pg_hw == NULL) { 408 pg_hw = kmem_alloc(sizeof (group_t), KM_SLEEP); 409 group_create(pg_hw); 410 group_expand(pg_hw, (uint_t)PGHW_NUM_COMPONENTS); 411 } 412 413 /* 414 * Create the new hwset 415 * Add it to the top level pg_hw group. 416 */ 417 g = kmem_alloc(sizeof (group_t), KM_SLEEP); 418 group_create(g); 419 420 ret = group_add_at(pg_hw, g, (uint_t)hw); 421 ASSERT(ret == 0); 422 423 return (g); 424 } 425 426 /* 427 * Find the hwset associated with the given hardware sharing type 428 */ 429 group_t * 430 pghw_set_lookup(pghw_type_t hw) 431 { 432 group_t *hwset; 433 434 if (pg_hw == NULL) 435 return (NULL); 436 437 hwset = GROUP_ACCESS(pg_hw, (uint_t)hw); 438 return (hwset); 439 } 440 441 /* 442 * Add a PG to a hwset 443 */ 444 static void 445 pghw_set_add(group_t *hwset, pghw_t *pg) 446 { 447 (void) group_add(hwset, pg, GRP_RESIZE); 448 } 449 450 /* 451 * Remove a PG from a hwset 452 */ 453 static void 454 pghw_set_remove(group_t *hwset, pghw_t *pg) 455 { 456 int result; 457 458 result = group_remove(hwset, pg, GRP_RESIZE); 459 ASSERT(result == 0); 460 } 461 462 /* 463 * Return a string name given a pg_hw sharing type 464 */ 465 char * 466 pghw_type_string(pghw_type_t hw) 467 { 468 switch (hw) { 469 case PGHW_IPIPE: 470 return ("Integer Pipeline"); 471 case PGHW_CACHE: 472 return ("Cache"); 473 case PGHW_FPU: 474 return ("Floating Point Unit"); 475 case PGHW_MPIPE: 476 return ("Data Pipe to memory"); 477 case PGHW_CHIP: 478 return ("Socket"); 479 case PGHW_MEMORY: 480 return ("Memory"); 481 case PGHW_POW_ACTIVE: 482 return ("CPU PM Active Power Domain"); 483 case PGHW_POW_IDLE: 484 return ("CPU PM Idle Power Domain"); 485 default: 486 return ("unknown"); 487 } 488 } 489 490 /* 491 * Create / Update routines for PG hw kstats 492 * 493 * It is the intention of these kstats to provide some level 494 * of informational / debugging observability into the types 495 * and nature of the system's detected hardware sharing relationships 496 */ 497 void 498 pghw_kstat_create(pghw_t *pg) 499 { 500 char *sharing = pghw_type_string(pg->pghw_hw); 501 char name[KSTAT_STRLEN + 1]; 502 503 /* 504 * Canonify PG name to conform to kstat name rules 505 */ 506 (void) strncpy(name, pghw_type_string(pg->pghw_hw), KSTAT_STRLEN + 1); 507 strident_canon(name, KSTAT_STRLEN + 1); 508 509 /* 510 * Create a hardware performance kstat 511 */ 512 if ((pg->pghw_kstat = kstat_create("pg", ((pg_t *)pg)->pg_id, 513 "pg", "pg", 514 KSTAT_TYPE_NAMED, 515 sizeof (pghw_kstat) / sizeof (kstat_named_t), 516 KSTAT_FLAG_VIRTUAL)) != NULL) { 517 /* Class string, hw string, and policy string */ 518 pg->pghw_kstat->ks_data_size += PG_CLASS_NAME_MAX; 519 pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX; 520 pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX; 521 pg->pghw_kstat->ks_lock = &pghw_kstat_lock; 522 pg->pghw_kstat->ks_data = &pghw_kstat; 523 pg->pghw_kstat->ks_update = pghw_kstat_update; 524 pg->pghw_kstat->ks_private = pg; 525 kstat_install(pg->pghw_kstat); 526 } 527 528 if (pg_cpulist_maxlen == 0) 529 pg_cpulist_maxlen = CPUSTR_LEN(max_ncpus); 530 531 /* 532 * Create a physical pg kstat 533 */ 534 if ((pg->pghw_cu_kstat = kstat_create("pg_hw_perf", ((pg_t *)pg)->pg_id, 535 name, "processor_group", 536 KSTAT_TYPE_NAMED, 537 sizeof (pghw_cu_kstat) / sizeof (kstat_named_t), 538 KSTAT_FLAG_VIRTUAL)) != NULL) { 539 pg->pghw_cu_kstat->ks_lock = &pghw_kstat_lock; 540 pg->pghw_cu_kstat->ks_data = &pghw_cu_kstat; 541 pg->pghw_cu_kstat->ks_update = pghw_cu_kstat_update; 542 pg->pghw_cu_kstat->ks_private = pg; 543 pg->pghw_cu_kstat->ks_data_size += strlen(sharing) + 1; 544 /* Allow space for CPU strings */ 545 pg->pghw_cu_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX; 546 pg->pghw_cu_kstat->ks_data_size += pg_cpulist_maxlen; 547 kstat_install(pg->pghw_cu_kstat); 548 } 549 } 550 551 int 552 pghw_kstat_update(kstat_t *ksp, int rw) 553 { 554 struct pghw_kstat *pgsp = &pghw_kstat; 555 pghw_t *pg = ksp->ks_private; 556 557 if (rw == KSTAT_WRITE) 558 return (EACCES); 559 560 pgsp->pg_id.value.ui32 = ((pg_t *)pg)->pg_id; 561 pgsp->pg_ncpus.value.ui32 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus); 562 pgsp->pg_instance_id.value.ui32 = pg->pghw_instance; 563 kstat_named_setstr(&pgsp->pg_class, ((pg_t *)pg)->pg_class->pgc_name); 564 kstat_named_setstr(&pgsp->pg_hw, pghw_type_string(pg->pghw_hw)); 565 kstat_named_setstr(&pgsp->pg_policy, pg_policy_name((pg_t *)pg)); 566 return (0); 567 } 568 569 int 570 pghw_cu_kstat_update(kstat_t *ksp, int rw) 571 { 572 struct pghw_cu_kstat *pgsp = &pghw_cu_kstat; 573 pghw_t *pg = ksp->ks_private; 574 pghw_util_t *hw_util = &pg->pghw_stats; 575 boolean_t has_cpc_privilege; 576 577 if (rw == KSTAT_WRITE) 578 return (EACCES); 579 580 /* 581 * Check whether the caller has priv_cpc_cpu privilege. If it doesn't, 582 * it will not get hardware utilization data. 583 */ 584 585 has_cpc_privilege = (secpolicy_cpc_cpu(crgetcred()) == 0); 586 587 pgsp->pg_id.value.i32 = ((pg_t *)pg)->pg_id; 588 pgsp->pg_parent_id.value.i32 = (int)pghw_parent_id(pg); 589 590 pgsp->pg_ncpus.value.ui32 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus); 591 592 /* 593 * Allocate memory for the string representing the list of CPUs in PG. 594 * This memory should persist past the call to pghw_cu_kstat_update() 595 * since the kstat snapshot routine will reference this memory. 596 */ 597 pghw_cpulist_alloc(pg); 598 599 if (pg->pghw_kstat_gen != pg->pghw_generation) { 600 /* 601 * PG kstat generation number is out of sync with PG's 602 * generation mumber. It means that some CPUs could have joined 603 * or left PG and it is not possible to compare the numbers 604 * obtained before and after the generation change. 605 * 606 * Reset the maximum utilization rate and start computing it 607 * from scratch. 608 */ 609 hw_util->pghw_util = 0; 610 hw_util->pghw_rate_max = 0; 611 pg->pghw_kstat_gen = pg->pghw_generation; 612 } 613 614 /* 615 * We can't block on CPU lock because when PG is destroyed (under 616 * cpu_lock) it tries to delete this kstat and it will wait for us to 617 * complete which will never happen since we are waiting for cpu_lock to 618 * drop. Deadlocks are fun! 619 */ 620 if (mutex_tryenter(&cpu_lock)) { 621 if (pg->pghw_cpulist != NULL && 622 *(pg->pghw_cpulist) == '\0') { 623 (void) group2intlist(&(((pg_t *)pg)->pg_cpus), 624 pg->pghw_cpulist, pg->pghw_cpulist_len, cpu2id); 625 } 626 627 if (has_cpc_privilege) 628 cu_pg_update(pg); 629 630 mutex_exit(&cpu_lock); 631 } 632 633 pgsp->pg_generation.value.ui32 = pg->pghw_kstat_gen; 634 if (pg->pghw_cpulist != NULL) 635 kstat_named_setstr(&pgsp->pg_cpus, pg->pghw_cpulist); 636 else 637 kstat_named_setstr(&pgsp->pg_cpus, ""); 638 639 kstat_named_setstr(&pgsp->pg_relationship, 640 pghw_type_string(pg->pghw_hw)); 641 642 if (has_cpc_privilege) { 643 pgsp->pg_hw_util.value.ui64 = hw_util->pghw_util; 644 pgsp->pg_hw_util_time_running.value.ui64 = 645 hw_util->pghw_time_running; 646 pgsp->pg_hw_util_time_stopped.value.ui64 = 647 hw_util->pghw_time_stopped; 648 pgsp->pg_hw_util_rate.value.ui64 = hw_util->pghw_rate; 649 pgsp->pg_hw_util_rate_max.value.ui64 = hw_util->pghw_rate_max; 650 } else { 651 pgsp->pg_hw_util.value.ui64 = 0; 652 pgsp->pg_hw_util_time_running.value.ui64 = 0; 653 pgsp->pg_hw_util_time_stopped.value.ui64 = 0; 654 pgsp->pg_hw_util_rate.value.ui64 = 0; 655 pgsp->pg_hw_util_rate_max.value.ui64 = 0; 656 } 657 658 return (0); 659 } 660 661 /* 662 * Update the string representation of CPUs in PG (pg->pghw_cpulist). 663 * The string representation is used for kstats. 664 * 665 * The string is allocated if it has not already been or if it is already 666 * allocated and PG has more CPUs now. If PG has smaller or equal number of 667 * CPUs, but the actual CPUs may have changed, the string is reset to the empty 668 * string causes the string representation to be recreated. The pghw_generation 669 * field is used to detect whether CPUs within the pg may have changed. 670 */ 671 static void 672 pghw_cpulist_alloc(pghw_t *pg) 673 { 674 uint_t ncpus = GROUP_SIZE(&((pg_t *)pg)->pg_cpus); 675 size_t len = CPUSTR_LEN(ncpus); 676 677 /* 678 * If the pghw_cpulist string is already allocated we need to make sure 679 * that it has sufficient length. Also if the set of CPUs may have 680 * changed, we need to re-generate the string. 681 */ 682 if (pg->pghw_cpulist != NULL && 683 pg->pghw_kstat_gen != pg->pghw_generation) { 684 if (len <= pg->pghw_cpulist_len) { 685 /* 686 * There is sufficient space in the pghw_cpulist for 687 * the new set of CPUs. Just clear the string to trigger 688 * re-generation of list of CPUs 689 */ 690 *(pg->pghw_cpulist) = '\0'; 691 } else { 692 /* 693 * There is, potentially, insufficient space in 694 * pghw_cpulist, so reallocate the string. 695 */ 696 ASSERT(strlen(pg->pghw_cpulist) < pg->pghw_cpulist_len); 697 kmem_free(pg->pghw_cpulist, pg->pghw_cpulist_len); 698 pg->pghw_cpulist = NULL; 699 pg->pghw_cpulist_len = 0; 700 } 701 } 702 703 if (pg->pghw_cpulist == NULL) { 704 /* 705 * Allocate space to hold cpulist. 706 * 707 * Length can not be bigger that the maximum space we have 708 * allowed for the kstat buffer 709 */ 710 if (len > pg_cpulist_maxlen) 711 len = pg_cpulist_maxlen; 712 if (len > 0) { 713 pg->pghw_cpulist = kmem_zalloc(len, KM_NOSLEEP); 714 if (pg->pghw_cpulist != NULL) 715 pg->pghw_cpulist_len = len; 716 } 717 } 718 } 719 720 static int 721 cpu2id(void *v) 722 { 723 cpu_t *cp = (cpu_t *)v; 724 725 ASSERT(v != NULL); 726 727 return (cp->cpu_id); 728 } 729 730 /* 731 * Return parent ID or -1 if there is no parent. 732 * All hardware PGs are currently also CMT PGs, but for safety we check the 733 * class matches cmt before we upcast the pghw pointer to pg_cmt_t. 734 */ 735 static pgid_t 736 pghw_parent_id(pghw_t *pghw) 737 { 738 pg_t *pg = (pg_t *)pghw; 739 pgid_t parent_id = -1; 740 741 if (pg != NULL && strcmp(pg->pg_class->pgc_name, "cmt") == 0) { 742 pg_cmt_t *cmt = (pg_cmt_t *)pg; 743 pg_t *parent = (pg_t *)cmt->cmt_parent; 744 if (parent != NULL) 745 parent_id = parent->pg_id; 746 } 747 748 return (parent_id); 749 } 750