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