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