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/cpupart.h> 34*fb2f18f8Sesaxe #include <sys/kmem.h> 35*fb2f18f8Sesaxe #include <sys/cmn_err.h> 36*fb2f18f8Sesaxe #include <sys/kstat.h> 37*fb2f18f8Sesaxe #include <sys/processor.h> 38*fb2f18f8Sesaxe #include <sys/disp.h> 39*fb2f18f8Sesaxe #include <sys/group.h> 40*fb2f18f8Sesaxe #include <sys/pg.h> 41*fb2f18f8Sesaxe 42*fb2f18f8Sesaxe /* 43*fb2f18f8Sesaxe * Processor groups 44*fb2f18f8Sesaxe * 45*fb2f18f8Sesaxe * With the introduction of Chip Multi-Threaded (CMT) processor architectures, 46*fb2f18f8Sesaxe * it is no longer necessarily true that a given physical processor module 47*fb2f18f8Sesaxe * will present itself as a single schedulable entity (cpu_t). Rather, each 48*fb2f18f8Sesaxe * chip and/or processor core may present itself as one or more "logical" CPUs. 49*fb2f18f8Sesaxe * 50*fb2f18f8Sesaxe * The logical CPUs presented may share physical components such as caches, 51*fb2f18f8Sesaxe * data pipes, execution pipelines, FPUs, etc. It is advantageous to have the 52*fb2f18f8Sesaxe * kernel be aware of the relationships existing between logical CPUs so that 53*fb2f18f8Sesaxe * the appropriate optmizations may be employed. 54*fb2f18f8Sesaxe * 55*fb2f18f8Sesaxe * The processor group abstraction represents a set of logical CPUs that 56*fb2f18f8Sesaxe * generally share some sort of physical or characteristic relationship. 57*fb2f18f8Sesaxe * 58*fb2f18f8Sesaxe * In the case of a physical sharing relationship, the CPUs in the group may 59*fb2f18f8Sesaxe * share a pipeline, cache or floating point unit. In the case of a logical 60*fb2f18f8Sesaxe * relationship, a PG may represent the set of CPUs in a processor set, or the 61*fb2f18f8Sesaxe * set of CPUs running at a particular clock speed. 62*fb2f18f8Sesaxe * 63*fb2f18f8Sesaxe * The generic processor group structure, pg_t, contains the elements generic 64*fb2f18f8Sesaxe * to a group of CPUs. Depending on the nature of the CPU relationship 65*fb2f18f8Sesaxe * (LOGICAL or PHYSICAL), a pointer to a pg may be recast to a "view" of that 66*fb2f18f8Sesaxe * PG where more specific data is represented. 67*fb2f18f8Sesaxe * 68*fb2f18f8Sesaxe * As an example, a PG representing a PHYSICAL relationship, may be recast to 69*fb2f18f8Sesaxe * a pghw_t, where data further describing the hardware sharing relationship 70*fb2f18f8Sesaxe * is maintained. See pghw.c and pghw.h for details on physical PGs. 71*fb2f18f8Sesaxe * 72*fb2f18f8Sesaxe * At this time a more specialized casting of a PG representing a LOGICAL 73*fb2f18f8Sesaxe * relationship has not been implemented, but the architecture allows for this 74*fb2f18f8Sesaxe * in the future. 75*fb2f18f8Sesaxe * 76*fb2f18f8Sesaxe * Processor Group Classes 77*fb2f18f8Sesaxe * 78*fb2f18f8Sesaxe * Processor group consumers may wish to maintain and associate specific 79*fb2f18f8Sesaxe * data with the PGs they create. For this reason, a mechanism for creating 80*fb2f18f8Sesaxe * class specific PGs exists. Classes may overload the default functions for 81*fb2f18f8Sesaxe * creating, destroying, and associating CPUs with PGs, and may also register 82*fb2f18f8Sesaxe * class specific callbacks to be invoked when the CPU related system 83*fb2f18f8Sesaxe * configuration changes. Class specific data is stored/associated with 84*fb2f18f8Sesaxe * PGs by incorporating the pg_t (or pghw_t, as appropriate), as the first 85*fb2f18f8Sesaxe * element of a class specific PG object. In memory, such a structure may look 86*fb2f18f8Sesaxe * like: 87*fb2f18f8Sesaxe * 88*fb2f18f8Sesaxe * ----------------------- - - - 89*fb2f18f8Sesaxe * | common | | | | <--(pg_t *) 90*fb2f18f8Sesaxe * ----------------------- | | - 91*fb2f18f8Sesaxe * | HW specific | | | <-----(pghw_t *) 92*fb2f18f8Sesaxe * ----------------------- | - 93*fb2f18f8Sesaxe * | class specific | | <-------(pg_cmt_t *) 94*fb2f18f8Sesaxe * ----------------------- - 95*fb2f18f8Sesaxe * 96*fb2f18f8Sesaxe * Access to the PG class specific data can be had by casting a pointer to 97*fb2f18f8Sesaxe * it's class specific view. 98*fb2f18f8Sesaxe */ 99*fb2f18f8Sesaxe 100*fb2f18f8Sesaxe static pg_t *pg_alloc_default(pg_class_t); 101*fb2f18f8Sesaxe static void pg_free_default(pg_t *); 102*fb2f18f8Sesaxe 103*fb2f18f8Sesaxe /* 104*fb2f18f8Sesaxe * Bootstrap CPU specific PG data 105*fb2f18f8Sesaxe * See pg_cpu_bootstrap() 106*fb2f18f8Sesaxe */ 107*fb2f18f8Sesaxe static cpu_pg_t bootstrap_pg_data; 108*fb2f18f8Sesaxe 109*fb2f18f8Sesaxe /* 110*fb2f18f8Sesaxe * Bitset of allocated PG ids (they are sequential) 111*fb2f18f8Sesaxe * and the next free id in the set. 112*fb2f18f8Sesaxe */ 113*fb2f18f8Sesaxe static bitset_t pg_id_set; 114*fb2f18f8Sesaxe static pgid_t pg_id_next = 0; 115*fb2f18f8Sesaxe 116*fb2f18f8Sesaxe /* 117*fb2f18f8Sesaxe * Default and externed PG ops vectors 118*fb2f18f8Sesaxe */ 119*fb2f18f8Sesaxe static struct pg_ops pg_ops_default = { 120*fb2f18f8Sesaxe pg_alloc_default, /* alloc */ 121*fb2f18f8Sesaxe pg_free_default, /* free */ 122*fb2f18f8Sesaxe NULL, /* cpu_init */ 123*fb2f18f8Sesaxe NULL, /* cpu_fini */ 124*fb2f18f8Sesaxe NULL, /* cpu_active */ 125*fb2f18f8Sesaxe NULL, /* cpu_inactive */ 126*fb2f18f8Sesaxe NULL, /* cpupart_in */ 127*fb2f18f8Sesaxe NULL, /* cpupart_out */ 128*fb2f18f8Sesaxe NULL, /* cpupart_move */ 129*fb2f18f8Sesaxe NULL, /* cpu_belongs */ 130*fb2f18f8Sesaxe }; 131*fb2f18f8Sesaxe 132*fb2f18f8Sesaxe /* 133*fb2f18f8Sesaxe * Class specific PG allocation callbacks 134*fb2f18f8Sesaxe */ 135*fb2f18f8Sesaxe #define PG_ALLOC(class) \ 136*fb2f18f8Sesaxe (pg_classes[class].pgc_ops->alloc ? \ 137*fb2f18f8Sesaxe pg_classes[class].pgc_ops->alloc() : \ 138*fb2f18f8Sesaxe pg_classes[pg_default_cid].pgc_ops->alloc()) 139*fb2f18f8Sesaxe 140*fb2f18f8Sesaxe #define PG_FREE(pg) \ 141*fb2f18f8Sesaxe ((pg)->pg_class->pgc_ops->free ? \ 142*fb2f18f8Sesaxe (pg)->pg_class->pgc_ops->free(pg) : \ 143*fb2f18f8Sesaxe pg_classes[pg_default_cid].pgc_ops->free(pg)) \ 144*fb2f18f8Sesaxe 145*fb2f18f8Sesaxe 146*fb2f18f8Sesaxe /* 147*fb2f18f8Sesaxe * Class specific membership test callback 148*fb2f18f8Sesaxe */ 149*fb2f18f8Sesaxe #define PG_CPU_BELONGS(pg, cp) \ 150*fb2f18f8Sesaxe ((pg)->pg_class->pgc_ops->cpu_belongs ? \ 151*fb2f18f8Sesaxe (pg)->pg_class->pgc_ops->cpu_belongs(pg, cp) : 0) \ 152*fb2f18f8Sesaxe 153*fb2f18f8Sesaxe /* 154*fb2f18f8Sesaxe * CPU configuration callbacks 155*fb2f18f8Sesaxe */ 156*fb2f18f8Sesaxe #define PG_CPU_INIT(class, cp) \ 157*fb2f18f8Sesaxe { \ 158*fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_init) \ 159*fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpu_init(cp); \ 160*fb2f18f8Sesaxe } 161*fb2f18f8Sesaxe 162*fb2f18f8Sesaxe #define PG_CPU_FINI(class, cp) \ 163*fb2f18f8Sesaxe { \ 164*fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_fini) \ 165*fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpu_fini(cp); \ 166*fb2f18f8Sesaxe } 167*fb2f18f8Sesaxe 168*fb2f18f8Sesaxe #define PG_CPU_ACTIVE(class, cp) \ 169*fb2f18f8Sesaxe { \ 170*fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_active) \ 171*fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpu_active(cp); \ 172*fb2f18f8Sesaxe } 173*fb2f18f8Sesaxe 174*fb2f18f8Sesaxe #define PG_CPU_INACTIVE(class, cp) \ 175*fb2f18f8Sesaxe { \ 176*fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_inactive) \ 177*fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpu_inactive(cp); \ 178*fb2f18f8Sesaxe } 179*fb2f18f8Sesaxe 180*fb2f18f8Sesaxe /* 181*fb2f18f8Sesaxe * CPU / cpupart configuration callbacks 182*fb2f18f8Sesaxe */ 183*fb2f18f8Sesaxe #define PG_CPUPART_IN(class, cp, pp) \ 184*fb2f18f8Sesaxe { \ 185*fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpupart_in) \ 186*fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpupart_in(cp, pp); \ 187*fb2f18f8Sesaxe } 188*fb2f18f8Sesaxe 189*fb2f18f8Sesaxe #define PG_CPUPART_OUT(class, cp, pp) \ 190*fb2f18f8Sesaxe { \ 191*fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpupart_out) \ 192*fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpupart_out(cp, pp); \ 193*fb2f18f8Sesaxe } 194*fb2f18f8Sesaxe 195*fb2f18f8Sesaxe #define PG_CPUPART_MOVE(class, cp, old, new) \ 196*fb2f18f8Sesaxe { \ 197*fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpupart_move) \ 198*fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpupart_move(cp, old, new); \ 199*fb2f18f8Sesaxe } 200*fb2f18f8Sesaxe 201*fb2f18f8Sesaxe 202*fb2f18f8Sesaxe 203*fb2f18f8Sesaxe static pg_class_t *pg_classes; 204*fb2f18f8Sesaxe static int pg_nclasses; 205*fb2f18f8Sesaxe 206*fb2f18f8Sesaxe static pg_cid_t pg_default_cid; 207*fb2f18f8Sesaxe 208*fb2f18f8Sesaxe /* 209*fb2f18f8Sesaxe * Initialze common PG subsystem. Perform CPU 0 initialization 210*fb2f18f8Sesaxe */ 211*fb2f18f8Sesaxe void 212*fb2f18f8Sesaxe pg_init(void) 213*fb2f18f8Sesaxe { 214*fb2f18f8Sesaxe pg_default_cid = 215*fb2f18f8Sesaxe pg_class_register("default", &pg_ops_default, PGR_LOGICAL); 216*fb2f18f8Sesaxe } 217*fb2f18f8Sesaxe 218*fb2f18f8Sesaxe /* 219*fb2f18f8Sesaxe * Perform CPU 0 initialization 220*fb2f18f8Sesaxe */ 221*fb2f18f8Sesaxe void 222*fb2f18f8Sesaxe pg_cpu0_init(void) 223*fb2f18f8Sesaxe { 224*fb2f18f8Sesaxe extern void pghw_physid_create(); 225*fb2f18f8Sesaxe 226*fb2f18f8Sesaxe /* 227*fb2f18f8Sesaxe * Create the physical ID cache for the boot CPU 228*fb2f18f8Sesaxe */ 229*fb2f18f8Sesaxe pghw_physid_create(CPU); 230*fb2f18f8Sesaxe 231*fb2f18f8Sesaxe /* 232*fb2f18f8Sesaxe * pg_cpu_* require that cpu_lock be held 233*fb2f18f8Sesaxe */ 234*fb2f18f8Sesaxe mutex_enter(&cpu_lock); 235*fb2f18f8Sesaxe 236*fb2f18f8Sesaxe pg_cpu_init(CPU); 237*fb2f18f8Sesaxe pg_cpupart_in(CPU, &cp_default); 238*fb2f18f8Sesaxe pg_cpu_active(CPU); 239*fb2f18f8Sesaxe 240*fb2f18f8Sesaxe mutex_exit(&cpu_lock); 241*fb2f18f8Sesaxe } 242*fb2f18f8Sesaxe 243*fb2f18f8Sesaxe /* 244*fb2f18f8Sesaxe * Register a new PG class 245*fb2f18f8Sesaxe */ 246*fb2f18f8Sesaxe pg_cid_t 247*fb2f18f8Sesaxe pg_class_register(char *name, struct pg_ops *ops, pg_relation_t relation) 248*fb2f18f8Sesaxe { 249*fb2f18f8Sesaxe pg_class_t *newclass; 250*fb2f18f8Sesaxe pg_class_t *classes_old; 251*fb2f18f8Sesaxe id_t cid; 252*fb2f18f8Sesaxe 253*fb2f18f8Sesaxe mutex_enter(&cpu_lock); 254*fb2f18f8Sesaxe 255*fb2f18f8Sesaxe /* 256*fb2f18f8Sesaxe * Allocate a new pg_class_t in the pg_classes array 257*fb2f18f8Sesaxe */ 258*fb2f18f8Sesaxe if (pg_nclasses == 0) { 259*fb2f18f8Sesaxe pg_classes = kmem_zalloc(sizeof (pg_class_t), KM_SLEEP); 260*fb2f18f8Sesaxe } else { 261*fb2f18f8Sesaxe classes_old = pg_classes; 262*fb2f18f8Sesaxe pg_classes = 263*fb2f18f8Sesaxe kmem_zalloc(sizeof (pg_class_t) * (pg_nclasses + 1), 264*fb2f18f8Sesaxe KM_SLEEP); 265*fb2f18f8Sesaxe (void) kcopy(classes_old, pg_classes, 266*fb2f18f8Sesaxe sizeof (pg_class_t) * pg_nclasses); 267*fb2f18f8Sesaxe kmem_free(classes_old, sizeof (pg_class_t) * pg_nclasses); 268*fb2f18f8Sesaxe } 269*fb2f18f8Sesaxe 270*fb2f18f8Sesaxe cid = pg_nclasses++; 271*fb2f18f8Sesaxe newclass = &pg_classes[cid]; 272*fb2f18f8Sesaxe 273*fb2f18f8Sesaxe (void) strncpy(newclass->pgc_name, name, PG_CLASS_NAME_MAX); 274*fb2f18f8Sesaxe newclass->pgc_id = cid; 275*fb2f18f8Sesaxe newclass->pgc_ops = ops; 276*fb2f18f8Sesaxe newclass->pgc_relation = relation; 277*fb2f18f8Sesaxe 278*fb2f18f8Sesaxe mutex_exit(&cpu_lock); 279*fb2f18f8Sesaxe 280*fb2f18f8Sesaxe return (cid); 281*fb2f18f8Sesaxe } 282*fb2f18f8Sesaxe 283*fb2f18f8Sesaxe /* 284*fb2f18f8Sesaxe * Try to find an existing pg in set in which to place cp. 285*fb2f18f8Sesaxe * Returns the pg if found, and NULL otherwise. 286*fb2f18f8Sesaxe * In the event that the CPU could belong to multiple 287*fb2f18f8Sesaxe * PGs in the set, the first matching PG will be returned. 288*fb2f18f8Sesaxe */ 289*fb2f18f8Sesaxe pg_t * 290*fb2f18f8Sesaxe pg_cpu_find_pg(cpu_t *cp, group_t *set) 291*fb2f18f8Sesaxe { 292*fb2f18f8Sesaxe pg_t *pg; 293*fb2f18f8Sesaxe group_iter_t i; 294*fb2f18f8Sesaxe 295*fb2f18f8Sesaxe group_iter_init(&i); 296*fb2f18f8Sesaxe while ((pg = group_iterate(set, &i)) != NULL) { 297*fb2f18f8Sesaxe /* 298*fb2f18f8Sesaxe * Ask the class if the CPU belongs here 299*fb2f18f8Sesaxe */ 300*fb2f18f8Sesaxe if (PG_CPU_BELONGS(pg, cp)) 301*fb2f18f8Sesaxe return (pg); 302*fb2f18f8Sesaxe } 303*fb2f18f8Sesaxe return (NULL); 304*fb2f18f8Sesaxe } 305*fb2f18f8Sesaxe 306*fb2f18f8Sesaxe /* 307*fb2f18f8Sesaxe * Iterate over the CPUs in a PG after initializing 308*fb2f18f8Sesaxe * the iterator with PG_CPU_ITR_INIT() 309*fb2f18f8Sesaxe */ 310*fb2f18f8Sesaxe cpu_t * 311*fb2f18f8Sesaxe pg_cpu_next(pg_cpu_itr_t *itr) 312*fb2f18f8Sesaxe { 313*fb2f18f8Sesaxe cpu_t *cpu; 314*fb2f18f8Sesaxe pg_t *pg = itr->pg; 315*fb2f18f8Sesaxe 316*fb2f18f8Sesaxe cpu = group_iterate(&pg->pg_cpus, &itr->position); 317*fb2f18f8Sesaxe return (cpu); 318*fb2f18f8Sesaxe } 319*fb2f18f8Sesaxe 320*fb2f18f8Sesaxe /* 321*fb2f18f8Sesaxe * Create a PG of a given class. 322*fb2f18f8Sesaxe * This routine may block. 323*fb2f18f8Sesaxe */ 324*fb2f18f8Sesaxe pg_t * 325*fb2f18f8Sesaxe pg_create(pg_cid_t cid) 326*fb2f18f8Sesaxe { 327*fb2f18f8Sesaxe pg_t *pg; 328*fb2f18f8Sesaxe pgid_t id; 329*fb2f18f8Sesaxe 330*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 331*fb2f18f8Sesaxe 332*fb2f18f8Sesaxe /* 333*fb2f18f8Sesaxe * Call the class specific PG allocation routine 334*fb2f18f8Sesaxe */ 335*fb2f18f8Sesaxe pg = PG_ALLOC(cid); 336*fb2f18f8Sesaxe pg->pg_class = &pg_classes[cid]; 337*fb2f18f8Sesaxe pg->pg_relation = pg->pg_class->pgc_relation; 338*fb2f18f8Sesaxe 339*fb2f18f8Sesaxe /* 340*fb2f18f8Sesaxe * Find the next free sequential pg id 341*fb2f18f8Sesaxe */ 342*fb2f18f8Sesaxe do { 343*fb2f18f8Sesaxe if (pg_id_next >= bitset_capacity(&pg_id_set)) 344*fb2f18f8Sesaxe bitset_resize(&pg_id_set, pg_id_next + 1); 345*fb2f18f8Sesaxe id = pg_id_next++; 346*fb2f18f8Sesaxe } while (bitset_in_set(&pg_id_set, id)); 347*fb2f18f8Sesaxe 348*fb2f18f8Sesaxe pg->pg_id = id; 349*fb2f18f8Sesaxe bitset_add(&pg_id_set, pg->pg_id); 350*fb2f18f8Sesaxe 351*fb2f18f8Sesaxe /* 352*fb2f18f8Sesaxe * Create the PG's CPU group 353*fb2f18f8Sesaxe */ 354*fb2f18f8Sesaxe group_create(&pg->pg_cpus); 355*fb2f18f8Sesaxe 356*fb2f18f8Sesaxe return (pg); 357*fb2f18f8Sesaxe } 358*fb2f18f8Sesaxe 359*fb2f18f8Sesaxe /* 360*fb2f18f8Sesaxe * Destroy a PG. 361*fb2f18f8Sesaxe * This routine may block. 362*fb2f18f8Sesaxe */ 363*fb2f18f8Sesaxe void 364*fb2f18f8Sesaxe pg_destroy(pg_t *pg) 365*fb2f18f8Sesaxe { 366*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 367*fb2f18f8Sesaxe 368*fb2f18f8Sesaxe group_destroy(&pg->pg_cpus); 369*fb2f18f8Sesaxe 370*fb2f18f8Sesaxe /* 371*fb2f18f8Sesaxe * Unassign the pg_id 372*fb2f18f8Sesaxe */ 373*fb2f18f8Sesaxe if (pg_id_next > pg->pg_id) 374*fb2f18f8Sesaxe pg_id_next = pg->pg_id; 375*fb2f18f8Sesaxe bitset_del(&pg_id_set, pg->pg_id); 376*fb2f18f8Sesaxe 377*fb2f18f8Sesaxe /* 378*fb2f18f8Sesaxe * Invoke the class specific de-allocation routine 379*fb2f18f8Sesaxe */ 380*fb2f18f8Sesaxe PG_FREE(pg); 381*fb2f18f8Sesaxe } 382*fb2f18f8Sesaxe 383*fb2f18f8Sesaxe /* 384*fb2f18f8Sesaxe * Add the CPU "cp" to processor group "pg" 385*fb2f18f8Sesaxe * This routine may block. 386*fb2f18f8Sesaxe */ 387*fb2f18f8Sesaxe void 388*fb2f18f8Sesaxe pg_cpu_add(pg_t *pg, cpu_t *cp) 389*fb2f18f8Sesaxe { 390*fb2f18f8Sesaxe int err; 391*fb2f18f8Sesaxe 392*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 393*fb2f18f8Sesaxe 394*fb2f18f8Sesaxe /* This adds the CPU to the PG's CPU group */ 395*fb2f18f8Sesaxe err = group_add(&pg->pg_cpus, cp, GRP_RESIZE); 396*fb2f18f8Sesaxe ASSERT(err == 0); 397*fb2f18f8Sesaxe 398*fb2f18f8Sesaxe /* This adds the PG to the CPUs PG group */ 399*fb2f18f8Sesaxe ASSERT(cp->cpu_pg != &bootstrap_pg_data); 400*fb2f18f8Sesaxe err = group_add(&cp->cpu_pg->pgs, pg, GRP_RESIZE); 401*fb2f18f8Sesaxe ASSERT(err == 0); 402*fb2f18f8Sesaxe } 403*fb2f18f8Sesaxe 404*fb2f18f8Sesaxe /* 405*fb2f18f8Sesaxe * Remove "cp" from "pg". 406*fb2f18f8Sesaxe * This routine may block. 407*fb2f18f8Sesaxe */ 408*fb2f18f8Sesaxe void 409*fb2f18f8Sesaxe pg_cpu_delete(pg_t *pg, cpu_t *cp) 410*fb2f18f8Sesaxe { 411*fb2f18f8Sesaxe int err; 412*fb2f18f8Sesaxe 413*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 414*fb2f18f8Sesaxe 415*fb2f18f8Sesaxe /* Remove the CPU from the PG */ 416*fb2f18f8Sesaxe err = group_remove(&pg->pg_cpus, cp, GRP_RESIZE); 417*fb2f18f8Sesaxe ASSERT(err == 0); 418*fb2f18f8Sesaxe 419*fb2f18f8Sesaxe /* Remove the PG from the CPU's PG group */ 420*fb2f18f8Sesaxe ASSERT(cp->cpu_pg != &bootstrap_pg_data); 421*fb2f18f8Sesaxe err = group_remove(&cp->cpu_pg->pgs, pg, GRP_RESIZE); 422*fb2f18f8Sesaxe ASSERT(err == 0); 423*fb2f18f8Sesaxe } 424*fb2f18f8Sesaxe 425*fb2f18f8Sesaxe /* 426*fb2f18f8Sesaxe * Allocate a CPU's PG data. This hangs off struct cpu at cpu_pg 427*fb2f18f8Sesaxe */ 428*fb2f18f8Sesaxe static cpu_pg_t * 429*fb2f18f8Sesaxe pg_cpu_data_alloc(void) 430*fb2f18f8Sesaxe { 431*fb2f18f8Sesaxe cpu_pg_t *pgd; 432*fb2f18f8Sesaxe 433*fb2f18f8Sesaxe pgd = kmem_zalloc(sizeof (cpu_pg_t), KM_SLEEP); 434*fb2f18f8Sesaxe group_create(&pgd->pgs); 435*fb2f18f8Sesaxe group_create(&pgd->cmt_pgs); 436*fb2f18f8Sesaxe 437*fb2f18f8Sesaxe return (pgd); 438*fb2f18f8Sesaxe } 439*fb2f18f8Sesaxe 440*fb2f18f8Sesaxe /* 441*fb2f18f8Sesaxe * Free the CPU's PG data. 442*fb2f18f8Sesaxe */ 443*fb2f18f8Sesaxe static void 444*fb2f18f8Sesaxe pg_cpu_data_free(cpu_pg_t *pgd) 445*fb2f18f8Sesaxe { 446*fb2f18f8Sesaxe group_destroy(&pgd->pgs); 447*fb2f18f8Sesaxe group_destroy(&pgd->cmt_pgs); 448*fb2f18f8Sesaxe kmem_free(pgd, sizeof (cpu_pg_t)); 449*fb2f18f8Sesaxe } 450*fb2f18f8Sesaxe 451*fb2f18f8Sesaxe /* 452*fb2f18f8Sesaxe * A new CPU is coming into the system, either via booting or DR. 453*fb2f18f8Sesaxe * Allocate it's PG data, and notify all registered classes about 454*fb2f18f8Sesaxe * the new CPU. 455*fb2f18f8Sesaxe * 456*fb2f18f8Sesaxe * This routine may block. 457*fb2f18f8Sesaxe */ 458*fb2f18f8Sesaxe void 459*fb2f18f8Sesaxe pg_cpu_init(cpu_t *cp) 460*fb2f18f8Sesaxe { 461*fb2f18f8Sesaxe pg_cid_t i; 462*fb2f18f8Sesaxe 463*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 464*fb2f18f8Sesaxe 465*fb2f18f8Sesaxe /* 466*fb2f18f8Sesaxe * Allocate and size the per CPU pg data 467*fb2f18f8Sesaxe */ 468*fb2f18f8Sesaxe cp->cpu_pg = pg_cpu_data_alloc(); 469*fb2f18f8Sesaxe 470*fb2f18f8Sesaxe /* 471*fb2f18f8Sesaxe * Notify all registered classes about the new CPU 472*fb2f18f8Sesaxe */ 473*fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 474*fb2f18f8Sesaxe PG_CPU_INIT(i, cp); 475*fb2f18f8Sesaxe } 476*fb2f18f8Sesaxe 477*fb2f18f8Sesaxe /* 478*fb2f18f8Sesaxe * This CPU is being deleted from the system. Notify the classes 479*fb2f18f8Sesaxe * and free up the CPU's PG data. 480*fb2f18f8Sesaxe */ 481*fb2f18f8Sesaxe void 482*fb2f18f8Sesaxe pg_cpu_fini(cpu_t *cp) 483*fb2f18f8Sesaxe { 484*fb2f18f8Sesaxe pg_cid_t i; 485*fb2f18f8Sesaxe 486*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 487*fb2f18f8Sesaxe 488*fb2f18f8Sesaxe /* 489*fb2f18f8Sesaxe * This can happen if the CPU coming into the system 490*fb2f18f8Sesaxe * failed to power on. 491*fb2f18f8Sesaxe */ 492*fb2f18f8Sesaxe if (cp->cpu_pg == NULL || 493*fb2f18f8Sesaxe cp->cpu_pg == &bootstrap_pg_data) 494*fb2f18f8Sesaxe return; 495*fb2f18f8Sesaxe 496*fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 497*fb2f18f8Sesaxe PG_CPU_FINI(i, cp); 498*fb2f18f8Sesaxe 499*fb2f18f8Sesaxe pg_cpu_data_free(cp->cpu_pg); 500*fb2f18f8Sesaxe cp->cpu_pg = NULL; 501*fb2f18f8Sesaxe } 502*fb2f18f8Sesaxe 503*fb2f18f8Sesaxe /* 504*fb2f18f8Sesaxe * This CPU is becoming active (online) 505*fb2f18f8Sesaxe * This routine may not block as it is called from paused CPUs 506*fb2f18f8Sesaxe * context. 507*fb2f18f8Sesaxe */ 508*fb2f18f8Sesaxe void 509*fb2f18f8Sesaxe pg_cpu_active(cpu_t *cp) 510*fb2f18f8Sesaxe { 511*fb2f18f8Sesaxe pg_cid_t i; 512*fb2f18f8Sesaxe 513*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 514*fb2f18f8Sesaxe 515*fb2f18f8Sesaxe /* 516*fb2f18f8Sesaxe * Notify all registered classes about the new CPU 517*fb2f18f8Sesaxe */ 518*fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 519*fb2f18f8Sesaxe PG_CPU_ACTIVE(i, cp); 520*fb2f18f8Sesaxe } 521*fb2f18f8Sesaxe 522*fb2f18f8Sesaxe /* 523*fb2f18f8Sesaxe * This CPU is going inactive (offline) 524*fb2f18f8Sesaxe * This routine may not block, as it is called from paused 525*fb2f18f8Sesaxe * CPUs context. 526*fb2f18f8Sesaxe */ 527*fb2f18f8Sesaxe void 528*fb2f18f8Sesaxe pg_cpu_inactive(cpu_t *cp) 529*fb2f18f8Sesaxe { 530*fb2f18f8Sesaxe pg_cid_t i; 531*fb2f18f8Sesaxe 532*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 533*fb2f18f8Sesaxe 534*fb2f18f8Sesaxe /* 535*fb2f18f8Sesaxe * Notify all registered classes about the new CPU 536*fb2f18f8Sesaxe */ 537*fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 538*fb2f18f8Sesaxe PG_CPU_INACTIVE(i, cp); 539*fb2f18f8Sesaxe } 540*fb2f18f8Sesaxe 541*fb2f18f8Sesaxe /* 542*fb2f18f8Sesaxe * Invoked when the CPU is about to move into the partition 543*fb2f18f8Sesaxe * This routine may block. 544*fb2f18f8Sesaxe */ 545*fb2f18f8Sesaxe void 546*fb2f18f8Sesaxe pg_cpupart_in(cpu_t *cp, cpupart_t *pp) 547*fb2f18f8Sesaxe { 548*fb2f18f8Sesaxe int i; 549*fb2f18f8Sesaxe 550*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 551*fb2f18f8Sesaxe 552*fb2f18f8Sesaxe /* 553*fb2f18f8Sesaxe * Notify all registered classes that the 554*fb2f18f8Sesaxe * CPU is about to enter the CPU partition 555*fb2f18f8Sesaxe */ 556*fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 557*fb2f18f8Sesaxe PG_CPUPART_IN(i, cp, pp); 558*fb2f18f8Sesaxe } 559*fb2f18f8Sesaxe 560*fb2f18f8Sesaxe /* 561*fb2f18f8Sesaxe * Invoked when the CPU is about to move out of the partition 562*fb2f18f8Sesaxe * This routine may block. 563*fb2f18f8Sesaxe */ 564*fb2f18f8Sesaxe /*ARGSUSED*/ 565*fb2f18f8Sesaxe void 566*fb2f18f8Sesaxe pg_cpupart_out(cpu_t *cp, cpupart_t *pp) 567*fb2f18f8Sesaxe { 568*fb2f18f8Sesaxe int i; 569*fb2f18f8Sesaxe 570*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 571*fb2f18f8Sesaxe 572*fb2f18f8Sesaxe /* 573*fb2f18f8Sesaxe * Notify all registered classes that the 574*fb2f18f8Sesaxe * CPU is about to leave the CPU partition 575*fb2f18f8Sesaxe */ 576*fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 577*fb2f18f8Sesaxe PG_CPUPART_OUT(i, cp, pp); 578*fb2f18f8Sesaxe } 579*fb2f18f8Sesaxe 580*fb2f18f8Sesaxe /* 581*fb2f18f8Sesaxe * Invoked when the CPU is *moving* partitions. 582*fb2f18f8Sesaxe * 583*fb2f18f8Sesaxe * This routine may not block, as it is called from paused CPUs 584*fb2f18f8Sesaxe * context. 585*fb2f18f8Sesaxe */ 586*fb2f18f8Sesaxe void 587*fb2f18f8Sesaxe pg_cpupart_move(cpu_t *cp, cpupart_t *oldpp, cpupart_t *newpp) 588*fb2f18f8Sesaxe { 589*fb2f18f8Sesaxe int i; 590*fb2f18f8Sesaxe 591*fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 592*fb2f18f8Sesaxe 593*fb2f18f8Sesaxe /* 594*fb2f18f8Sesaxe * Notify all registered classes that the 595*fb2f18f8Sesaxe * CPU is about to leave the CPU partition 596*fb2f18f8Sesaxe */ 597*fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 598*fb2f18f8Sesaxe PG_CPUPART_MOVE(i, cp, oldpp, newpp); 599*fb2f18f8Sesaxe } 600*fb2f18f8Sesaxe 601*fb2f18f8Sesaxe /* 602*fb2f18f8Sesaxe * Provide the specified CPU a bootstrap pg 603*fb2f18f8Sesaxe * This is needed to allow sane behaviour if any PG consuming 604*fb2f18f8Sesaxe * code needs to deal with a partially initialized CPU 605*fb2f18f8Sesaxe */ 606*fb2f18f8Sesaxe void 607*fb2f18f8Sesaxe pg_cpu_bootstrap(cpu_t *cp) 608*fb2f18f8Sesaxe { 609*fb2f18f8Sesaxe cp->cpu_pg = &bootstrap_pg_data; 610*fb2f18f8Sesaxe } 611*fb2f18f8Sesaxe 612*fb2f18f8Sesaxe /*ARGSUSED*/ 613*fb2f18f8Sesaxe static pg_t * 614*fb2f18f8Sesaxe pg_alloc_default(pg_class_t class) 615*fb2f18f8Sesaxe { 616*fb2f18f8Sesaxe return (kmem_zalloc(sizeof (pg_t), KM_SLEEP)); 617*fb2f18f8Sesaxe } 618*fb2f18f8Sesaxe 619*fb2f18f8Sesaxe /*ARGSUSED*/ 620*fb2f18f8Sesaxe static void 621*fb2f18f8Sesaxe pg_free_default(struct pg *pg) 622*fb2f18f8Sesaxe { 623*fb2f18f8Sesaxe kmem_free(pg, sizeof (pg_t)); 624*fb2f18f8Sesaxe } 625