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*0e751525SEric Saxe * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fb2f18f8Sesaxe * Use is subject to license terms. 24fb2f18f8Sesaxe */ 25fb2f18f8Sesaxe 26fb2f18f8Sesaxe #include <sys/systm.h> 27fb2f18f8Sesaxe #include <sys/types.h> 28fb2f18f8Sesaxe #include <sys/param.h> 29fb2f18f8Sesaxe #include <sys/thread.h> 30fb2f18f8Sesaxe #include <sys/cpuvar.h> 31fb2f18f8Sesaxe #include <sys/kmem.h> 32fb2f18f8Sesaxe #include <sys/cmn_err.h> 33fb2f18f8Sesaxe #include <sys/group.h> 34fb2f18f8Sesaxe #include <sys/pg.h> 35fb2f18f8Sesaxe #include <sys/pghw.h> 36*0e751525SEric Saxe #include <sys/cpu_pm.h> 37fb2f18f8Sesaxe 38fb2f18f8Sesaxe /* 39fb2f18f8Sesaxe * Processor Groups: Hardware sharing relationship layer 40fb2f18f8Sesaxe * 41fb2f18f8Sesaxe * This file implements an extension to Processor Groups to capture 42fb2f18f8Sesaxe * hardware sharing relationships existing between logical CPUs. Examples of 43fb2f18f8Sesaxe * hardware sharing relationships include shared caches on some CMT 44fb2f18f8Sesaxe * procesoor architectures, or shared local memory controllers on NUMA 45fb2f18f8Sesaxe * based system architectures. 46fb2f18f8Sesaxe * 47fb2f18f8Sesaxe * The pghw_t structure represents the extended PG. The first member 48fb2f18f8Sesaxe * of the structure is the generic pg_t with the pghw specific members 49fb2f18f8Sesaxe * following. The generic pg_t *must* remain the first member of the 50fb2f18f8Sesaxe * structure as the code uses casting of structure references to access 51fb2f18f8Sesaxe * the generic pg_t structure elements. 52fb2f18f8Sesaxe * 53fb2f18f8Sesaxe * In addition to the generic CPU grouping, physical PGs have a hardware 54fb2f18f8Sesaxe * sharing relationship enumerated "type", and an instance id. The enumerated 55fb2f18f8Sesaxe * type is defined by the pghw_type_t enumeration, while the instance id 56fb2f18f8Sesaxe * uniquely identifies the sharing instance from among others of the same 57fb2f18f8Sesaxe * hardware sharing type. 58fb2f18f8Sesaxe * 59fb2f18f8Sesaxe * The physical PGs are organized into an overall hierarchy, and are tracked 60fb2f18f8Sesaxe * in a number of different per CPU, and per pghw_type_t type groups. 61fb2f18f8Sesaxe * As an example: 62fb2f18f8Sesaxe * 63fb2f18f8Sesaxe * ------------- 64fb2f18f8Sesaxe * | pg_hw | 65fb2f18f8Sesaxe * | (group_t) | 66fb2f18f8Sesaxe * ------------- 67fb2f18f8Sesaxe * || ============================ 68fb2f18f8Sesaxe * ||\\-----------------------// \\ \\ 69fb2f18f8Sesaxe * || | hwset (PGC_HW_CHIP) | ------------- ------------- 70fb2f18f8Sesaxe * || | (group_t) | | pghw_t | | pghw_t | 71fb2f18f8Sesaxe * || ----------------------- | chip 0 | | chip 1 | 72fb2f18f8Sesaxe * || ------------- ------------- 73fb2f18f8Sesaxe * || \\ \\ \\ \\ \\ \\ \\ \\ 74fb2f18f8Sesaxe * || cpu cpu cpu cpu cpu cpu cpu cpu 75fb2f18f8Sesaxe * || 76fb2f18f8Sesaxe * || ============================ 77fb2f18f8Sesaxe * ||\\-----------------------// \\ \\ 78fb2f18f8Sesaxe * || | hwset (PGC_HW_IPIPE)| ------------- ------------- 79fb2f18f8Sesaxe * || | (group_t) | | pghw_t | | pghw_t | 80fb2f18f8Sesaxe * || ----------------------- | ipipe 0 | | ipipe 1 | 81fb2f18f8Sesaxe * || ------------- ------------- 82fb2f18f8Sesaxe * || \\ \\ \\ \\ 83fb2f18f8Sesaxe * || cpu cpu cpu cpu 84fb2f18f8Sesaxe * ... 85fb2f18f8Sesaxe * 86fb2f18f8Sesaxe * 87fb2f18f8Sesaxe * The top level pg_hw is a group of "hwset" groups. Each hwset holds of group 88fb2f18f8Sesaxe * of physical PGs of the same hardware sharing type. Within each hwset, the 89fb2f18f8Sesaxe * PG's instance id uniquely identifies the grouping relationshsip among other 90fb2f18f8Sesaxe * groupings of the same sharing type. The instance id for a grouping is 91fb2f18f8Sesaxe * platform defined, and in some cases may be used by platform code as a handle 92fb2f18f8Sesaxe * to search for a particular relationship instance. 93fb2f18f8Sesaxe * 94fb2f18f8Sesaxe * Each physical PG (by virtue of the embedded pg_t) contains a group of CPUs 95fb2f18f8Sesaxe * that participate in the sharing relationship. Each CPU also has associated 96fb2f18f8Sesaxe * with it a grouping tracking the PGs in which the CPU belongs. This can be 97fb2f18f8Sesaxe * used to iterate over the various relationships in which the CPU participates 98fb2f18f8Sesaxe * (the CPU's chip, cache, lgroup, etc.). 99fb2f18f8Sesaxe * 100fb2f18f8Sesaxe * The hwsets are created dynamically as new hardware sharing relationship types 101*0e751525SEric Saxe * are instantiated. They are never destroyed, as once a given relationship 102fb2f18f8Sesaxe * type appears in the system, it is quite likely that at least one instance of 103fb2f18f8Sesaxe * that relationship will always persist as long as the system is running. 104fb2f18f8Sesaxe */ 105fb2f18f8Sesaxe 106fb2f18f8Sesaxe static group_t *pg_hw; /* top level pg hw group */ 107fb2f18f8Sesaxe 108fb2f18f8Sesaxe /* 109fb2f18f8Sesaxe * Physical PG kstats 110fb2f18f8Sesaxe */ 111fb2f18f8Sesaxe struct pghw_kstat { 112fb2f18f8Sesaxe kstat_named_t pg_id; 113fb2f18f8Sesaxe kstat_named_t pg_class; 114fb2f18f8Sesaxe kstat_named_t pg_ncpus; 115fb2f18f8Sesaxe kstat_named_t pg_instance_id; 116fb2f18f8Sesaxe kstat_named_t pg_hw; 117*0e751525SEric Saxe kstat_named_t pg_policy; 118fb2f18f8Sesaxe } pghw_kstat = { 119fb2f18f8Sesaxe { "id", KSTAT_DATA_UINT64 }, 120fb2f18f8Sesaxe { "pg_class", KSTAT_DATA_STRING }, 121fb2f18f8Sesaxe { "ncpus", KSTAT_DATA_UINT64 }, 122fb2f18f8Sesaxe { "instance_id", KSTAT_DATA_UINT64 }, 123fb2f18f8Sesaxe { "hardware", KSTAT_DATA_STRING }, 124*0e751525SEric Saxe { "policy", KSTAT_DATA_STRING }, 125fb2f18f8Sesaxe }; 126fb2f18f8Sesaxe 127fb2f18f8Sesaxe kmutex_t pghw_kstat_lock; 128fb2f18f8Sesaxe 129fb2f18f8Sesaxe /* 130fb2f18f8Sesaxe * hwset operations 131fb2f18f8Sesaxe */ 132fb2f18f8Sesaxe static group_t *pghw_set_create(pghw_type_t); 133fb2f18f8Sesaxe static void pghw_set_add(group_t *, pghw_t *); 134fb2f18f8Sesaxe static void pghw_set_remove(group_t *, pghw_t *); 135fb2f18f8Sesaxe 136fb2f18f8Sesaxe /* 137*0e751525SEric Saxe * Initialize the physical portion of a hardware PG 138fb2f18f8Sesaxe */ 139fb2f18f8Sesaxe void 140fb2f18f8Sesaxe pghw_init(pghw_t *pg, cpu_t *cp, pghw_type_t hw) 141fb2f18f8Sesaxe { 142fb2f18f8Sesaxe group_t *hwset; 143fb2f18f8Sesaxe 144fb2f18f8Sesaxe if ((hwset = pghw_set_lookup(hw)) == NULL) { 145fb2f18f8Sesaxe /* 146fb2f18f8Sesaxe * Haven't seen this hardware type yet 147fb2f18f8Sesaxe */ 148fb2f18f8Sesaxe hwset = pghw_set_create(hw); 149fb2f18f8Sesaxe } 150fb2f18f8Sesaxe 151fb2f18f8Sesaxe pghw_set_add(hwset, pg); 152fb2f18f8Sesaxe pg->pghw_hw = hw; 153fb2f18f8Sesaxe pg->pghw_instance = 154fb2f18f8Sesaxe pg_plat_hw_instance_id(cp, hw); 155fb2f18f8Sesaxe pghw_kstat_create(pg); 156*0e751525SEric Saxe 157*0e751525SEric Saxe /* 158*0e751525SEric Saxe * Hardware sharing relationship specific initialization 159*0e751525SEric Saxe */ 160*0e751525SEric Saxe switch (pg->pghw_hw) { 161*0e751525SEric Saxe case PGHW_POW_ACTIVE: 162*0e751525SEric Saxe pg->pghw_handle = 163*0e751525SEric Saxe (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_ACTIVE); 164*0e751525SEric Saxe break; 165*0e751525SEric Saxe case PGHW_POW_IDLE: 166*0e751525SEric Saxe pg->pghw_handle = 167*0e751525SEric Saxe (pghw_handle_t)cpupm_domain_init(cp, CPUPM_DTYPE_IDLE); 168*0e751525SEric Saxe break; 169*0e751525SEric Saxe default: 170*0e751525SEric Saxe pg->pghw_handle = (pghw_handle_t)NULL; 171*0e751525SEric Saxe } 172fb2f18f8Sesaxe } 173fb2f18f8Sesaxe 174fb2f18f8Sesaxe /* 175fb2f18f8Sesaxe * Teardown the physical portion of a physical PG 176fb2f18f8Sesaxe */ 177fb2f18f8Sesaxe void 178fb2f18f8Sesaxe pghw_fini(pghw_t *pg) 179fb2f18f8Sesaxe { 180fb2f18f8Sesaxe group_t *hwset; 181fb2f18f8Sesaxe 182fb2f18f8Sesaxe hwset = pghw_set_lookup(pg->pghw_hw); 183fb2f18f8Sesaxe ASSERT(hwset != NULL); 184fb2f18f8Sesaxe 185fb2f18f8Sesaxe pghw_set_remove(hwset, pg); 186fb2f18f8Sesaxe pg->pghw_instance = (id_t)PGHW_INSTANCE_ANON; 187fb2f18f8Sesaxe pg->pghw_hw = (pghw_type_t)-1; 188fb2f18f8Sesaxe 189fb2f18f8Sesaxe if (pg->pghw_kstat) 190fb2f18f8Sesaxe kstat_delete(pg->pghw_kstat); 191fb2f18f8Sesaxe } 192fb2f18f8Sesaxe 193fb2f18f8Sesaxe /* 194fb2f18f8Sesaxe * Find an existing physical PG in which to place 195fb2f18f8Sesaxe * the given CPU for the specified hardware sharing 196fb2f18f8Sesaxe * relationship 197fb2f18f8Sesaxe */ 198fb2f18f8Sesaxe pghw_t * 199fb2f18f8Sesaxe pghw_place_cpu(cpu_t *cp, pghw_type_t hw) 200fb2f18f8Sesaxe { 201fb2f18f8Sesaxe group_t *hwset; 202fb2f18f8Sesaxe 203fb2f18f8Sesaxe if ((hwset = pghw_set_lookup(hw)) == NULL) { 204fb2f18f8Sesaxe return (NULL); 205fb2f18f8Sesaxe } 206fb2f18f8Sesaxe 207fb2f18f8Sesaxe return ((pghw_t *)pg_cpu_find_pg(cp, hwset)); 208fb2f18f8Sesaxe } 209fb2f18f8Sesaxe 210fb2f18f8Sesaxe /* 211fb2f18f8Sesaxe * Find the pg representing the hw sharing relationship in which 212fb2f18f8Sesaxe * cp belongs 213fb2f18f8Sesaxe */ 214fb2f18f8Sesaxe pghw_t * 215fb2f18f8Sesaxe pghw_find_pg(cpu_t *cp, pghw_type_t hw) 216fb2f18f8Sesaxe { 217fb2f18f8Sesaxe group_iter_t i; 218fb2f18f8Sesaxe pghw_t *pg; 219fb2f18f8Sesaxe 220fb2f18f8Sesaxe group_iter_init(&i); 221fb2f18f8Sesaxe while ((pg = group_iterate(&cp->cpu_pg->pgs, &i)) != NULL) { 222fb2f18f8Sesaxe if (pg->pghw_hw == hw) 223fb2f18f8Sesaxe return (pg); 224fb2f18f8Sesaxe } 225fb2f18f8Sesaxe return (NULL); 226fb2f18f8Sesaxe } 227fb2f18f8Sesaxe 228fb2f18f8Sesaxe /* 229fb2f18f8Sesaxe * Find the PG of the given hardware sharing relationship 230fb2f18f8Sesaxe * type with the given instance id 231fb2f18f8Sesaxe */ 232fb2f18f8Sesaxe pghw_t * 233fb2f18f8Sesaxe pghw_find_by_instance(id_t id, pghw_type_t hw) 234fb2f18f8Sesaxe { 235fb2f18f8Sesaxe group_iter_t i; 236fb2f18f8Sesaxe group_t *set; 237fb2f18f8Sesaxe pghw_t *pg; 238fb2f18f8Sesaxe 239fb2f18f8Sesaxe set = pghw_set_lookup(hw); 240fb2f18f8Sesaxe if (!set) 241fb2f18f8Sesaxe return (NULL); 242fb2f18f8Sesaxe 243fb2f18f8Sesaxe group_iter_init(&i); 244fb2f18f8Sesaxe while ((pg = group_iterate(set, &i)) != NULL) { 245fb2f18f8Sesaxe if (pg->pghw_instance == id) 246fb2f18f8Sesaxe return (pg); 247fb2f18f8Sesaxe } 248fb2f18f8Sesaxe return (NULL); 249fb2f18f8Sesaxe } 250fb2f18f8Sesaxe 251fb2f18f8Sesaxe /* 252fb2f18f8Sesaxe * CPUs physical ID cache creation / destruction 253fb2f18f8Sesaxe * The cache's elements are initialized to the CPU's id 254fb2f18f8Sesaxe */ 255fb2f18f8Sesaxe void 256fb2f18f8Sesaxe pghw_physid_create(cpu_t *cp) 257fb2f18f8Sesaxe { 258fb2f18f8Sesaxe int i; 259fb2f18f8Sesaxe 260fb2f18f8Sesaxe cp->cpu_physid = kmem_alloc(sizeof (cpu_physid_t), KM_SLEEP); 261fb2f18f8Sesaxe 262fb2f18f8Sesaxe for (i = 0; i < (sizeof (cpu_physid_t) / sizeof (id_t)); i++) { 263fb2f18f8Sesaxe ((id_t *)cp->cpu_physid)[i] = cp->cpu_id; 264fb2f18f8Sesaxe } 265fb2f18f8Sesaxe } 266fb2f18f8Sesaxe 267fb2f18f8Sesaxe void 268fb2f18f8Sesaxe pghw_physid_destroy(cpu_t *cp) 269fb2f18f8Sesaxe { 270fb2f18f8Sesaxe if (cp->cpu_physid) { 271fb2f18f8Sesaxe kmem_free(cp->cpu_physid, sizeof (cpu_physid_t)); 272fb2f18f8Sesaxe cp->cpu_physid = NULL; 273fb2f18f8Sesaxe } 274fb2f18f8Sesaxe } 275fb2f18f8Sesaxe 276fb2f18f8Sesaxe /* 277fb2f18f8Sesaxe * Create a new, empty hwset. 278fb2f18f8Sesaxe * This routine may block, and must not be called from any 279fb2f18f8Sesaxe * paused CPU context. 280fb2f18f8Sesaxe */ 281fb2f18f8Sesaxe static group_t * 282fb2f18f8Sesaxe pghw_set_create(pghw_type_t hw) 283fb2f18f8Sesaxe { 284fb2f18f8Sesaxe group_t *g; 285fb2f18f8Sesaxe int ret; 286fb2f18f8Sesaxe 287fb2f18f8Sesaxe /* 288fb2f18f8Sesaxe * Create the top level PG hw group if it doesn't already exist 289fb2f18f8Sesaxe * This is a "set" of hardware sets, that is ordered (and indexed) 290fb2f18f8Sesaxe * by the pghw_type_t enum. 291fb2f18f8Sesaxe */ 292fb2f18f8Sesaxe if (pg_hw == NULL) { 293fb2f18f8Sesaxe pg_hw = kmem_alloc(sizeof (group_t), KM_SLEEP); 294fb2f18f8Sesaxe group_create(pg_hw); 295fb2f18f8Sesaxe group_expand(pg_hw, (uint_t)PGHW_NUM_COMPONENTS); 296fb2f18f8Sesaxe } 297fb2f18f8Sesaxe 298fb2f18f8Sesaxe /* 299fb2f18f8Sesaxe * Create the new hwset 300fb2f18f8Sesaxe * Add it to the top level pg_hw group. 301fb2f18f8Sesaxe */ 302fb2f18f8Sesaxe g = kmem_alloc(sizeof (group_t), KM_SLEEP); 303fb2f18f8Sesaxe group_create(g); 304fb2f18f8Sesaxe 305fb2f18f8Sesaxe ret = group_add_at(pg_hw, g, (uint_t)hw); 306fb2f18f8Sesaxe ASSERT(ret == 0); 307fb2f18f8Sesaxe 308fb2f18f8Sesaxe return (g); 309fb2f18f8Sesaxe } 310fb2f18f8Sesaxe 311fb2f18f8Sesaxe /* 312fb2f18f8Sesaxe * Find the hwset associated with the given hardware sharing type 313fb2f18f8Sesaxe */ 314fb2f18f8Sesaxe group_t * 315fb2f18f8Sesaxe pghw_set_lookup(pghw_type_t hw) 316fb2f18f8Sesaxe { 317fb2f18f8Sesaxe group_t *hwset; 318fb2f18f8Sesaxe 319fb2f18f8Sesaxe if (pg_hw == NULL) 320fb2f18f8Sesaxe return (NULL); 321fb2f18f8Sesaxe 322fb2f18f8Sesaxe hwset = GROUP_ACCESS(pg_hw, (uint_t)hw); 323fb2f18f8Sesaxe return (hwset); 324fb2f18f8Sesaxe } 325fb2f18f8Sesaxe 326fb2f18f8Sesaxe /* 327fb2f18f8Sesaxe * Add a PG to a hwset 328fb2f18f8Sesaxe */ 329fb2f18f8Sesaxe static void 330fb2f18f8Sesaxe pghw_set_add(group_t *hwset, pghw_t *pg) 331fb2f18f8Sesaxe { 332fb2f18f8Sesaxe (void) group_add(hwset, pg, GRP_RESIZE); 333fb2f18f8Sesaxe } 334fb2f18f8Sesaxe 335fb2f18f8Sesaxe /* 336fb2f18f8Sesaxe * Remove a PG from a hwset 337fb2f18f8Sesaxe */ 338fb2f18f8Sesaxe static void 339fb2f18f8Sesaxe pghw_set_remove(group_t *hwset, pghw_t *pg) 340fb2f18f8Sesaxe { 341fb2f18f8Sesaxe int result; 342fb2f18f8Sesaxe 343fb2f18f8Sesaxe result = group_remove(hwset, pg, GRP_RESIZE); 344fb2f18f8Sesaxe ASSERT(result == 0); 345fb2f18f8Sesaxe } 346fb2f18f8Sesaxe 347fb2f18f8Sesaxe 348fb2f18f8Sesaxe /* 349fb2f18f8Sesaxe * Return a string name given a pg_hw sharing type 350fb2f18f8Sesaxe */ 351fb2f18f8Sesaxe static char * 352fb2f18f8Sesaxe pghw_type_string(pghw_type_t hw) 353fb2f18f8Sesaxe { 354fb2f18f8Sesaxe switch (hw) { 355fb2f18f8Sesaxe case PGHW_IPIPE: 356*0e751525SEric Saxe return ("Integer Pipeline"); 357fb2f18f8Sesaxe case PGHW_CACHE: 358*0e751525SEric Saxe return ("Cache"); 359fb2f18f8Sesaxe case PGHW_FPU: 360*0e751525SEric Saxe return ("Floating Point Unit"); 361e853d8c3Sjc25722 case PGHW_MPIPE: 362*0e751525SEric Saxe return ("Data Pipe to memory"); 363fb2f18f8Sesaxe case PGHW_CHIP: 364*0e751525SEric Saxe return ("Socket"); 365fb2f18f8Sesaxe case PGHW_MEMORY: 366*0e751525SEric Saxe return ("Memory"); 367*0e751525SEric Saxe case PGHW_POW_ACTIVE: 368*0e751525SEric Saxe return ("CPU PM Active Power Domain"); 369*0e751525SEric Saxe case PGHW_POW_IDLE: 370*0e751525SEric Saxe return ("CPU PM Idle Power Domain"); 371fb2f18f8Sesaxe default: 372fb2f18f8Sesaxe return ("unknown"); 373fb2f18f8Sesaxe } 374fb2f18f8Sesaxe } 375fb2f18f8Sesaxe 376fb2f18f8Sesaxe /* 377fb2f18f8Sesaxe * Create / Update routines for PG hw kstats 378fb2f18f8Sesaxe * 379fb2f18f8Sesaxe * It is the intention of these kstats to provide some level 380fb2f18f8Sesaxe * of informational / debugging observability into the types 381fb2f18f8Sesaxe * and nature of the system's detected hardware sharing relationships 382fb2f18f8Sesaxe */ 383fb2f18f8Sesaxe void 384fb2f18f8Sesaxe pghw_kstat_create(pghw_t *pg) 385fb2f18f8Sesaxe { 386fb2f18f8Sesaxe /* 387fb2f18f8Sesaxe * Create a physical pg kstat 388fb2f18f8Sesaxe */ 389fb2f18f8Sesaxe if ((pg->pghw_kstat = kstat_create("pg", ((pg_t *)pg)->pg_id, 390fb2f18f8Sesaxe "pg", "pg", KSTAT_TYPE_NAMED, 391fb2f18f8Sesaxe sizeof (pghw_kstat) / sizeof (kstat_named_t), 392fb2f18f8Sesaxe KSTAT_FLAG_VIRTUAL)) != NULL) { 393*0e751525SEric Saxe /* Class string, hw string, and policy string */ 394fb2f18f8Sesaxe pg->pghw_kstat->ks_data_size += PG_CLASS_NAME_MAX; 395*0e751525SEric Saxe pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX; 396*0e751525SEric Saxe pg->pghw_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX; 397fb2f18f8Sesaxe pg->pghw_kstat->ks_lock = &pghw_kstat_lock; 398fb2f18f8Sesaxe pg->pghw_kstat->ks_data = &pghw_kstat; 399fb2f18f8Sesaxe pg->pghw_kstat->ks_update = pghw_kstat_update; 400fb2f18f8Sesaxe pg->pghw_kstat->ks_private = pg; 401fb2f18f8Sesaxe kstat_install(pg->pghw_kstat); 402fb2f18f8Sesaxe } 403fb2f18f8Sesaxe } 404fb2f18f8Sesaxe 405fb2f18f8Sesaxe int 406fb2f18f8Sesaxe pghw_kstat_update(kstat_t *ksp, int rw) 407fb2f18f8Sesaxe { 408fb2f18f8Sesaxe struct pghw_kstat *pgsp = &pghw_kstat; 409fb2f18f8Sesaxe pghw_t *pg = ksp->ks_private; 410fb2f18f8Sesaxe 411fb2f18f8Sesaxe if (rw == KSTAT_WRITE) 412fb2f18f8Sesaxe return (EACCES); 413fb2f18f8Sesaxe 414fb2f18f8Sesaxe pgsp->pg_id.value.ui64 = ((pg_t *)pg)->pg_id; 415fb2f18f8Sesaxe pgsp->pg_ncpus.value.ui64 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus); 416fb2f18f8Sesaxe pgsp->pg_instance_id.value.ui64 = (uint64_t)pg->pghw_instance; 417fb2f18f8Sesaxe kstat_named_setstr(&pgsp->pg_class, ((pg_t *)pg)->pg_class->pgc_name); 418fb2f18f8Sesaxe kstat_named_setstr(&pgsp->pg_hw, pghw_type_string(pg->pghw_hw)); 419*0e751525SEric Saxe kstat_named_setstr(&pgsp->pg_policy, pg_policy_name((pg_t *)pg)); 420fb2f18f8Sesaxe return (0); 421fb2f18f8Sesaxe } 422